Use ASP. net mvc engine to develop plug-in systems, asp. netmvc

Source: Internet
Author: User

Use ASP. net mvc engine to develop plug-in systems, asp. netmvc

I. 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 dll that implements a service interface, and then calls it using reflection or IOC technology, but a complete small mvc application, I can install and disable the Plugin in the background. The directory structure is as follows:

Generated and placed in the Plugins folder under the root directory of the site. Each plug-in has a sub folder

Plugins/Sms. AliYun/

Plugins/Sms. ManDao/

I am an obsessive lazy, and I don't want to copy the generated dll file to the bin directory.

Ii. Problems to be Solved

1.asp.net will only load the dll in the "bin" folder by default, and the plug-in files we want are scattered in the subdirectories under the Plugins directory.

2. What should I do when a model is used in a view? By default, RazorViewEngine uses BuildManager to compile the view into a dynamic assembly, and then uses Activator. createInstance instances the newly compiled object. When using the plug-in dll, the current AppDomain does not know how to parse this view that references the model because it does not exist in "bin" or GAC. What's worse, it won't receive any error message, 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 running under the site. Directly overwriting the plug-in dll will tell you that the current dll is in use and cannot be overwritten.

4. View files are not stored in the View directory of the site. How to load them.

Iii. Net 4.0 makes it all possible

A new feature in Net4.0 is the ability to execute code (PreApplicationStartMethodAttribute) before application initialization. This feature allows applications to do some work before Application_Star, for example, before starting an application, let us know where the dll of the mvc plug-in system is stored and perform pre-loading. Some of the new features of. net are described by bloggers. Click me ., For PreApplicationStartMethodAttribute, you have already written this article. Click me. The enabling module of the Abp should also be implemented using the PreApplicationStartMethodAttribute feature principle. I haven't looked at it yet.

Iv. Solutions

1. Modify the web. config directory of the main site so that files in the bin directory can be loaded from other directories.

 <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">  <probing privatePath="Plugins/temp/" /> </assemblyBinding> </runtime>

2. develop a Simple plug-in management class. The function of this class is to copy the dll in each subdirectory of Plugins to the folder specified in step 1 before Application_Start. In order to make the demo as simple as possible, no repeated dll detection (for example, the ef assembly is referenced in the plug-in, and the main site is also referenced. The ef dll already exists in the site bin directory, there is no need to copy the dll in the plug-in to the dynamic assembly directory set above)

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 (HostingEnvironment. MapPath ("~ /Plugins "); ShadowCopyFolder = new DirectoryInfo (HostingEnvironment. MapPath ("~ /Plugins/temp ");} // <summary> // The directory where the plug-in is located // </summary> private static readonly DirectoryInfo PluginFolder; /// <summary> // specifies the dll Directory when the program runs. // </summary> private static readonly DirectoryInfo ShadowCopyFolder; public static void Initialize () {Directory. createDirectory (ShadowCopyFolder. fullName); // clear the file 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 ();}}}}

3. How can the View engine find our views? The answer is to override the RazorViewEngine method. I adopted the Convention over the configuration method (assuming that our plug-in project namespace is Plugins. apps. the default controller namespace is Plugins. apps. sms. controllers: the folder generated by the plug-in must be/Plugins. apps. sms/). By analyzing the current controller, you can know the View directory location of the current plug-in.

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> // defines the address of the view page. /// </Summary> private string [] _ viewLocationFormats = new [] {"~ /Views/Parts/{0}. cshtml ","~ /Plugins/{pluginFolder}/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", ""); // The Controller in the plug-in. The View directory needs to process if (ns. toLower (). contains ("plugins") {var pluginsFolder = Ns. toLower (). replace (". controllers "," "); ViewLocationFormats = ReplacePlaceholder (pluginsFolder);} return base. findView (controllerContext, viewName, masterName, useCache );} /// <summary> /// Replace the infolder placeholder /// </summary> /// <param name = "folderName"> </param> private string [] ReplacePlaceholder (string folderName) {string [] tempArray = new string [_ viewLocationFormats. length]; if (_ viewlow.o NFormats! = Null) {for (int I = 0; I <_ viewLocationFormats. length; I ++) {tempArray [I] = _ viewLocationFormats [I]. replace ("{pluginFolder}", folderName) ;}} return tempArray ;}}}

Then, in the Global. asax of the main site, specify the Razor engine as the rewritable

4. Start to create a plug-in Directory, which is not much different from the MVC project we have created at ordinary times, but requires some settings for release.

. The generated path should be written according to the 3rd conventions. Otherwise, the view file will not be found.

The web. config and. cshtml files under the. View directory must be copied to the generated directory (right-click the file)

3. set the generate attribute in the reference project. If the main program already has an attribute, set "Copy to output directory" to none. Otherwise, an error occurs when copying the property to the dynamic bin directory, you can modify the class in step 1 and add the file comparison function. If the class is not in the bin directory, it is copied to the dynamic bin directory.

4. The generated directory structure is as follows:

5. Run it. Everything works normally. The controller in the plug-in works normally, and there is no problem if the Model is referenced in the view.

By now, the core part of a plug-in system has been completed. You can continue to expand and add plug-in discovery, installation, and uninstallation functions. These functions are pediatrics compared with core functions. In the future, I will develop an article on the plug-in system based on the Abp framework. If you are interested, prepare the bench and buy the seeds and nuts :)

V. Source Code

Download Plugins link: https://pan.baidu.com/s/1nvmbL81 password: 85v1

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

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.