Along with putting feature dlls in a separate directory with the shared assemblies they need, I like to run these features in an isolated AppDomain to contain memory usage as well as state. When using Trace for logging, this is a great benefit because application state is local to the AppDomain, so my Trace.Listeners collection is dedicated to the AppDomain. Here’s an easy sample showing how to do this:
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
Trace.WriteLine(“Starting MainClass”);
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; // or another directory.
setup.ApplicationName = “My Domain”;
AppDomain ad = AppDomain.CreateDomain(“CreateDomain”, null, setup);
object o = ad.CreateInstanceAndUnwrap(“BusinessLogic”, “BusinessLogic.BusinessLogic”);
Trace.WriteLine(o.ToString());
Trace.WriteLine(“DONE testing appdomain. Now testing process”);
Console.ReadLine();
And here is my BusinessLogic class I contrived for this test:
namespace BusinessLogic
{
/// <summary>
/// Summary description for Class1.
/// </summary>
[Serializable()]
public class BusinessLogic : MarshalByRefObject
{
public override string ToString(){
System.Diagnostics.Trace.WriteLine(“From Business Logic”);
string retValue = “Information about current runtime:n”;
retValue += “Current AppDomain location: ” + AppDomain.CurrentDomain.BaseDirectory + “n”;
retValue += “Executing Assembly FullName: ” + Assembly.GetExecutingAssembly().ToString() + “n”;
retValue += “BusinessLogic location: ” + Assembly.GetExecutingAssembly().Location + “n”;
retValue += “Framework Assembly FullName: ” + typeof(Audit).Assembly.ToString() + “n”;
retValue += “Framework location” + typeof(Audit).Assembly.Location + “n”;
return retValue;
}
public override bool Equals(object obj) {
throw new Exception(“BOMB”);
return base.Equals (obj);
}
}
}
Notice how I marked the class as Serializable. And don’t forget to mark other classes that you may need to pass back and forth (not many, I hope). I also have to inherit my object from MarshalByRefObject because my initial call is directly to this object. Any exceptions that may be raised up back to the parent AppDomain must also be Serialiable and implemet a Serialization constructor.
I love this model for code and state isolation, and it has made my life so much easier!