• MVC 4 插件化架构简单实现


    ASP.NET MVC 4 插件化架构简单实现-思路篇

     

         用过和做过插件的都会了解插件的好处,园子里也有很多和讨论,但大都只些简单的加载程序集什么的,这里主要讨论的就是使用 ASP.NET MVC 4 来实现每个插件都可以完全从主站点剥离出来,即使只是一个插件,也是一个完整的站点,同时也可以和其它插件一起组装成一个庞大的系统。

    参考资料:

    ASP.NET MVC 4 源码。

    Orchard 源码。

    MVC3PlugInDemo 源码。

    ASP.NET MVC的Razor引擎:View编译原理

    基于ASP.NET MVC3 Razor的模块化/插件式架构实现

    基于OSGi.NET开发ASP.NET MVC 3.0插件化应用程序

    http://stackoverflow.com/questions/6923572/asp-net-mvc-3-portable-area-view-doesnt-find-my-model

    首先,非常感谢以上几位大牛分享的文章,由于文笔不好,对.NET 了解也不够,希望大家多多指点。

    理想情况下是希望能够像Orchard那样,可以运行时修改代码,又或者可以直接把插件(包含页面、样式、图片等资源文件)编译成一个DLL来使用(但是这样的做法会对前端与美工修改不便,而且就算改一个字也要重新编译一个DLL),只是依然还没找到方法ORZ。

    最终结构图如下。

    当把插件的站点发布出来后,目录名为插件名,并将该目录及目录下的所有文件复制到Plugins目录下即可自动安装并运行,不需要重启程序池。

    要实现这么一个架构,最初认为,只要使用 Assembly.LoadFile(name);方法来加载外部的程序集,并且使用反射创建控制器,在定义一下MVC的模板引擎的搜索路径不就可以了吗?

    当具体实现之后,发现,在不使用强类型的模型绑定时,可以正常使用,但是,使用了强类型的模型绑定时,则会出现以下错误。

    问题产生原因:

    .NET 会把.cshtml 与相关的程序集进行编译,之后访问的是编译后的临时程序集,但是,由于没有引用进入系统中,这里编译的时候没有该程序集,就会出现错误。

    那么,要解决这个问题,就需要在编译时,把需要的程序集,都一起编译了,但是,怎么样才可以实现?

    直接引用并使用类库的时候,系统会自行编译到一起了,所以解决办法有两种:

    1、在系统启动前的预编译时,手动把相关的程序集增加进系统中,这样就是一个实际存在于系统的程序集,在页面编译时自然会编译进去。

    在google查找相关的解决方法时,发现了该方法:

    BuildManager.AddReferencedAssembly(assembly);

    在查MSDN有这么一段话:此方法必须在 Global.asax 文件中的 Application_Start 事件发生前调用。

    也就意味着加载程序集的方法就必须要在预启动阶段就是加载了。

    并且使用上面的方法,来把程序集加到系统里。

    虽然这样可以正常使用了,但是,偶尔还是会有出现编译错误的异常。

    在调试阶段下,只有重新生成的代码时可以正常运行,重新生成之后的代码,在点启动调试时,就会出现编译错误问题,调试发现,在这个时候,系统并没有将需要的程序集加载到系统中,有大牛了解的话希望指点下原因。

    但是,在使用了Web.config 配置文件中的节点“probing”以后,把相关的程序集复制到“probing”指定的目录下,就能正常运行了。

    但是, 由于上面的那段代码只可以在预启动阶段使用,所有注定了该方法有个缺点,就是每个更新插件时,都要重启或者回收一次程序池,没能正常的做到插件化的灵活性。

    2、在模板(cshtml)进行编译前,把外部引用的相关的程序集增加到编译信息中,这样在对模板进行编译的同时,会把该程序集也编译进去。

     在谷歌娘的帮助下,找到了该事件:

    RazorBuildProvider.CodeGenerationStarted

    从名字可以看出,这是在编译启动时触发的事件,具体功能不明ORZ。

    可以通过该事件,把外部的程序集增加到 RazorBuildProvider 类中。

    provider.AssemblyBuilder.AddAssemblyReference(plugin.Assembly);

    provider 是 RazorBuildProvider 类的一个实例。
    plugin.Assembly 是一个页面所使用的程序集。
    只要把这段代码放到模板引擎的搜索视图的位置,即可根据需要,将增加外部的程序集。
    复制代码
            /// <summary>
            /// 给运行时编译的页面加了引用程序集。
            /// </summary>
            /// <param name="pluginName"></param>
            private void CodeGeneration(string pluginName)
            {
                RazorBuildProvider.CodeGenerationStarted += (object sender, EventArgs e) =>
                {
                    RazorBuildProvider provider = (RazorBuildProvider)sender;
    
                    var plugin = PluginManager.GetPlugin(pluginName);
    
                    if (plugin != null)
                    {
                        //var assemblies = AppDomain.CurrentDomain.GetAssemblies();
    
                        //foreach (var assembly in assemblies)
                        //{
                        //    provider.AssemblyBuilder.AddAssemblyReference(assembly);
                        //}
    
                        provider.AssemblyBuilder.AddAssemblyReference(plugin.Assembly);
                    }
                };
            }
    复制代码

    我不喜欢每装一个插件,都要重启一次,所以我选择使用了第二种方法。

    下一篇,将使用第二种方法来进行具体的实践并发布源码。

  • 相关阅读:
    browser-sync events.js:85 throw er; // Unhandled 'error' event
    js判断页面放大缩小
    uniapp小实例-新闻列表及详情
    uniapp 分享接口
    uniapp--第三方登录 小程序登录
    vue h5转换uni-app指南(vue转uni、h5转uni)
    uniapp详解及配置
    uniapp快速上手
    Vuex 的项目实例11 列表数据的按需切换
    Vuex 的项目实例10 底部按钮高亮切换
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3406327.html
Copyright © 2020-2023  润新知