Developing a plugin framework in ASP. NET MVC with medium trust

Source: Internet
Author: User
Tags umbraco

Http://shazwazza.com/post/Developing-a-plugin-framework-in-ASPNET-with-medium-trust.aspx

January 7, 10:06 tweets

I ' ve recently spent quite a lot of time researching and prototyping different ways to create a plugin engine in ASP C3 and primarily finding a nice-to load plugins (DLLs) on from outside of the ' bin ' folder. Although this post focuses in MVC3, I am sure that the same principles would apply for other MVC versions.

The issues

Loading DLLs from outside of the ' bin ' folder isn ' t really anything new or cutting edge, however when working with MVC This becomes more difficult. This was primarily due to how MVC loads/finds types that it needs to process including controllers, view models (more Preci sely The generic argument passed to a viewpage or used with the @model declaration in Razor), model binders, etc ... MVC is very tied to the BuildManager which are the mechanism for compiling views, and locating other services such as Contr Ollers. By default the BuildManager are only familiar with assembies in the ' Bin ' folder and in the GAC, so if you start putting DL Ls in folders outside of the ' bin ' then it won ' t is able to locate the MVC services and objects so you might want it to be referencing.

Another issue that needs to be dealt with is DLL file locking. When a plugin DLL was loaded and is on use, the CLR would lock the file. This becomes a issue if developers want to update the plugin DLL while the website are running since they ' t be won To unless they bump the Web. config or take the site down. This holds true for the MEF and how it loads DLLs as well.

. Net 4 to the rescue ... almost

One of the new features in. Net 4 are the ability to execute code before the app initializes which compliments another new feature of the BuildManager that lets you add assembly references to it at runtime (which must is done on application pre- init). Here's a nice little reference to these new features from Phil HAACK:HTTP://HAACKED.COM/ARCHIVE/2010/05/16/THREE-HIDDEN-E Xtensibility-gems-in-asp-net-4.aspx. The essential to making a plugin framework work with MVC so that the Buildmanage R knows where to reference your plugin DLLs outside of the ' bin '. However, this isn ' t the end of the story.

Strongly typed views with model Types located in plugin DLLs

Unfortunately if you had a view that was strongly typed to a model that exists outside of the ' bin ' and then you'll find out Very quickly that it doesn ' t work and it won ' t actually tell you why. This was because the Razorviewengine uses the BuildManager to compile the view into a dynamic assembly and then usesActivator.CreateInstanceTo instantiate the newly compiled object. This is where the problem lies, the current AppDomain doesn ' t know how to resolve the model Type for the strongly typed VI  EW since it doesn ' t exist in the ' bin ' or GAC. An even worse part on this scenario is so you don't get any error message telling what's this isn ' t working, or wher E the problem is. Instead you get the nice MVC view not found error: "...or its master is not found or no view engine supports the searched locations. The following locations were searched: ...Telling you it have searched for views in all of the viewengine locations and couldn ' t find it ... which is actually not  The error at all. Deep in the MVC3 source, it tries to instantiate the view object from the dynamic assembly and it fails so it just keeps l Ooking for this view in the rest of the viewengine paths.

Note:even though in MVC3 there ' s a new iviewpageactivator which should being responsible for instantiating the views that ha ve been compiled with the BuildManager, implementing a custom iviewpageactivator to handle this still does isn't work Becaus E somewhere in the MVC3 codebase fails before the call to the iviewpageactivator which have to does with resolving an ASSEMBL Y that's not in the ' bin '.

Full Trust

When working in full Trust we had a few options for dealing with the above scenario:

    • Use the AppDomain ' s resolveassembly event
      • By subscribing to this event, you is able to instruct the AppDomain where to look when it can ' t find a reference to a TYP E.
      • This is easily do by checking if your plugin assemblies match the assembly being searched for, and then returning the AS sembly object If found:
