BrnShop开源网上商城第三讲:插件的工作机制

这几天BrnShop的开发工作比较多,所以这一篇文章来的晚了一些,还请大家见谅呀!还有通知大家一下BrnShop1.0.312版本已经发布,此版本添加了报表统计等新功能,需要源码的园友可以点此下载。好了,我们现在进入今天的正题。关于BrnShop插件内容比较多,所以我分成两篇文章来讲解,今天先讲第一部分内容:插件的工作机制。

  对于任意一种插件机制来说,基本上只要解决以下三个方面的问题,这个插件机制就算成功了。这三个方面如下:

  • 插件程序集的加载
  • 视图文件的路径和编译
  • 插件的部署

  首先是插件程序集的加载(请仔细阅读,下面的坑比较多),最简单的方式就是直接将插件程序集复制到网站根目录下的bin文件夹(够简单吧!),但是我们不推荐使用这种方式,因为这种方式导致插件的程序集和视图文件等内容分布在不同目录,为以后的维护带来不便。我们期望的是插件的所有内容都在同一个目录中,以BrnShop的支付宝插件为例:

所有的插件文件都在“BrnShop.PayPlugin.Alipay”目录中,这样我们以后的删除,扩展等就方便多了。好了现在第一个坑来了,那就是如何让asp.net加载此目录下的程序集文件?我们可能会想到使用web.config文件中probing节点来配置asp.net运行时探测程序集的目录,但是很不幸它不管用(不信你可以试一下)。代码如下:

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

  既然自动加载不行,那我们就手动加载吧。手动加载需要使用一个方法:System.Web.Compilation.BuildManager.AddReferencedAssembly(Assembly assembly),此方法的的MSDN解释如下图:

通过调用这个方法可以手动加载指定的程序集(就是它的参数)到我们的程序中。在调用这个方法时有两个坑需要注意,第一个坑是这个方法必须在Application_Start 事件发生前调用,针对这个坑我们可以使用微软在.NET4.0中提供的PreApplicationStartMethodAttribute性质(此性质的具体介绍大家可以看这篇文章:http://haacked.com/archive/2010/05/16/three-hidden-extensibility-gems-in-asp-net-4.aspx/)来解决这个问题。代码如下:

[assembly: PreApplicationStartMethod(typeof(BrnShop.Core.BSPPlugin), "Load")]

第二个坑是CLR会锁定程序集文件,所以如果我们直接读取此文件会导致异常,解决这个坑的方式是复制它的一个副本,然后不读取原程序集,而是读取程序集的副本并传入AddReferencedAssembly方法中。具体代码如下:

            try
            {                //复制程序集
                File.Copy(dllFile.FullName, newDllFile.FullName, true);
            }
            catch
            {
                //在某些情况下会出现"正由另一进程使用,因此该进程无法访问该文件"错误,所以先重命名再复制
                File.Move(newDllFile.FullName, newDllFile.FullName + Guid.NewGuid().ToString("N") + ".locked");
                File.Copy(dllFile.FullName, newDllFile.FullName, true);
            }
            //加载程序集的副本到应用程序中
            Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(newDllFile.FullName));
            //将程序集添加到当前应用程序域
            BuildManager.AddReferencedAssembly(assembly);

不过这时又产生一个坑:此副本复制到哪个目录呢?我们期望这个副本能够保存下来,不必每次应用程序启动都要复制一次,熟悉asp.net编译的园友们估计都会想到,这个目录就是应用程序域的DynamicDirectory目录,一般情况下这个目录位于C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\15a300ab\6af0b19a类似的目录,截图如下:

不过这时又产生了一个坑(哎,步步有坑呀!):权限问题,就是只有在Full Trust级别下才有操作此目录的权限,而在Medium Trust级别下我们没有操作此目录的权限。信任级别的MSDN解释如下:

针对这个坑我们只能根据不同的级别复制到不同的目录,Full Trust级别时复制到DynamicDirectory目录,Medium Trust级别时复制到一个影子目录(/Plugins/bin)代码如下:

            DirectoryInfo copyFolder;
            //根据当前的信任级别设置复制目录
            if (WebHelper.GetTrustLevel() != AspNetHostingPermissionLevel.Unrestricted)//非完全信任级别
            {                //shadowFolder就是"/Plugins/bin"影子目录
                copyFolder = shadowFolder;
            }
            else//完全信任级别
            {
                copyFolder = new DirectoryInfo(AppDomain.CurrentDomain.DynamicDirectory);
            }

