An example of developing a plug-in system using the MVC engine in ASP

Source: Internet
Author: User
Tags hosting
This article is mainly for you to introduce the use of ASP. NET MVC engine development of plug-in system of relevant information, with a certain reference value, interested in small partners can refer to

First, preface

The plug-in system in my mind should be like NOP (more awesome like orchard,osgi. NET), each plug-in module is not just a bunch of DLLs that implement a business interface, and then invoked using reflection or IOC technology, but a complete MVC applet that I can use to control the installation and disabling of plugins in the background, with the following directory structure:

After the build is placed in the Plugins folder under the site root, each plugin has a subfolder

plugins/sms.aliyun/

plugins/sms.mandao/

I'm a compulsive lazy, and I don't want to copy the generated DLL files to the bin directory.

Ii. problems to be solved

The 1.asp.net engine only loads the DLLs in the Bin folder by default, and the plug-in files we want are scattered across subdirectories in the plugins directory.

2. How do I handle a model when I use it in a view? By default, Razorviewengine uses BuildManager to compile the view into a dynamic assembly. Then using Activator.CreateInstance to instantiate the newly compiled object, while using the plug-in DLL, the current AppDomain does not know how to parse the view that references the model, because it does not exist in the "bin" or the GAC. Even worse, you won't get any error messages telling you why it doesn't work, or where the problem is. Instead, he will tell you that files cannot be found from the view directory.

3. A plug-in is hanging under the site running, directly overwrite the plugin DLL, will tell you that the current DLL is in use, cannot be overwritten.

4. The view file is not placed in the site's view directory, how it is loaded.

Three. Net 4.0 makes it all possible

A new feature of Net4.0 is the ability to execute code before an application is initialized (Preapplicationstartmethodattribute), which allows the application to do some work before Application_star, For example, we can tell our MVC plug-in system where the DLLs are placed, do pre-load processing, and so on before the app starts. A few new features about. NET, there are crooked nuts written to have a blog to introduce, point me. , about Preapplicationstartmethodattribute, have Bo friends have already written, point me. The boot module for ABP should also be implemented using the Preapplicationstartmethodattribute feature principle, which is not yet seen.

Iv. Solutions

1. Modify the primary site Web. config directory to allow the runtime to load files from other directories, in addition to those in the bin directory

<runtime> <assemblybinding xmlns= "urn:schemas-microsoft-com:asm.v1" >  <probing privatepath= " plugins/temp/"/> </assemblyBinding> </runtime>

2. Develop a simple plug-in management class, the role of this class is to application_start the plugins in each subdirectory of the DLL to the 1th step of the specified folder, in order to make the demo as simple as possible, Duplicate DLLs are not detected (such as a plug-in reference to the EF assembly, the primary site is also referenced, in the site Bin directory already exists in the EF DLL, there is no need to copy the DLL in the plugin set in the dynamic assembly directory)

Using system;using system.collections.generic;using system.io;using system.linq;using System.Reflection;using System.text;using system.threading.tasks;using system.web;using system.web.compilation;using System.Web.Hosting; [Assembly:preapplicationstartmethod (typeof (Plugins.Core.PreApplicationInit), "Initialize")]namespace plugins.core{public class Preapplicationinit {static Preapplicationinit () {pluginfolder = new DirectoryInfo (Hosting   Environment.mappath ("~/plugins"));  Shadowcopyfolder = new DirectoryInfo (Hostingenvironment.mappath ("~/plugins/temp"));  }///<summary>///plug-in directory information///</summary> private static readonly DirectoryInfo Pluginfolder;  <summary>////The DLL directory specified when the program should be///</summary> private static readonly DirectoryInfo Shadowcopyfolder;   public static void Initialize () {directory.createdirectory (shadowcopyfolder.fullname); Emptying the file in the plugin DLL run directory foreach (var f in shadowcopyfolder.getfiles ("*.dll", searchoption.alldirectories)) {   F.delete (); } foreach (var plug in pluginfolder.getfiles ("*.dll", searchoption.alldirectories). Where (i=>i.directory.parent.name== "plugins")) {file.copy (plug. FullName, Path.Combine (shadowcopyfolder.fullname, plug.   Name), true); } foreach (Var a in shadowcopyfolder. GetFiles ("*.dll", searchoption.alldirectories). Select (x = Assemblyname.getassemblyname (X.fullname)).   Select (x = Assembly.Load (x.fullname))) {buildmanager.addreferencedassembly (a); }  } }}

3. How do I get the view engine to find our views? The answer is to rewrite the Razorviewengine method, I used the Convention is greater than the configuration of the way ( Assuming our plug-in project namespace is PLUGINS.APPS.SMS, the default controller namespace is Plugins.Apps.Sms.Controllers, and the plugin-generated folder must be/plugins/plugins.apps.sms /), the View directory location of the current plug-in can be known by analyzing the current controller

Using system;using system.collections.generic;using system.linq;using system.threading.tasks;using System.Web;using System.web.mvc;using system.web.webpages.razor;namespace plugins.web{public class Customerviewengine:  Razorviewengine {//<summary>///define the address of the view page. </summary> private string[] _viewlocationformats = new[] {"~/views/parts/{0}.cshtml", "~/plugins/{pluginf Older}/views/{1}/{0}.cshtml "," ~/plugins/{pluginfolder}/views/shared/{0}.cshtml "," ~/Views/{1}/{0}.cshtml "," ~/  Views/shared/{0}.cshtml ",}; public override Viewengineresult Findview (ControllerContext controllercontext, String viewName, string mastername, bool UseCache) {String ns = ControllerContext.Controller.GetType ().   Namespace; String controller = ControllerContext.Controller.GetType ().   Name.replace ("Controller", "" "); Description is the controller in the plug-in, and the view directory needs to be handled separately if (NS). ToLower (). Contains ("plugins")) {var pluginsfolder = ns. ToLower ().    Replace (". Controllers", ""); Viewlocationformats = RePlaceplaceholder (Pluginsfolder); } return base.  Findview (ControllerContext, ViewName, Mastername, UseCache); }///<summary>//Replace Pluginfolder placeholder///</summary>//<param name= "FolderName" ></param> PR   Ivate string[] Replaceplaceholder (string folderName) {string[] Temparray = new String[_viewlocationformats.length];  if (_viewlocationformats! = null) {for (int i = 0; i < _viewlocationformats.length; i++) {Temparray[i] = _viewlocationformats[i].    Replace ("{Pluginfolder}", FolderName);  }} return temparray; } }}

The razor engine is then specified in the Global.asax of the primary site as our rewritten

4. Starting a plug-in directory is not very different from the MVC project we normally build, but it needs to be set at the time of release.

The build path should be written in accordance with the Convention of 3rd, otherwise the view file will not be found

. The Web. config and. cshtml files in the view directory are copied to the build directory (right-click in the file)

3. Set the build properties in the reference project, the main program has already had the "Copy to Output directory" set to None, or copy to the dynamic Bin directory error, you can change the 2nd step of the class, add File comparison function, Bin directory is not in the dynamic Bin directory.

4. The resulting directory structure is as follows:

5. Run, everything is OK, the controller in the plugin is working properly, the model is not a problem in the view

In this case, the core part of a plug-in system is completed, you can continue to expand, add plug-in discovery, installation, uninstall functions, these are relative to the core function, are pediatrics. Later I will be based on the ABP framework out of a plug-in system article, interested in the small bench ready, melon seeds peanut Buy:)

Related Article

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.