Common uses and best practices for application domains in .NET? - c#

What are some guidelines and best practices for when to create new application domains within an application?
Also, what are some common uses and examples of how multiple application domains are used whithin an application?

The most common scenario I've seen is to be able to provide extensibility with a different security model than the main program.
Loading a plugin in a separate AppDomain allows two things:
You can implement a more restricted security model
You can prevent the plugin from tearing down your application if it's buggy
Another nice use of AppDomains are to load and inspect an assembly. Doing this in a separate AppDomain allows you to glean information (or run code) from a separate assembly, then unload the entire assembly from your process's space. If you load the assembly directly, there is no way to unload it. This is also useful if you want to be able to, at runtime, "upgrade" a type to a new version (ie: load a remote assembly, and reload it later).

It is recommended to create new domain when you need to host 3-rd party components within your application that are unreliable or you do not trust them (like plug-ins) or you want to be able to unload them.

A typical example is for plugin-/addin-like cases. Not only does it allow you to unload the DLL if required, it also gives you better security control over what the plugin is allowed to do.
Also, if you create temporary assemblies (code generation) which you want to unload again, this is a good way to do it. (LCG only allows implementing single methods, if you want to implement a complete class you need to emit to a "real" assembly).

Related

Is there a .NET IoC container that can load and unload assemblies

I'm beating my head against the wall trying to find a container that will accomplish this.
What I'd like to do is have a AS.NET website running and not unload / recycle the AppDomain when I deploy a new or updated business rule contained in an assembly. This implies that the folder is outside of the bin folder, and preferably above it, not under it (although I can live with that). The closet I've come to this so far is using Autofac and MEF, but it seems like there's no way to unload a previously loaded assembly.
Anybody have any resources they can point me to?
Thank you,
Stephen
No, there is not. Because it is not possible to unload an assembly, only a total appdomain. THis is a .NET runtime limitation - and as every .NET IOC container has to live in the .NET runtime it can not bypass it.
If your imports are big enough isolating them in separate appdomains may be a good and viable idea.
You can not unload assemblies in .Net without unload whole AppDomain. So the only way to allow it is to load new assemblies into new AppDomains.
While it may be possible to build such IoC container that will marshal all requests to new AppDomains for many interfaces such code would put very significant restrictions on methods/objects exposed by the interfaces. Also many .Net objects can't cross AppDomain boundary (xml, UI/controls, HTML context, database related classes).
It is significantly easier to allow ASP.Net to deal with reloading of the AppDomain.

What is an easily maintainable way to share a common .net class library over many corporate asp.net mvc 3 web applications?

I've been struggling to do this in a way that fulfills all of my requirements.
Here is what we have in our library:
Base classes for controllers and services
Business objects (stores, departments, etc)
Common Partial Views (Login, Error, etc)
Base class for HttpApplication
General common code (read an INI file, create a db conn, etc)
The one requirement that has been giving me trouble is as follows:
Lives in one place on a server. (i.e. copy local = false)
This breaks because:
The DLL containing the HttpApplication class must be in the same directory as the web apps dll to launch. I haven't found a way around that. I'm ok with duplicating this code in every app, but would rather not.
The shared views don't like to work if I use Assembly.LoadFrom() to load the dll from the shared location. (I've been using this method to precompile my views)
Any namespace shortcuts in web.config break at runtime with compilation errors because the web.config is parsed before the assembly is loaded.
My question to you folks is how do you handle your common code in a similar environment?
The GAC seems to be more trouble than its worth, and we want all of our apps to be using the same code, and not have multiple apps on multiple versions and have to maintain all of that. Are there design patters/best practices that can guide us in this regard?
Also, as a bonus, if you can solve any of the problems above, that would be great, too.
Thanks!
Edit: I guess a question that follows is whether or not we should even have a directory with the common dll(s) on the server, or if they should only be deployed as projects are deployed/updated?
Firstly, you will want to separate out what you're trying to achieve. Don't create 1 library that does everything or you will have a Big Ball of Mud. Don't be afraid to create several maintainable libraries to achieve what you're after. Is there a specific reason it needs to be stored in one location?
For example, several of the items you mention are MVC or web specific. If you have items that can be reused by MVC, create a class library that contains MVC base classes you inherit and reference them in your project. Use the single responsibility principle as much as possible.
Regarding the other items you mentioned, like database connectivity, if it's reusable, abstract it out in a data access class library and reference it. Other simple operations like reading an ini file or creating a file, create another library and abstract it to easy to use methods.
I prefer to copy the library dlls locally. You never know when you will need to make changes to the library, but you don't want all of your projects to stop compiling. When you're ready to implement a new version of the library, copy the dll in and recompile.
Not sure why all the hate towards the gac. It was designed to handle this specific problem. Install your common dlls to the gac and all apps can see them. Need to deploy a new one, just re-install it in one place.

