Visual Studio 2010: ApplicationIcon

by Aaron 30. June 2011 02:45

I recently had need to associate a different icon to my C# project based on the selected configuration (i.e. Debug, Release, SomeCustomConfigurationYouCreatedToBeClever).

I did the standard thing of right-click on the project in the Solution Explorer, select Unload Project. Then I again, right-click on the project and choose Edit MyFancyProject.csproj. ApplicationIcon was easy to find.

I tried several ways of setting the icon. I tried a handful of ApplicationIcon nodes with Condition attribute set to " '$(Configuration)' == 'SomeCustomConfigurationYouCreatedToBeClever' ".  I added a line for each of the different configurations.

I saved and reloaded the project into Visual Studio.  The icon it showed wasn't the icon for the selected configuration.  I checked the syntax in the CSPROJ file with no luck.  I changed it to a Choose element with multiple conditions to add a new PropertyGroup with the appropriate icon.  Again, Visual Studio showed me the wrong icon.

Finally, I added the ApplicationIcon element to each of the $(Configuration)|$(Platform).  Still, didn't work!

I decided to just try compiling the application to see what icon was embedded and displayed for the executable after a build.  The icon was right!

The moral of this story is that Visual Studio doesn't process the conditions set in the CSPROJ file, but will process it during the build.

Tags: , , , ,

Thread safety...why didn't I see it before????

by Aaron 28. May 2010 21:29

So a few weeks ago, we deployed the latest version of our application to a customer.  Within a couple of hours, the web servers were throwing a ton of unhandled exceptions.  The app pools had to be recycled pretty frequently.  We eventually rolled back.

This happened again when we deployed at the end of the next sprint.  I hadn't looked at the error yet, but I began looking more heavily at the changes that were made since the previous successful deployment two sprints ago.

Between my coworker and me, I was more heavily updating the core framework, while he was doing more to update the UI components.  So I suspected it was something that I had changed, but nothing that I changed stood out as "wrong".

The first thing that did stand out to me as a possibility was one of the Actions on a Controller I updated used to have the responses cached in an OutputCache profile.  I had to stop caching the response because different responses were going to be returned based on the user's session.  As a test though, we put caching back in.  The original reason for caching the response was to speed up the Acton which was retrieving a file from the server.

The production site is load-balanced between two servers.  As a test, we deployed the change with caching added back in to one of the servers expecting the other server to crash.  After the expected amount of time, that's exactly what happened!  We deployed to the other server while I stretched my arm around and patted myself on the back for being so smart!  I declared that the problem was probably because of resource issues and disk thrashing and blah blah blah blah...blah.  Of course I was wrong.

In fact, the issue was happening overnight, and again the next day.  We went to the client site to observe and dig through the server logs.

What we saw happening was a plethora of exceptions happening at the time of the application dying.  It was the same exception happening many many times per minute:

Index was outside the bounds of the array.

"Interesting," I exaggerated.  In fact it wasn't interesting at all.  I was even able to figure out what line it was occurring on.  The snippet looked something like this:

if (myStaticGenericDictionary[keyObject] == null)
    myStaticGenericDictionary[keyObject] = objectWeWantToKeep;
return myStaticGenericDictionary[keyObject];

Not very interesting.  Adding the value into the dictionary is, in fact, the line that was throwing the exception.

I knew it was a concurrency issue.  I won't go into all the boring details about how I sat there scratching my head pondering the simplicity of the statement throwing the exception versus the complexities and reasons of how, when, and why.  Just know that I did, and it was for longer than it should have been.  Instead, allow me to cover the architecture, the primary change that exacerbated the issue, and the solution.

Note the use of the word "exacerbation".  See, this issue had actually occurred in the past, we had the error reported to us a couple of times, we just didn't realize it.  We didn't ignore those other times it happened, we just didn't feel we had anything to worry about because of teh rarity and what we assumed was causing it.

Anyway...  Here's a rough UML diagram of what the architecture looks like: 

A bunch of controllers, a bunch of views, and even the view models all call GetMyContextObject() based on the current HttpContext.  The method looks like:

private static MyContextObject GetMyContextObject(HttpContextBase key)
{
    if (!myStaticDictionary.ContainsKey(key))
        myStaticDictionary[key] = new MyContextObject(key);
// ^^^ that line is throwing the exception!
    return myStaticDictionary[key];
}

You can see, based on the comment, and the monologue above, which line was throwing the exception.

The controllers that are descendant from MyControllerBase all have a Dispose(bool) method implemented.  That Dispose calls ReleaseMyContextObject().  That method looks like:

public static void ReleaseMyContextObject(HttpContextBase key)
{
    myStaticDictionary.Remove(key);
}

I'm going to tell you a bit of a spoiler now.  Public members on instances of Dictionary<TKey, TValue> aren't guaranteed thread safe.  Don't take my word for it though.  More on that later.

The change that we made was to the MyOneOffController that isn't a descendant of MyControllerBase.  The change was to do just that: make it a descendant of MyControllerBase.

As you can see, it doesn't look much different.

Now where the problems begin. MyOneOffController is used pretty heavily by one of our customer sites.  For every page that's loaded, that controller is called at least 4 times for each page.

So once that controller inherited the base Dispose() method, suddenly the dictionary is really getting a workout.  It has threads coming and going and going and coming.  It just isn't prepared for this kind of thing.

The answer was to synchronize those threads.  It was honestly an easy change.  Our GetMyContextObject() method now looks much like this:

private static MyContextObject GetMyContextObject(HttpContextBase key)
{
    MyContextObject myContextObject = null;
    lock (myStaticDictionary)
    {
        if (!myStaticDictionary.ContainsKey(key))
            myStaticDictionary[key] = new MyContextObject(key);
        myContextObject = myStaticDictionary[key];
    }
    return myContextObject;
}

And our ReleaseMyContextObject() looks much like this:

public static void ReleaseMyContextObject(HttpContextBase key)
{
    lock (myStaticDictionary)
        myStaticDictionary.Remove(key);
}

By locking the dictionary, and doing the smallest amount of work possible within the lock block, we managed to eliminate the exception entirely.  Folks were nervous that it wasn't fixed.  I assured them by letting them know I was 98% certain that the issue was resolved.  I mean, what could go wrong?

Nothing went wrong, and the application is serving up data like a champ!  I am still uncomfortable with where the context data is being cached and removed, but the product is stable for now, and that'll be cleaned up in a future sprint.

Tags: , , , , , , , , ,