在跳过上面众多坑后,我们终于长舒一口气,来到胜利的彼岸:插件的程序集文件能够正确加载了。下面附上插件加载的完整代码:

 

   在解决了插件程序集的加载问题后我们再来解决视图文件的路径和编译问题,由于插件目录不在传统View文件夹中,所以我们像普通视图那样返回插件路径,我们需要使用根目录路径来返回视图文件路径,以支付宝插件为例:

        /// <summary>
        /// 配置
        /// </summary>
        [HttpGet]
        [ChildActionOnly]
        public ActionResult Config()
        {
            ConfigModel model = new ConfigModel();

            model.Partner = PluginUtils.GetPluginSet().Partner;
            model.Key = PluginUtils.GetPluginSet().Key;
            model.Seller = PluginUtils.GetPluginSet().Seller;
            model.AllowRecharge = PluginUtils.GetPluginSet().AllowRecharge;

            //插件视图文件路径必须以"~"开头
            return View("~/Plugins/BrnShop.PayPlugin.Alipay/Views/AdminAlipay/Config.cshtml", model);
        }

通过使用根目录路径,我们可以忽视一切路由匹配问题了。再来说说视图的编译问题,为了能够正确指导asp.net编译视图文件,我们需要在“/Plugins”文件夹(此文件夹中的web.cong能够覆盖所有插件目录)中添加一个web.config文件,并指定编译要求如下:

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Text" />
        <add namespace="System.Data" />
        <add namespace="System.Collections"/>
        <add namespace="System.Collections.Generic"/>
        <add namespace="BrnShop.Core" />
        <add namespace="BrnShop.Services" />
        <add namespace="BrnShop.Web.Framework" />
        <add namespace="BrnShop.Web.Models" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

这样我们的插件视图文件就能够正确编译了。

  现在只剩下插件的部署问题了。如果是手动部署我们只需要将插件目录及其文件复制到"/Plugins"目录中就可以。如果是使用vs自动部署我们需要做以下几步配置:

第一步配置插件程序集的输出路径,通过在项目上点击右键选择属性进入,具体配置如下:

现在你生成一下解决方案就会发现插件程序集已经到"/Plugins"文件夹中。

第二步是筛选程序集,就是只输出插件程序集,其它的程序集(包括系统自带和引用的程序集)不输出。具体配置如下如图:

最后一步是输出内容文件,例如视图文件,具体配置如下图:

到此BrnShop的插件能够正常工作了。

  PS:其实asp.net mvc插件的实现方式有许多种,大家可以google一下就会发现。而BrnShop之所以采用这种插件机制其实是服从于程序整体框架设计理念的。我们在设计BrnShop框架之初确定的框架设计理念是:在不损失框架的扩展性,稳定性和性能的条件下,一切从简,直接,一目了然,返璞归真。最后奉上本人的框架设计理念(如不喜,请轻喷!):

时间: 2024-10-05 23:44:13

BrnShop开源网上商城第三讲:插件的工作机制的相关文章

BrnShop开源网上商城第一讲:架构设计

