• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

转发-基于ASP.NET MVC 4/5 Razor的模块化/插件式架构实现 基 ...

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
 

概述

  在日常开发中, 我们经常谈起模块化/插件化架构,这样可既可以提高开效率,又可以实现良好的扩展性,尤其对于产品化的系统有更好的实用性。

架构

  我们采用的是MVC5(本文中介绍的方法对于MVC4也是适用的),如下图,解决方案中有四个项目,其中 WeDiscuss 为前端,WeDiscuss.Plugin.Framework 为插件公共类库  WeDiscuss.Plugin.Album 为插件(相册) WeDiscuss.Plugin.News 为插件(新闻),本文只是讲解决插件的实现方式,就不多做其它如果业务逻辑、数据访问层等

  注;每个插件都有自已的(M、V、C),内部实现和常用MVC没有区别,这样可以方便的开发,没有其它新知识的引入。

  

  其中,插件层可以在主项目中引用,也可以不引用,或是放到其它目录下(如把插件DLL单独放到“Plugins”目录中),如果不引用就采用在编译完成时复制

  下面讲解编译完成复制方法,如想复制到“Plugins”目录中请修改BIN为“Plugins”:

  在如下图加入:

copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)Wediscuss\Bin\"

如何让ASP.NET加载BIN目录之外的路径的Assembly

  我们把各个模块编译出来的assembly和各个模块的配置文件自动放到一个bin平级的plugin目录,然后web应用启动的时候自动扫描这个plugin目录并加载各个模块plugin,这个怎么做到的?大家也许知道,ASP.NET只允许读取Bin目录下的assbmely,不可以读取其他路径,包括Bin\abc等,即使在web.config这样配置probing也不行:(不信你可以试一下)

 

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

如何注入菜单

  插件能用了,但也想动态注入菜单,这样才实现了自动化,要不还是人工进行菜单注入永远是半自动化,这和我们开发的思想是不想符的,下面就来说一下菜单的注入

  1、首称在WeDiscuss.Plugin.Framework 为插件公共类库中建实体类PluginMenu 和PluginMenus

/*
 * -------------------------------------------------------------------------------
 * 功能描述:
 * 
 * 创建人:     JunHan(俊涵)
 * 创建日期:    2013/12/15 21:59:16
 * 创建说明:    
 * 
 * 修改人:     
 * 修改日期:    
 * 修改说明:    
 *    
 * -------------------------------------------------------------------------------
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace WeDiscuss.Plugin.Framework
{
    public class PluginMenus
    {
        public List<PluginMenu> MenuList { get; set; }

        public string CssClass { get; set; }

        public int MenuType { get; set; }

        public string Html
        {
            get
            {
                StringBuilder stringBuilder = new StringBuilder();
                foreach (var menu in MenuList)
                {
                    TagBuilder tagBuilder = new TagBuilder("a");
                    tagBuilder.MergeAttribute("href", menu.MenuUrl);
                    tagBuilder.InnerHtml = menu.MenuText;
                    tagBuilder.MergeAttribute("class", CssClass);
                    stringBuilder.Append(tagBuilder.ToString(TagRenderMode.Normal) + "\r\n");
                }
                return stringBuilder.ToString();
            }
        }

        public List<PluginMenu> AvailableList
        {
            get
            {
                if (MenuList == null)
                {
                    return new List<PluginMenu>();
                }
                if (MenuType == 0)
                {
                    return MenuList;
                }
                if (!MenuList.Any(o => o.MenuType == MenuType))
                {
                    return new List<PluginMenu>();
                }
                return MenuList.Where(o => o.MenuType == MenuType).ToList();
            }
        }
    }

    public class PluginMenu
    {
        public string MenuText { get; set; }
        public string MenuUrl { get; set; }

        public int MenuType { get; set; }

        public int MenuOrder { get; set; }

        public bool Visible { get; set; }
    }
}

  这样我们就实现了菜单的结构,接下来就是采单的生成或注入方法:

  新建 AppPlugin 和 PluginApplication来实现菜单的初使化方法,并将生成好的菜单存放在静态变量中。

/*
 * -------------------------------------------------------------------------------
 * 功能描述:
 * 
 * 创建人:     JunHan(俊涵)
 * 创建日期:    2013/12/15 23:29:58
 * 创建说明:    
 * 
 * 修改人:     
 * 修改日期:    
 * 修改说明:    
 *    
 * -------------------------------------------------------------------------------
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WeDiscuss.Plugin.Framework
{
    public class PluginApplication : BaseMvcPluginApplication
    {
        #region Plugin Menu Support
        public static PluginMenus PluginMenus = new PluginMenus();
        public void RegisterMenuItem(PluginMenu menu)
        {
            lock (PluginMenus)
            {
                if (PluginMenus.MenuList == null) PluginMenus.MenuList = new List<PluginMenu>();
                PluginMenus.MenuList.Add(new PluginMenu() { MenuText = menu.MenuText, MenuUrl = menu.MenuUrl, MenuType = menu.MenuType, MenuOrder = menu.MenuOrder });
                PluginMenus.MenuList = PluginMenus.MenuList.OrderBy(o => o.MenuOrder).ToList();
            }
        }
        #endregion

        public static new PluginApplication Instance
        {
            get { return BaseMvcPluginApplication.Instance as PluginApplication; }
            set { BaseMvcPluginApplication.Instance = value; }
        }


        protected override bool ShouldIncludeResourceCore(BaseMvcPluginApplication.ResourceTypes type, IMvcPlugin plugin)
        {
            return ShouldIncludeResource(plugin, null);
        }

        protected virtual bool ShouldIncludeResource(IMvcPlugin plugin, object resource)
        {
            bool should = true;
            if (plugin != null)
            {
                if ((should = plugin.Enabled) && plugin is AppPlugin)
                    should = ((AppPlugin)plugin).ShouldIncludeResource(resource);
            }

            return should;
        }

        protected override void AddAdditionalRazorViewLocationsCore(List<string> lst)
        {
            lst.Add("~/Plugins/PluginDemo/Views.{1}.{0}.cshtml");
        }


        public static PluginApplication SetupApplication(object bundles, object routes)
        {
            PluginApplication me = new PluginApplication(bundles, routes);
            return me;
        }

        protected PluginApplication(object bundles, object routes)
            : base(bundles, routes)
        {
        }
    }

    public class AppPlugin : BaseMvcPlugin
    {
        public PluginApplication _App { get { return (PluginApplication)App; } }

        public AppPlugin(bool ensureStandardViewLocation = true)
            : base(ensureStandardViewLocation)
        {
        }

        public void DefineMenuItem(PluginMenu item)
        {
            _App.RegisterMenuItem(item);
        }

        public virtual bool ShouldIncludeResource(object content)
        {
            return true;
        }
    }
}

  2、菜单初使化

  在每个插件项目中新建一类,并继承AppPlugin,重写方法:SetupExtensions 调用DefineMenuItem 实现菜单初使化,在菜单的结果中我们看到有MenuType类型,这里我们自定义,一般会用枚举来实现,可以定义为前台或后台等,一个插件可以拥有多个菜单,可以注入多个地方

  

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WeDiscuss.Plugin.Framework;

namespace WeDiscuss.Plugin.Album
{
    [Export(typeof(IMvcPlugin))]
    [MvcPluginMetadata("AlbumPlugin", null, "Demo App Site Album", ""

 
                    
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
演练:在 ASP.NET 中缓存应用程序数据发布时间:2022-07-10
下一篇:
asp.netWeb.Config使用发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap