Shortcut to Collapse All Projects in Solution Explorer of Visual Studio

It’s nice to be able to collapse all projects in Visual Studio Solution Explorer. If you hate mice like me, it’s even nicer to have a keyboard shortcut to do that for you.

In Visual Studio, go to Tools > Options > Keyboard. In the Show commands containing text box, type in CollapseProjects. Select the ProjectandSolutionContextMenus.Projects.CollapseProjects and assign it your shortcut as shown below:collapse projects shortcut

Server Name Indication – Bind Different Certificates to 1 IP Address Using the Same Port

In the old days, you could only bind a single SSL certificate to an IP address in IIS. So, if I was using host-headers to have more than 1 site at the same IP address, I could only bind a single SSL certificate to port 443 of one of those WebSites. This was a bummer. In my day job, owing to some limitations, we have our Testing Site on the same server as our Staging Site. As a result, I’d have to bind the Test Site’s certificate to a different port. And as the web server can only have 1 default port for SSL, the 2 urls would be:


Nowadays, you can have your cake and eat it. And all it takes is a single checkbox:
Server Name Indication

It’s called Server Name Indication and if the CheckBox is checked for the sites using the same port (presumably 443), then you can bind different certificates to different sites (with distinct host-headers) on the same IP address and the same port.

Currying to Rein in Underscorejs

Whilst I am a big fan of Underscorejs, today I am going to show you a small technique to rein it in. So, first I will show you the problem which I am going to solve.

When you use the Underscorejs methods for manipulating/iterating collections, Underscorejs usually passes in three parameters to the function which you use for the call-back:

  1. the current item being iterated;
  2. the index for that item in the collection; and
  3. the whole collection itself.

The easiest way to verify that, is to put a breakpoint in your function, open the console in either Firebug or Chrome developer tools and type the word arguments (see the following screenshot):


For one reason or another, you may want to confine the arguments which get passed in to the first one. You may be only interested in the item being iterated. And to lock your method down, you may want to effectively block the other to parameters from being passed in (note how I keep using the word “may”. Most of the time, you’ll be quite happy to have access to all 3 parameters).

To do that, I am going to write a small helper function which I will call curryOneArgument. That function will use the technique of currying to return a function that will only receive one argument:

var curryOneArg = function(fun) {
        return function(arg) {
            return fun(arg);

Now, all we have to do is wrap our call-back in that new function and we will be restricting that callback to only receive one argument from Underscorejs:

var newColl =, curryOneArg(function (arg) {

And, using the console to verify:



Some Json.NET Methods

Here are a couple of Json.NET functions which I wrote to assist in working with Json operations in C#:

public class JsonHelpers
	public static string MergeJsonWithStoredField(string existingJson, JProperty newJson)
		if (newJson == null) throw new ArgumentNullException("newJson");

		JObject jObject;

		if (string.IsNullOrWhiteSpace(existingJson))
			jObject = new JObject(newJson);
			jObject = JObject.Parse(existingJson.Trim());

		return jObject.ToString(Formatting.None);

	public static IEnumerable<JProperty> CreateJsonPropertiesFromObject(Object objectToJsonify)
		if (objectToJsonify == null) throw new ArgumentNullException("objectToJsonify");

		ICollection<JProperty> properties = new List<JProperty>();

		foreach (var propertyInfo in objectToJsonify.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
			properties.Add(new JProperty(propertyInfo.Name, propertyInfo.GetValue(objectToJsonify)));

		return properties;

	public static string AddObjectToJsonArray(string jsonAsString, string keyOfArray, Object objectToJsonify)
		JObject existingStoredJsonObject;
		JArray jArray;

		// convert object to a json object
		var newJsonObject = new JObject(CreateJsonPropertiesFromObject(objectToJsonify));

		// if the existing stored string is null or emptiness, just create it and return.
		if (string.IsNullOrWhiteSpace(jsonAsString))
			existingStoredJsonObject = new JObject();
			jArray = new JArray(newJsonObject);
			existingStoredJsonObject.Add(JsonPropertyKeys.PostEventMaterialsWereAccessed, jArray);

			return existingStoredJsonObject.ToString(Formatting.None);

		// ************* if we got here, we need to now process the existing stored json as an input *************
		existingStoredJsonObject = JObject.Parse(jsonAsString);

		// 1st, see if valid json is stored at all
		if (!ReferenceEquals(null, existingStoredJsonObject))
			JToken jToken;

			// 2nd, see if the array which we are augmenting already exists
			if (existingStoredJsonObject.TryGetValue(keyOfArray, StringComparison.OrdinalIgnoreCase, out jToken))
				jArray = jToken.Value<JArray>();
				jArray.AddFirst(newJsonObject); // add so most recent is at beginning of the array

				return existingStoredJsonObject.ToString(Formatting.None);

			// if the array does not exist in the existing json, just create it
			jArray = new JArray(newJsonObject);
			existingStoredJsonObject.Add(keyOfArray, jArray);

			return existingStoredJsonObject.ToString(Formatting.None);

		return jsonAsString;

	public static JObject CreateJsonObjectFromDictionary(IDictionary<string, string> dataForJson)
		var outObject = new JObject();

		foreach (var keyValuePair in dataForJson)
			outObject.Add(keyValuePair.Key, keyValuePair.Value);

		return outObject;

The methods came in handy as I was storing json in a database field of type nvarchar. I needed to be able to update the json, add new keys/values and augment existing arrays.

Here’s a few usage examples:

  1. Adds a new property to an existing Json object:
  2. public static AugmentOrderHistory(SomeViewModel viewModel, bool? createdByImpersonatedClaim)
    	JProperty createdByImpersonatedUserMsg = new JProperty(
    	newOrder.AdminComments = JsonHelpers.MergeJsonWithStoredField(
  3. Converts a C# object to a JObject and adds it as a Json object to a Javascript array.
    public static AugmentOrderHistoryWithObject(...)
    	var fieldsToComments = new PostEventMaterialsWereAccessed
    		DateAdded = TtsConfig.UtcNowAsCts,
    		Code = identifyModel.OnDemandCode,
    		UserEmail = identifyModel.Email,
    		UserName = identifyModel.FullName,		
    	string updatedUserComments = JsonHelpers.AddObjectToJsonArray(
            /* json looks something like {"PostEventMaterialsWereAccessed":[{"Code":"rzszq","DateAdded":"2015-06-03T06:49:34.0986495","UserName":"Jonty","UserEmail":""},{"Code":"rzszq","DateAdded":"2015-06-02T14:52:56.7051448","UserName":"harry","UserEmail":""}]} */

New Zealand should declare James Newton-King to be a nationl treasure.

Tracking Down Log4net Problems

This post is more of an FYI to myself than anything. There are a short number of steps which you need to take to debug Log4net issues when Log4net is not working. I always forget them and I am sick of navigating to the same StackOverflow question.

So, if the ADO.NET appender Log4net is not writing anything to the relevant table in your database, you need to take a look at the internal debugging built into Log4net. It’s only really 2 things that you need to do – add an app setting and a trace listener. Follow these steps to do that:

  1. add the following AppSetting to the AppSettings in your config file (Web.config or App.config as applicable):
    <add key="log4net.Internal.Debug" value="true"/>
  2. add the following trace listener:
        <trace autoflush="true">
                    initializeData="C:\tmp\log4net.txt" />

Obviously, put that text file where ever you like on your machine.

Now you will have a log file which you can scrutinise to see what’s going on. (More often than not, there will be a typo or something in your ConnectionString.)