Archive for April, 2009

Guaranteeing Disposal Of UserControls In ASP.NET

3 commentsWritten on April 9th, 2009 by
Categories: Software Development

As i mentioned recently, one of our applications suffered from a memory leak because one of ASP.NET's UserControls (in this case, the Repeater) created instances of one of our own UserControl type without disposing them afterward. In most cases, this isn't really a big issue, but if your UserControl really requires explicit Disposal this can obviously be a pretty big problem.

In order to prevent this situation from ever happening again, i came up with an approach which guarantees that all instances of UserControls that require explicit disposal are indeed properly disposed at the end of the request in which they were created. I don't really like this approach as i consider it a hack. But then again, when ASP.NET controls fail to dispose the controls they create in some occasions, all bets are off.

And so the Disposer class was born:

    public static class Disposer
    {
        private const string DisposalEnabledKey = "_disposeTrackedObjects";
        private const string DisposableObjectsKey = "_disposableObjects";
 
        public static void EnableDisposalOfTrackedObjectsForCurrentRequest()
        {
            HttpContext.Current.Items[DisposalEnabledKey] = true;
            HttpContext.Current.Items[DisposableObjectsKey] = new List<WeakReference>();
        }
 
        public static void RegisterForGuaranteedDisposal(IDisposable disposable)
        {
            if (GuaranteedDisposalIsEnabled())
            {
                var disposables = GetTrackedDisposables();
                disposables.Add(new WeakReference(disposable));
            }
        }
 
        public static void DisposeTrackedReferences()
        {
            var disposables = GetTrackedDisposables();
 
            foreach (var reference in disposables)
            {
                if (reference.IsAlive)
                {
                    var disposable = reference.Target as IDisposable;
                    if (disposable != null) disposable.Dispose();
                }
            }
        }
 
        private static bool GuaranteedDisposalIsEnabled()
        {
            var value = HttpContext.Current.Items[DisposalEnabledKey];
 
            if (value == null)
            {
                return false;
            }
 
            return (bool)value;
        }
 
        private static List<WeakReference> GetTrackedDisposables()
        {
            return HttpContext.Current.Items[DisposableObjectsKey] as List<WeakReference> ?? new List<WeakReference>();
        }
    }

Ugly stuff, right? It gets worse.

In the constructor of the UserControl(s) that really need(s) to be disposed, add the following line:

            Disposer.RegisterForGuaranteedDisposal(this);

Then, we have our own custom HttpModule to complete this little hack-fest:

    public class OurKickAssHttpModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += context_BeginRequest;
            context.EndRequest += context_EndRequest;
        }
 
        private void context_BeginRequest(object sender, EventArgs e)
        {
            Disposer.EnableDisposalOfTrackedObjectsForCurrentRequest();
        }
 
        private void context_EndRequest(object sender, EventArgs e)
        {
            Disposer.DisposeTrackedReferences();
        }
 
        // not really needed here but it's required by IHttpModule
        public void Dispose() {}
    }

All in all, pretty horrible stuff if you ask me. But at least we're sure now that all instances of the UserControl are always properly disposed.

Resharper 4.5 Is Out

No Comments »Written on April 9th, 2009 by
Categories: Visual Studio

It's finally here... i've been using the betas for a while now with hardly any issues so this final release should be very solid as well. Most important improvement IMO is the improved performance and reduced memory overhead for large solutions. We all know Visual Studio is pretty slow when it comes to large solutions, and adding Resharper to the mix only makes matters worse (though it still improves your overall productivity a lot no matter what performance penalty is involved). This release should improve this, and the other new features are pretty good too. Be sure to check it out ;)

The Joys Of Debugging ASP.NET Memory Leaks

5 commentsWritten on April 6th, 2009 by
Categories: .NET bugs, ASP.NET, Memory Management

One of my coworkers describes a very interesting memory leak he just fixed. Be sure to read his post to get the entire story.

We basically had a custom UserControl which contained (among other things) a Repeater which would render another custom UserControl. Nothing really weird there, right? The problem was that the custom UserControl that was created by the Repeater explicitly needed to be disposed. No problem, System.Web.UI.Control implements IDisposable so we could just override the Dispose method, perform our cleanup there and then proceed with the base Dispose implementation.