首先在此感谢大家对BrnShop项目的支持和鼓励!我们在发布BrnShop以前曾推测项目会受到不少园友的支持,但没想到园友们的支持大大超过我们的预测.4天6000次浏览,140个推荐,170个评论,8000次下载.看到这些数据后我们内心除了激动外,更多了一份责任.无论将来遇到多大的困难,我们一定要坚持把BrnShop坚持到底!! 如果你还不知道BrnShop是什么或还没有下载源码的可以点此下载,如果下载源码后发现商城有bug,也可以点此下载(什么?你还是1.0.**版本?我们现在都已经更新到1.

BrnShop开源网上商城第四讲:自定义插件

重要通知:BrnShop企业版NOSQL设计(基于Redis)已经开源!源码内置于最新版的BrnShop中,感兴趣的园友可以去下载来看看.官网地址:www.brnshop.com. 好了现在进入今天的正题:自定义插件.上一讲中我们已经阐述了BrnShop插件的工作机制,现在我们详细介绍下如何自定义插件.首先BrnShop的插件从功能上分为三类,分别是: 开放授权插件(OAuth) 支付插件 配送插件 对应的接口文件(注:位于BrnShop.Core项目的Plugin/Base文件夹中)依次如下:

BrnShop开源网上商城第六讲:扩展视图功能

在正式讲解扩展视图功能以前,我们有必要把视图的工作原理简单说明下.任何一个视图都会被翻译成一个c#类,并保存到指定的位置,然后被编译.这也就是为什么能在视图中包含c#代码片段的原因.下面我们通过一个项目具体的了解一下这个过程,首先我们新建一个mvc3项目,它的Index.cshtml视图文件的代码如下: 1 2 3 4 5 6 7 8 @{     ViewBag.Title = "主页"; } <h2>@ViewBag.Message</h2> <p&g

BrnShop开源网上商城第五讲:自定义视图引擎

今天这篇博文主要讲解自定义视图引擎,大家都知道在asp.net mvc框架中默认自带一个Razor视图引擎,除此之外我们也可以自定义自己的视图引擎,只需要实现IViewEngine接口,接口定义如下: ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) ViewEngineResult FindPartialView(Co

BrnShop开源网上商城第二讲:ASP.NET MVC框架

在团队设计BrnShop的web项目之初,我们碰到了两个问题,第一个是数据的复用和传递,第二个是大mvc框架和小mvc框架的选择.下面我依次来说明下. 首先是数据的复用和传递:对于BrnShop的每一次请求,程序都要分成好几个阶段执行,例如验证,执行动作方法等等,在各个阶段我们可能需要重复使用同一信息,而我们的愿景就是希望此信息只需获取一次,然后沿着流程管道一直流动,这样在后面的阶段中就可以直接使用,不用再重新获取了,提高程序的性能.举例来说:在授权验证阶段,我们为对用户进行验证,从而获取了用户

Python 开源网上商城项目

django-oscar  https://github.com/django-oscar/django-oscar#screenshots django-shop  https://github.com/awesto/django-shop cakeshop  https://github.com/myoula/cakeshop satchmo  https://bitbucket.org/chris1610/satchmo/wiki/Home django-lfs https://githu

开源Asp.Net MVC网上商城BrnShop正式发布,提供源码下载(非官方文章)

BrnShop网上商城是以Asp.Net mvc3为基础开发的网上商城,源代码完全开源(企业版的源代码目前还没有完全整理完成,一旦整理完成也全部开源). 源码下载地址: asp.net(c#)开源商店系统Brn shop 1.9(免费仿京东商城) asp.net(c#)开源商店系统Brn shop 2.1(免费仿京东商城) 项目结构图如下: 后台管理页面: 功能简介: 1 基本数据:品牌,分类,属性(有些属性用作sku,有些属性还要提供商品筛选功能). 2 商品属性:商品图库,商品属性列表,商品

重磅来袭,开源Asp.Net MVC网上商城BrnShop正式发布,提供源码下载

BrnShop网上商城是以Asp.Net mvc3为基础开发的网上商城,源代码完全开源(企业版的源代码目前还没有完全整理完成,一旦整理完成也全部开源). 啥话也不说了,直接上源码:下载源码(由于公司服务器在香港,所以如果下载速度过慢可来此下载网盘) 项目结构图如下: 后台管理页面: 一个完整的网上商城应该至少包含以下几个方面: 1 基本数据:品牌,分类,属性(有些属性用作sku,有些属性还要提供商品筛选功能). 2 商品属性:商品图库,商品属性列表,商品关键词列表,商品库存(有的需要按照仓库拆分

开源Asp.Net MVC网上商城BrnShop正式发布,提供源码下载

BrnShop网上商城是以Asp.Net mvc3为基础开发的网上商城,源代码完全开源(企业版的源代码目前还没有完全整理完成,1旦整理完成也全部开源).         MVC3.0下载地址:        https://www.microsoft.com/zh-cn/download/confirmation.aspx?id=4211 源码下载地址: asp.net(c#)开源商店系统Brn shop 1.9(免费仿京东商城) asp.net(c#)开源商店系统Brn shop 2.1(免费