zoukankan      html  css  js  c++  java
  • 说说项目中的插件思想

    目前项目的架构基本趋势都是易扩展,易扩展主要的实现方式就是插件,在项目中所有的扩展模块都看作为是一个插件,那最为主要的就是插件与母体如何结合起来的,接下来就来讨论一下,我对于插件项目的理解和实现。同时由于本人能力有限,问题会很多,请大家批评指正。

      我认为插件就是就是一个单独的项目,到最后整合到一个母项目中去。后台的逻辑代码根本就不用分开,用命名空间分开即可,只要在UI上面做做到分开行了,当然有些要求比较高的,就是从UI到逻辑都是分开来写的,但是我这里觉得不用,读者可以根据自己的要求来做。

      直入主题,先说一下我写的例子的主体结构,直接把解决方案的截图拿上来,看看如何分层的。

                                     

      由于本人比较热衷于DDD的学习,所以就用DDD的思想实现了这个例子,对于DDD我就不去讲解了,可以翻看具体的文章。其中主要的是03Plugins这个里面放置的就是所有的插件的UI,逻辑代码我都是放到了05Applaction中去了。

      下面我来讲一下,如何使插件用到主项目中去,也就是所谓的“站点合并”。UI层我运用的是MVC,所以合并的关键就是路由的合并,插件的路由如何进入到主项目中去。

      在06Foundation中的Framework中,我实现了这样的方法。

                             

      下面以博客插件为例子讲解一下:

    其中IPlugin.cs

    复制代码
    复制代码
    // 作者:                    不要理我 CJ
    // 邮件:               869722304@qq.com(仅仅支持商业合作洽谈)
    // 创建时间:                2012-08-8
    // 最后修改时间:            2012-08-11
    // 
    // 未经修改的文件版权属于原作者所有,但是你可以阅读,修改,调试。本项目不建议商用,不能确保稳定性。
    // 同时由于项目引起的一切问题,原作者概不负责。
    //
    // 本项目所引用的所有类库,仍然遵循其原本的协议,不得侵害其版权
    //
    // 您一旦下载就视为您已经阅读此声明。
    //
    // 您不可以移除项目中所有的声明。
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.Routing;
    
    namespace CJCMS.Framework.Plugin
    {
        public interface IPlugin
        {
            /// <summary>
            /// 插件名
            /// </summary>
            string PluginName { get; set; }
            
            /// <summary>
            /// 插件描述
            /// </summary>
            string Describtion { get; set; }
            
            /// <summary>
            /// 插件路由
            /// </summary>
            List<Route> routes { get; set; }
        }
    }
    复制代码
    复制代码

    插件管理类:

    复制代码
    复制代码
    // 作者:                    不要理我 CJ
    // 邮件:               869722304@qq.com(仅仅支持商业合作洽谈)
    // 创建时间:                2012-08-8
    // 最后修改时间:            2012-08-11
    // 
    // 未经修改的文件版权属于原作者所有,但是你可以阅读,修改,调试。本项目不建议在商用,不能确保稳定性。
    // 同时由于项目引起的一切问题,原作者概不负责。
    //
    // 本项目所引用的所有类库,仍然遵循其原本的协议,不得侵害其版权
    //
    // 您一旦下载就视为您已经阅读此声明。
    //
    // 您不可以移除项目中所有的声明。
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using CJCMS.Framework.Routes;
    
    namespace CJCMS.Framework.Plugin
    {
        public class PluginsManger:IPluginsManger
        {
            /// <summary>
            /// 安装插件
            /// </summary>
            /// <param name="plugin"></param>
            /// <returns></returns>
            public bool InstallPlugin(IPlugin plugin)
            {
                try
                {
                    ///注册路由
                    RoutesRegister re = new RoutesRegister();
                    re.RegisterRoute(plugin.routes);
    
                    ///记录插件表
                    ///
                    return true;
                }
                catch
                {
                    return false;
                }
    
            }
    
            /// <summary>
            /// 卸载插件
            /// </summary>
            /// <param name="plugin"></param>
            /// <returns></returns>
            public bool UnInstallPlugin(IPlugin plugin)
            {
                try
                {
                    ///卸载路由
                    RoutesRegister re = new RoutesRegister();
                    re.DeleteRoute(plugin.routes);
    
                    ///记录插件表
                    ///
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }
    }
    复制代码
    复制代码

    BlogPlugin

    复制代码
    复制代码
    // 作者:                    不要理我 CJ
    // 邮件:               869722304@qq.com(仅仅支持商业合作洽谈)
    // 创建时间:                2012-08-8
    // 最后修改时间:            2012-08-11
    // 
    // 未经修改的文件版权属于原作者所有,但是你可以阅读,修改,调试。本项目不建议在商用,不能确保稳定性。
    // 同时由于项目引起的一切问题,原作者概不负责。
    //
    // 本项目所引用的所有类库,仍然遵循其原本的协议,不得侵害其版权
    //
    // 您一旦下载就视为您已经阅读此声明。
    //
    // 您不可以移除项目中所有的声明。
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using CJCMS.Framework.Plugin;
    using System.Web.Routing;
    using System.Web.Mvc;
    
    namespace CJCMS.Plugin.Blog
    {
        public class BlogPlugin :IPlugin
        {
            public List<Route> routes { get; set; }
    
            /// <summary>
            /// 插件名
            /// </summary>
            public string PluginName { get; set; }
    
            /// <summary>
            /// 插件描述
            /// </summary>
            public string Describtion { get; set; }
    
            public BlogPlugin()
            {
                routes = new List<Route>();
                /*
                 * 路由例子
                routes.Add(new Route(
                        "User/Login", 
                        new RouteValueDictionary(new { controller = "User", action = "Login" }), 
                        new System.Web.Mvc.MvcRouteHandler()));
                 */
                routes.Add(new Route(
                        "{controller}/{action}/{id}/{k}",
                        
                        new System.Web.Mvc.MvcRouteHandler()));
            }
        }
    }
    复制代码
    复制代码

    这样在主项目中加载插件的时候就可以调用了。

    复制代码
    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using CJCMS.Framework.Plugin;
    using CJCMS.Plugin.Blog;
    using CJCMS.Core;
    
    namespace CJCMS.Web
    {
        // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
        // 请访问 http://go.microsoft.com/?LinkId=9394801
    
        public class MvcApplication : System.Web.HttpApplication
        {
            
    
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
                routes.MapRoute(
                    "Default", // 路由名称
                    "{controller}/{action}/{id}", // 带有参数的 URL
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值
                );
                /*
                 * 
                 * 注册插件例子,这里应该注册安装时已经选中的插件,当然在项目已经运行的时候开启插件,也是这样子注册
                 * 
                IPluginsManger ipm = new PluginsManger();
                IPlugin blogplugin = new BlogPlugin();
                ipm.InstallPlugin(blogplugin);
                 */
                IPluginsManger ipm = new PluginsManger();
                IPlugin blogplugin = new BlogPlugin();
                ipm.InstallPlugin(blogplugin);
    
                //AutofacRepositity auto = new AutofacRepositity(builder);
                //auto.RegisterRepositity();
            }
    
            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
    
                RegisterRoutes(RouteTable.Routes);
            }
        }
    }
    复制代码
    复制代码

    最后要记得把插件UI复制到主项目中去,添加编译后指令

    xcopy /s /y "$(ProjectDir)bin\*" "$(SolutionDir)CJCMS.Web\bin\"
    xcopy /s /y "$(ProjectDir)Content\*" "$(SolutionDir)CJCMS.Web\Content"
    xcopy /s /y "$(ProjectDir)Scripts\*" "$(SolutionDir)CJCMS.Web\Scripts"
    xcopy /s /y /i "$(ProjectDir)Views\*" "$(SolutionDir)CJCMS.Web\Views\Blog"

     也许这段代码

    xcopy /s /y /i "$(ProjectDir)Views\*" "$(SolutionDir)CJCMS.Web\Views\Blog"

     你能看出些端倪,不错,下一讲就是主讲这句话,先卖个关子。

    未完待续,希望大牛给予指导和好的建议。

    Just waiting. Go on  coding.

    上面一讲我留下一个疑问,那就是一句编译后指令,有一些MVC基础的人,应该能够看出端倪,要是你没有看懂,那就认真的听我道来吧。

      

    1 xcopy /s /y "$(ProjectDir)bin\*" "$(SolutionDir)CJCMS.Web\bin\"
    2 xcopy /s /y "$(ProjectDir)Content\*" "$(SolutionDir)CJCMS.Web\Content"
    3 xcopy /s /y "$(ProjectDir)Scripts\*" "$(SolutionDir)CJCMS.Web\Scripts"
    4 xcopy /s /y /i "$(ProjectDir)Views\*" "$(SolutionDir)CJCMS.Web\Views\Blog"

      第四行中那句代码,我解释一下,怕大家对于xcopy不大理解,这句主要就是在编译之后把,项目的Views目录的文件复制到解决方案文件

    CJCMS.Web\Views\Blog下,谁是CJCMS.Web,CJCMS.Web就是主项目,也就是把插件的Views都拷贝到CJCMS.Web下的Views/Blog去了,但是大家看一下,要是这样的话,主项目的目录结构成什么样子了。

     
    
    

      主项目的Views目录有三层,而不是两个层次,这样子如何访问到Views/Blog/Blog/Home.aspx呢,插件中的Controller结构你看一下是正常的目录,那我们遇到了一个问题,就是如何使得MVC支持多层目录。

      我在Framework中写了这么一个类,继承一下MVC的ActionFilterAttribute,来拦截到请求,然后跳转到你想要跑去的多层目录去,Folder变量就是Views多层目录中你多出来的目录,多出来就是原本MVC是两层目录,而现在变成了多层目录,在浏览器中输入localhost/Blog/Home,如何能够访问到我上面例子的三层目录呢,我其实多了一层目录Blog/,那你就可以在Controller中添加属性了。

    复制代码
    // 作者:                    不要理我 CJ 
    // 邮件:               869722304@qq.com(仅仅支持商业合作洽谈)
    // 创建时间:                2012-08-8
    // 最后修改时间:            2012-08-11
    // 
    // 未经修改的文件版权属于原作者所有,但是你可以阅读,修改,调试.本项目不建议商用,不能确保稳定性
    // 同时由于项目引起的一切问题,原作者概不负责。
    //
    // 本项目所引用的所有类库,仍然遵循其原本的协议,不得侵害其版权
    //
    // 您一旦下载就视为您已经阅读此声明。
    //
    // 您不可以移除项目中所有的声明。
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.Mvc;
    
    namespace CJCMS.Framework.Routes
    {
        public class CustomRouting : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                string value = "/"+filterContext.RouteData.Values["action"].ToString() + ".aspx";
                filterContext.RouteData.Values["action"] = Folder + value;
                base.OnActionExecuting(filterContext);
            }
    
            public CustomRouting(string folder)
            { this.Folder = folder; }
    
            public string Folder { get; set; }
        }
    }
    复制代码
      具体插件中的Controller怎么用这个呢?
    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.Mvc;
     6 using CJCMS.Framework.Routes;
     7 using CJCMS.Contracts.DTO;
     8 //using CJCMS.Plugin.Blog.BlogServiceReference;
     9 using CJCMS.Plugin.Blog.BlogS;
    10 using CJCMS.Contracts.DTO.Blog;
    11 using System.Threading;
    12 
    13 
    14 namespace CJCMS.Plugin.Blog.Controllers
    15 {
    16     [HandleError]
    17     [CustomRouting("~/Views/Blog/Blog")]
    18     public class BlogController : Controller
    19     {
    20        
    21         public ActionResult Home()
    22         {
    23             ViewData["Message"] = "欢迎使用 ASP.NET MVC!";
    24 
    25 
    26             BlogServiceClient service = new BlogServiceClient();
    27 
    28             try
    29             {
    30                 BlogDspModel b = new BlogDspModel();
    31                 b.Title = Guid.NewGuid().ToString();
    32                 b.Body = "123";
    33                 b.Created = DateTime.Now;
    34                 b.Id = Guid.NewGuid().ToString();
    35                 service.Add(b);
    36             }
    37             catch (Exception ee)
    38             {
    39                 ViewData["Message"] += ee.Message;
    40             }
    41 
    42             IList<BlogDspModel> il = service.Fetch();
    43             service.Close();
    44             return View();
    45         }
    46 
    47        
    48 
    49         [HttpGet]
    50         public ActionResult Home(string id,string k)
    51         {
    52             ViewData["Message"] = "欢迎使用 ASP.NET MVC!";
    53             BlogServiceClient service = new BlogServiceClient();
    54             try
    55             {
    56                 BlogDspModel b = new BlogDspModel();
    57                 b.Title = Guid.NewGuid().ToString();
    58                 b.Body = "123";
    59                 b.Created = DateTime.Now;
    60                 b.Id = Guid.NewGuid().ToString();
    61                 service.Add(b);
    62             }
    63             catch (Exception ee)
    64             {
    65                 ViewData["Message"] += ee.Message;
    66             }
    67             IList<BlogDspModel> il = service.Fetch();
    68             service.Close();
    69             return View();
    70         }
    71 
    72         public ActionResult About()
    73         {
    74             return View();
    75         }
    76     }
    77 }
    复制代码

      第17行你已经看到了,怎么去处理,使得MVC支持多层目录,好啦这一讲也结束了。

      下面,我会开始讲讲我写得例子的整体的架构,也就是开始讲DDD了,我的项目设计了,你准备好了吗?

      这个项目,主要使用的技术:ORM(NHibernate),MVC,WCF,DTO-DO Mapping,DDD设计理念,单例模式等等。

      希望你能够期待,要是大家感兴趣,我会选择开源,给大家看看,共同学习。

      Just waiting. Go on  coding.

     
     
    标签: DDD插件架构设计
  • 相关阅读:
    Jmeter -- HTTP Request Defaults
    Jmeter -- 属性和变量
    Jmeter -- 逻辑控制器(Logic Controller)
    Jmeter报告优化之New XSL stylesheet
    Jmeter调试工具---HTTP Mirror Server
    Jmeter ----Bean shell使用
    转jmeter --JDBC请求
    Memcached 教程
    基于ZooKeeper的分布式Session实现
    Kafka配置说明
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2635517.html
Copyright © 2011-2022 走看看