Now, i'm far from an ASP.NET expert but i was under the impression that all Page and UserControl instances would always have their Dispose method called if they were created by other ASP.NET controls (containing pages or controls). After all, what's the point in implementing IDisposable in the base Control class if you're not even going to guarantee proper usage of the pattern, right?

Well, as Kristof describes in his post, there is at least one situation where a UserControl is not disposed of, even though it was created by a Repeater. In our case, the leak was subtle. It took a stress test of 10 hours with a load that would be comparable to real world usage of one month to expose the leak. A lot of people would say "oh, let's just recycle the application pool periodically and everything is A-OK". But the very idea of having to recycle an application pool periodically to keep a system up and running is just a cop out to me. Good code should not require periodic restarts. Period.

I wonder how many ASP.NET WebForms applications might actually have the same (or at least similar) problem(s) like the one Kristof encountered. If everyone keeps recycling their application pools periodically, we unfortunately may never found out.

The Subscriber Count

3 commentsWritten on April 3rd, 2009 by
Categories: About The Blog

After the subscriber count (as reported by Feedburner) dropped to 325 today instead of the usual average of slightly above 900, some people started asking me "what's up with the low subscriber count all of the sudden?"

Well, here's the deal... in the beginning of this blog, there was just one feed (http://davybrion.com/blog/feed/) but after a while i switched to Feedburner. That introduced another URL to access the feed: http://feeds.feedburner.com/davybrion. Then another couple of months later, i migrated from a regular Feedburner account to a Google Feedburner account. For some reason, this introduced another 2 URLs: http://feeds2.feedburner.com/davybrion and http://feedproxy.google.com/davybrion. I really don't understand why they need to add 2 more URL's but i'm sure they have their reasons.

The cool thing about Feedburner is that it gives you an overview of how many people are following your RSS feed and what clients they're using. For instance, when everything works alright it tells me that 630 people are using Google Reader to follow my feed. Which is the combined total of subscribers to my 4 feed URLs as reported by Google Reader. But for some reason, Google Feedburner sometimes doesn't count all of the subscribers that are using Google Reader. Sometimes it just doesn't count the subscribers of one of the feeds, and occasionally it simply doesn't count any Google Reader subscribers at all. It's usually fixed within a few days or sometimes even the next day.

So that's pretty much why the subscriber count sometimes looks like it's on a roller coaster ride. But why a company that is otherwise capable of indexing the entire internet and making it easy and fast to search is incapable of incrementing a simple counter with a total that one of its other products is reporting is far beyond my ability to comprehend though :)

Assigning Foreign Keys In NHibernate

9 commentsWritten on April 3rd, 2009 by
Categories: NHibernate

This post from the Entity Framework team recently caught my attention. It discusses the ability to add actual foreign key values to your entities instead of just references to the referred entities. One of the benefits of this ability is that you can assign foreign key values to an entity's properties without having to actually retrieve the entity you are referring to. While i am no fan of this approach, i do want to point out that you can do this with NHibernate too, especially because some people don't know about this.

Take a look at the following code:

                product.Category = session.Get<ProductCategory>(categoryId);
                session.SaveOrUpdate(product);

This code changes the product's Category property, and to do that it retrieves the actual ProductCategory instance through the id value of the category. This causes 2 database hits. One to retrieve the ProductCategory, and one to persist the Product.

You could do this instead:

                product.Category = session.Load<ProductCategory>(categoryId);
                // this verifies that the product.Category is an uninitialized proxy
                // which means that we did not fetch the product category from the database
                Assert.IsFalse(NHibernateUtil.IsInitialized(product.Category));
                // we were able to save the product without having loaded the product category
                session.Save(product);

Notice how we use ISession's Load method here, instead of the Get method to 'retrieve' the ProductCategory. The Get method actually fetches the entity from the database if it's not already in the session cache. The Load method however will return an uninitialized proxy to the ProductCategory entity if it's not present in the session cache. The NHibernateUtil.IsInitialized() method will return false, because this proxy is indeed uninitialized. It does not hit the database until you try to access any of the properties of the ProductCategory proxy, except for its identifier property. So accessing product.Category.Id would not hit the database, but product.Category.Name or product.Category.Description would.

If you want to avoid hitting the database to assign foreign keys, using a proxy might be an interesting alternative for you.