.netasp.netappdomainperformancecounter

Using custom performance counters across appdomain recycles


I have an ASP.NET application which tracks statistics by creating and writing to custom performance counters. Occasionally, I see in the error logs that indicate that the counters have failed to open because they had already been used in the current process. I presume this is due to my .NET appdomain having been reset within the same w3wp.exe process. How can I avoid these errors and re-establish a connection to my performance counters when my app domain has been recycled?

Counter construction:

PerformanceCounter pc = new PerformanceCounter();
pc.CategoryName = category_name;
pc.CounterName = counter_name;
pc.ReadOnly = false;
pc.InstanceLifetime =
PerformanceCounterInstanceLifetime.Process;
pc.InstanceName = instance_name;

Counter usage:

pc.Increment()

[Update on 3/26/09] The error message received is:

Instance '_lm_w3svc_1_root_myapp' already exists with a lifetime of Process. It cannot be recreated or reused until it has been removed or until the process using it has exited. already exists with a lifetime of Process.

I tried to replicate the exception in a console application by initializing the performance counters and writing to one of them in a transient AppDomain. I then unload the AppDomain and do it again in a second Appdomain (same process). They both succeed. I'm unsure now exactly what the cause of this is, my assumption about AppDomain recycling in ASP.NET seems to be false.


Solution

  • IIRC, IIS will not make sure that your first AppDomain is closed before it starts the second, particularly when you are recyclying it manually or automatically. I believe that when a recycle is initiated, the second AppDomain is instantiated first, and once that succeeds, new incoming requests are directed towards it, and then IIS waits for the first AppDomain (the one being shut down) to finish process any requests it has.

    The upshot is that there's an overlap where two AppDomains are in existence, both with the same value for instance_name.

    However, not all is solved. I have corrected this problem in my code by including the process ID as part of the instance name. But it seems to have introduced another problem -- what I thought was a process-scoped performance counter never seems to go away without rebooting the computer. (That may be a bug on my part, so YMMV).

    This is the routine I have for creating an instance name:

        private static string GetFriendlyInstanceName()
        {
            string friendlyName = AppDomain.CurrentDomain.FriendlyName;
            int dashPosition = friendlyName.IndexOf('-');
            if (dashPosition > 0)
            {
                friendlyName = friendlyName.Substring(0, dashPosition);
            }
            friendlyName = friendlyName.TrimStart('_');
            string processID = Process.GetCurrentProcess().Id.ToString();
            string processName = Process.GetCurrentProcess().ProcessName;
            string instanceName = processName + " " + processID + " " + friendlyName.Replace('/', '_').Trim('_').Trim();
            return instanceName;
        }