Remove all references to a DLL across all application domains

I have a web application that dynamically loads assemblies based on database configuration entries to perform certain actions (dynamic plugin style architecture).
The calls to the objects are in a Factory Pattern implementation, and the object is cached (in a static dictionary<> within the Factory) as the calls can be made many thousands of times in a minute.
The calls to this factory are made from both the main web application and a number of webservices, some in different assemblies/projects.
When I need to update one of these DLLs, I have to recycle IIS to get the DLL released.
As this has an impact on another application on the server, I wanted to know if there was a way I could release the DLL without restarting IIS?
There's absolutely no way to unload a loaded assembly other than killing the AppDomain which is basically what you are doing when you restart IIS.
You can try restarting the application pool not the whole IIS server. Maybe that will do the trick for you
If you have an assembly that you need to load and unload you will have to jump through a few hoops.
the types being loaded must derive from MarshalByRefObject
the types being loaded must derive from an interface that will be used to call them
you must build a remoting based 'loader' to isolate the loaded assembly in a new appdomain, which can be unloaded.
see http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm for a good introduction. It is a bit dated and deals with dynamically generated code but given your rep I would assume that you can extract the relevant information.

Unload CodeDom-compiled assembly

I have some C# code (let's call it "script") I am compiling at runtime. It uses an interface in my main program that I use to access its functions. Once compiling is done I have CompilerResults.CompiledAssembly in which case I can CreateInstance(Type).
Once I am done using the script I would like to unload completely. From what I understand, I can only do this if I create a separate app domain:
Loading DLLs into a separate AppDomain
I had some questions specific to my implementation:
If I have multiple scripts to compile and want to unload them independently, do I have to create separate app domains for each?
What app domain names should I use? Would GUIDs be a good idea? Are there any names I should avoid that may conflict?
If the assembly is in a separate app domain, will it have any issues accessing the interface in the main program? I am currently doing ReferencedAssemblies.Add(typeof(Interface).Assembly.Location) before I compile.
Can I use CompilerParameters GenerateInMemory=true, or do I have to save it somewhere?
Answers in order:
Yes, if you want to unload them independently you'll need separate app domains.
Use whatever. It may help you debugging if you can identify it back to script, but that would be more true for the executing Thread.
Not so long as you set the domain setup's base path to your own.
AppDomainSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
No you don't need to save it and it doesn't sound like it would benefit you.

Loading assemblies at run-time

My project is an application in which we load various assemblies and perform operations on them.
We are stuck at a situation where we need to add a reference to the assembly we load (which will be selected by user). So I need to add a reference to the DLL at run time.
I tried this site but here they support only microsoft DLLs like System.Security etc. I want to add a reference to a user created dll (class library).
You can't "add a reference" at runtime - but you can load assemblies - Assembly.LoadFrom / Assembly.LoadFile etc. The problem is that you can't unload them unless you use AppDomains. Once you have an Assembly, you can use assemblyInstance.GetType(fullyQualifiedTypeName) to create instances via reflection (which you can then cast to known interfaces etc).
For a trivial example:
// just a random dll I have locally...
Assembly asm = Assembly.LoadFile(#"d:\protobuf-net.dll");
Type type = asm.GetType("ProtoBuf.ProtoContractAttribute");
object instance = Activator.CreateInstance(type);
At which point I can either cast instance to a known base-type/interface, or continue to use reflection to manipulate it.
If the assembly is in another location than the current or in the GAC, just use the
AppDomain.CurrentDomain.AssemblyResolve event to deliver the assembly yourself.
If you load an assembly at runtime, it will look for all its dependencies in the current location or the GAC, and load them if found, else error.
The Composite UI Application Block facilitates the design and implementation of your client applications in three areas:
It allows your application to be based on the concept of modules or plug-ins.
It allows developers with shell expertise to build components that hide user interface complexity from the business logic development.
It facilitates development using patterns for loose coupling between modules.
For WPF: Take a look at Prism: patterns & practices Composite Application Guidance for WPF and Silverlight site It does the assembly loading you require and actually uses Unity internally as it's IoC container.
For non WPF: Take a look at Smart Client - Composite UI Application Block
Or alternatively: Try any of the IoC containers like Castle Windsor, autofac, unity, etc.

Categories