views:

155

answers:

4

Hello,

I have written a plugin solution for ASP MVC applications based on the advice found on this site, however, I have reached a roadblock and would appreciate some help. Without going too deep into how the plug-in system works, it does successfully load the controller and finds its appropriate view - the problem is that the view does not compile because it cannot resolve all the plugin's references (the plugin DLL has references to other DLL's that the host application doesn't know about).

I am using AssemblyResolve on the CurrentDomain but that doesn't get called when the default BuildManager is compiling the view, instead, it takes the list of assemblies from the web.config section. If I add all the plugin files to the GAC and add a reference in that section - it works fine. But that defeats the purpose of having a plugin system if I have to change web.config for every plug-in.

A little illustration to explain the issue: Plugin.dll --references--> PluginServices.dll

URL http://mysite.com/some/index MVC Application --load--> Plugin.dll PASS

MVC Application --load--> Plugin.SomeController PASS

MVC Application --find--> Plugin\Views\Some\Index.aspx PASS

MVC Application --compile--> Index.aspx FAIL (the view uses a type from PluginServices which cannot be found)

Is there a way to dynamically add references to BuildManager so that the compilation passes without changing web.config?

Thanks in advance!

A: 

You need to think about creating some interfaces or abstract classes (preferably interfaces) that you can put in the base application, so that when the plugin is not present, the base application will still compile. You then write the implementation for the interfaces or base classes in your plugin.

This article will get you started.

Robert Harvey
Thanks for the reply, but that doesn't really work since the problem is when ASP is trying to actually render the page and resolve the references, it can't find the associated DLL's.
Gil
If you don't have an implementation of your plugin's interfaces available (even if it's just a stub or a unit test mock), how can you expect the application to run?
Robert Harvey
The implementation is another assembly that gets delivered to the plugin at runtime. The plugin only knows about the interfaces of the objects it's using and a service layer subs that with a real object at runtime. The problem is that when the host application renders the views in the plugin it can't resolve the interface names.
Gil
A: 

I think you want to not have your host project compiling the plugin dlls. I think you want to have the plugins built in advance and perhaps embed the views in the assembly dll - this way, you can create the appropriate interfaces [Robert Harvey et-al] and let the host app rely on the fact that the dynamically loaded assembly's are ok. Perhaps you need to also create a plugin harness solution in which you (unit?) test the plugin as its developed/compiled - this seems necessary as some compilation errors in views dont show up immediately (this post should also help with compiler errors in views - it worked for me).

cottsak
This looked promising, but does work either. I pre-compiled all the views and made sure they are in the same folder as the host and it still could not resolve the references.There are a lot of posts out there that claim to have a plug-in design for ASP MVC but I have yet to see one that works with real-world views that have references to a business layer that is not known to the host application.
Gil
A: 

Gil,

Have a look at the following article. It explains how to use Reflection to obtain information about your business layer assembly at runtime, and then use InvokeMember to call your desired method. It does not require any kind of registration to work; you just need a path to your assembly.

C# Reflection and Dynamic Method Invocation
http://my.execpc.com/~gopalan/dotnet/reflection.html

Robert Harvey
A: 

Again, the part of loading the logic directly is working fine and also locating the views, the only part that doesn't work is that part where I have no control over - which is the actual rendering of the page.

I did, however, manage to get it to work. What I had to do is the following: 1) have the plugin DLL's registered in the GAC

2) add a reference to the DLL's in the web.config of the host under the 'compilation' section

3) make sure all views in the plugin don't use the 'inherit' attribute to strongly type the view, instead I create a local variable and cast the model to the appropriate type.

This all seems to work ok for now, but i will keep thinking about it to see if i can come up with a better solution.

Again, I am not sure how anyone can claim they have a plugin system for MVC and have not dealt with a simple view.aspx that has a line like: <%= Model.Name %> where Model is an object that the host does know about.

Thanks again for all your answers!

Gil
That sounds like a pretty cool idea. How come you don't like it?
Robert Harvey
The only reason is that it's a little cumbersome since you have to keep updating the files in the GAC. Other than that, it seems to work well.
Gil