Using System.Addin with Assembly generated in memory

299 views Asked by At

I have an application where I have to provide on-the-fly extensibility to the user. You can think of it as a sort of calculation engine, with a lot of data and some math / numeric algorithms. I provide some static fields (the data) and methods (the calculations) with which the user can build a valid C# expression that should return a double.

The user types the valid expression on a text box, and I should provide the results. What I currently do is that I inject the expression on a static method of an assembly that is generated in memory, following the steps in http://blogs.msdn.com/b/abhinaba/archive/2006/02/09/528416.aspx. I then use reflection to call the specific method and return the result.

This works fine, except for the fact that the generated assemblies keep accumulating over the lifecycle of the application. This was ok when all I had were client applications, but now I'm moving into a server based application, and I don't want to have to reset the service from time to time.

When searching on how to unload an assembly, I found out the System.Addin namespace. It does exactly what I want: the loading of the assembly on a different AppDomain, which I can discard latter on. It even encapsulates all the reflection.

The only problem I have now is that the AddInStore expects a file path, but all my assemblies are generated in memory, by setting the GenerateInMemory property of the CompileParameters used to true. Is it absolutely necessary to have my assemblies written to disk? Or is it possible to use an assembly compiled at run-time directly as an add-in?

Best regards, Carlos

2

There are 2 answers

0
Lzh On

I don't understand what you're using AddInStore for (unloading assemblies?) but you can just unload the appdomain (which you said you were able to create your dynamically loaded assembly in):

            AppDomain.Unload(yourAppDomain);

Or maybe you're facing a much greater issue!

0
Panos Rontogiannis On

Maybe DynamicMethod is what you are looking for.

If not, then you could have a look at IronPython. It is very easy to add to your application and quite powerfull too. Sure this will be slower than compiled C# code but I'm not sure if it will be slower than compilation+reflection.

Of course you could do what MZN mentions. You could:

  1. Change your compiler class to derive from MarshalByRefObj. This is needed for the CLR to create a proxy object. You will have to check a little bit .Net Remoting. Not too much though.
  2. Create your own AppDomain,
  3. Finally call one of the overloads of CreateInstanceFromAndUnwrap to load the assmebly with your compiler class on the new AppDomain and create an instance of your compiler on it. It will return to you the proxy object. Then do the actuall compilation using the proxy object. The compiled assembly will be loaded on the new AppDomain. When you decide that you don't need this assembly anymore or when you have reached a max number of compiled assemblies, you can make the call mentioned by MZN and unload the AppDomain and all loaded assemblies. Then repeat the whole thing again from a fresh AppDomain.

I think the easiest way is to use IronPython.

At them moment I am working on a MAF based application that includes compilation of C# code on-site (using System.CodeDom). It's similar to yours but in my case the compilation only takes place after an upgrade. So I do not have a problem with many "script" assemblies loaded. Also I build the assemblies on the file system.

Regards and good luck,

Panos