.net 应用程序域的影子复制

AppDomain Shadow Copy explained

Introduction

The last couple of days I've been playing around with some stuff around WCF (formerly known as Indigo for the people who've been living on Mars lately). Instead of hosting stuff in IIS I decided (for no specific reason whatsoever) to take up the hosting stuff foreseen by WCF and to host my app inside a Windows Service. Pretty easy to do. However, there was one little problem that bothered me as I wanted to have some way to update the app without stopping the Windows Service that's responsible to host the app's functionality. In reality, what should happen is that the new version of the app core has to be loaded side-by-side with the old version till all clients connected with that old version are disconnected. Exactly what ASP.NET allows you to do in its bin folder. Enter the world of shadow copying.

A little example

Let's come to the point. How to enable this kind of stuff in your own application? A really simple and short example:

First, write a method to create a new app domain to host the new version of the assembly. As you might know, it's impossible to unload an assembly once loaded in an appdomain, you can only unload the associated appdomain entirely. What the following method does is pretty straightforward: it tells the CLR (assembly loader) where to look for files and then tells it to enable shadow copying by setting the (wrong-typed; a boolean property would have been much better) ShadowCopyFiles property to the string "true". Next, an appdomain is created with a unique name using some counter, and the assembly with the functionality is loaded (notice the _ indicates private members of the current class). This method is called when the app starts.

private void LoadAppDomain()
{
     AppDomainSetup setup = new AppDomainSetup
();
     setup.ApplicationBase =
"c:\\temp"
;
     setup.ShadowCopyFiles =
"true"
;

     AppDomain domain = AppDomain.CreateDomain("ShadowCopy domain " + _domainNumber, null
, setup);
     _currentAssembly = domain.Load(
"Server", null
);

     _domainNumber++;
}

The second piece of code required is the use of a FileSystemWatcher to detect when the original file is changed. This is done by watching (in this case) Server.dll in the "c:\temp" folder. When a change is detected, LoadAppDomain gets called. It's a little unfortunate the FileSystemWatcher triggers multiple events whenever a file is changed, so you need some plumbing to capture the event only once. This can be done using some datetime tracking or you can just keep a boolean field indicating the file was changed and load it upon arrival of a client.

Another thing to think about is how to unload the (old) appdomain(s). Doing it is as simple as calling AppDomain.Unload passing in the appdomain to be unloaded as the first parameter. The question however is when to do the unload. This will depend on the type of clients you are serving and mechanisms you have to detect no one is active in the appdomain anymore (which will be dependent on, say, the stateless or stateful nature of the app, just to name one thing). For the moment, in my app, there's just a timer that unloads "idle" appdomains after a couple of minutes from loading the new appdomain.

The last thing you have to do is cope with the clients in some way and send them to a "service" class that's defined in the Server.dll file. How you want to do this, depends on your (activation) scenario (such as singleton, singecall, ... - notice these indicate concepts, not .NET Remoting-specific technology pieces). A possiblity to create instances of the underlying service class is this:

IServer srv = (IServer)_currentAssembly.CreateInstance("ServerNamespace.Server");

Conclusion

Without going to much in depth on the specific scenario I was working on (maybe I'll write about this later on, if time and Belgian summer temperatures permit) you saw how easy it is to turn on shadow copying when creating an AppDomain. This feature keeps the assembly free for replacement while the app is running (read: no file locks). You might want to check out other AppDomainSetup members too, like ShadowCopyDirectories to limit the folders that are under shadow copy "protection".

posted on 2009-09-25 16:00  Maxwell Hu  阅读(500)  评论(0编辑  收藏  举报