StaticAssembly Currentdomain_assemblyresolve (Objectsender, Resolveeventargs args) {var pluginsfolder= NewDirectoryInfo (Hostingenvironment.mappath ("~/plugins"));Return(from FInchPluginsfolder.getfiles ( "*.dll" , searchoption.alldirectories) let AssemblyName = Assemblyname.getassemblyname (f.fullname) where Assemblyname.fullname == args. Name | | AssemblyName.FullName.Split ( , ' ) [0] == args. Name Select Assembly.loadfile (f.fullname)). FirstOrDefault ();}
    • Shadow Copy your plugin DLLs into the AppDomain ' s dynamicdirectory.
      • This are the directory that the BuildManager compiles it's dynamic assemblies into and are also a directory that the Appdoma In looks to when resolving Type ' s from assemblies.
      • You can shadow copy your plugin DLLs to this folder on the app Pre-init and everything ' should just work '
    • Replace the razorviewengine with a custom razor view engine so compiles views manually but makes references to the Appro Priate plugin DLLs
      • I actually had this working a Umbraco V5 prototype but it's hugely overkill and unnecessary plus you actually would h Ave to replace the razorviewengine which is pretty absurd.
The burden of Medium Trust

In the MVC world there's only a couple hurdles to jump when loading in plugins from outside of the ' bin ' folder in full Tr Ust. In Medium Trust However, things get interesting. Unfortunately in Medium Trust it isn't possible to handle the Assemblyresolve event and it's also not possible to access The dynamicdirectory of the AppDomain so the above a solutions get thrown out the window. Further to the IT seems as though you can ' t use the CodeDom in Medium Trust to custom compile views.

Previous attempts

For a while I began to think the this wasn ' t possible and I thought I tried everything:

  • Shadow copying DLLs from the Plugins folder to the ' Bin ' folder on application Pre-init
    • this fails Becau Se even during app Pre-init, the application pool would still recycle. Well, it doesn ' t actually ' fail ' unless your keep re-copying the DLL into the bin. If you check if it already exists and don ' t copy into the bin than this solution would work for you but it's hardly a ' solu tion ' Since you might as well just put all your DLLs into the ' bin ' of the first place.
  • Trying to use sub folders of the ' bin ' folder to load plugins.
    • Turns out that ASP. Doesn ' t by default load in DLLs that exist in sub-folders of the bin, though from the It looks Like standard. Net apps actually do.
    • Another interesting point is so if you try to copy a DLL into a sub folder of the bin during application pre-init you G Et a funky error: "Storage Scopes cannot was created when _appstart was executing". It seems that ASP. Monitoring all changes in the Bin folder regardless of whether or not they be in sub folders but Still doesn ' t load or reference those assemblies.
An easy solution

So, the easy solution are to just set a ' PrivatePath ' on the ' probing ' element in your Web. config to tell the AppDomain To also look for assemblies/types in the specified folders. I did a try this before if trying to load plugins from sub folders in the bin and couldn ' t get it into work. I ' m not sure if I am ' doing it wrong ' but it definitely wasn ' t working then, either that or attempting to set the this in sub Folders of the bin just doesn ' t work.

Runtime>  <assemblybinding xmlns="urn:schemas-microsoft-com:asm.v1" ><probing PrivatePath="plugins/temp"/>    
DLL File Locking

Since plugin DLLs get locked by the CLR when they is loaded, we need to work around this. The solution is to shadow copy of the DLLs to another folder on application Pre-init. As mentioned previously, this is one of the ways to get plugins loaded in full Trust and in my opinion is the nicest-a-t o do it since it kills 2 birds with one stone. In Medium Trust However, we'll have the through some hoops and shadow copy of the DLLs to a temp folder that exists Withi n the Web application. Important:when you ' re copying DLLs you might being tempted to modify the name of the DLL by adding a version number or Simil AR, but this won't work and you'll get a "the located assembly ' s manifest definition ... does not match the Assembly Reference. " exception.

Solution

Update:the Latest version of this code can is found in the Umbraco V5 source code. The following code does work but there's been a lot of enhancements to it in the Umbraco core. Here's the latest changeset as of 16/16/2012 Umbraco V5 PluginManager.cs

Working in full Trust, the simplest solution are to shadow copy your plugin DLLs into your AppDomain dynamicdirectory. Working in Medium Trust you ' ll need to do the following:

    • On application Pre-init:
      • Shadow Copy all of your plugin DLLs to a temporary folder in your Web application (not in the ' bin ')
      • Add all of the copied DLLs to being referenced by the BuildManager
    • ADD all folder paths to the PrivatePath attribute of the probing element in your Web. config to Where you'll be copying your DLLs
      • If you had more than one, you need to semi-colon separate them

Thanks to Glenn Block @ Microsoft who gave me a few suggestions regarding DLL file locking with MEF, Assembly load context S and probing paths! You put me back on track after I had pretty much given up.

Here's the code to does the shadow copying and providing the assemblies to the BuildManager on application pre-init (Mak E sure you set the PrivatePath on the probing element in your Web. config first!!)

UsingSystem.Linq;Usingsystem.web;UsingSystem.IO;UsingSystem.Web.Hosting;UsingSystem.Web.Compilation;UsingSystem.Reflection; [Assembly:preapplicationstartmethod (typeof(PluginFramework.Plugins.PreApplicationInit),"Initialize")]NamespacePluginframework.plugins {Public ClassPreapplicationinit {StaticPreapplicationinit () {Pluginfolder= NewDirectoryInfo (Hostingenvironment.mappath ("~/plugins")); Shadowcopyfolder= NewDirectoryInfo (Hostingenvironment.mappath ("~/plugins/temp")); }/// <summary> ///The source plugin folder from which to shadow copy from/// </summary> /// <remarks> ///This folder can contain sub folderst to organize plugin types/// </remarks> Private Static ReadOnlyDirectoryInfo Pluginfolder;/// <summary> ///The folder to shadow copy of the plugin DLLs to use for running the app/// </summary> Private Static ReadOnlyDirectoryInfo Shadowcopyfolder;Public Static voidInitialize () {directory.createdirectory (shadowcopyfolder.fullname);//Clear out plugins) Foreach(Var fInchShadowcopyfolder.getfiles ("*.dll", Searchoption.alldirectories)) {F.delete ();} //shadow copy files foreach (var plug in pluginfolder.getfiles ("*.dll") c12>, searchoption.alldirectories)) {var di = directory.createdirectory (Path.Combine ( Shadowcopyfolder.fullname, plug. Directory.name)); // note:you cannot rename the plugin DLL to a different name, it'll fail because the ASSEMBL

Developing a plugin framework in ASP. NET MVC with medium trust

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.