说说项目中的插件思想
目前项目的架构基本趋势都是易扩展,易扩展主要的实现方式就是插件,在项目中所有的扩展模块都看作为是一个插件,那最为主要的就是插件与母体如何结合起来的,接下来就来讨论一下,我对于插件项目的理解和实现。同时由于本人能力有限,问题会很多,请大家批评指正。
我认为插件就是就是一个单独的项目,到最后整合到一个母项目中去。后台的逻辑代码根本就不用分开,用命名空间分开即可,只要在UI上面做做到分开行了,当然有些要求比较高的,就是从UI到逻辑都是分开来写的,但是我这里觉得不用,读者可以根据自己的要求来做。
直入主题,先说一下我写的例子的主体结构,直接把解决方案的截图拿上来,看看如何分层的。
由于本人比较热衷于DDD的学习,所以就用DDD的思想实现了这个例子,对于DDD我就不去讲解了,可以翻看具体的文章。其中主要的是03Plugins这个里面放置的就是所有的插件的UI,逻辑代码我都是放到了05Applaction中去了。
下面我来讲一下,如何使插件用到主项目中去,也就是所谓的“站点合并”。UI层我运用的是MVC,所以合并的关键就是路由的合并,插件的路由如何进入到主项目中去。
在06Foundation中的Framework中,我实现了这样的方法。
下面以博客插件为例子讲解一下:
其中IPlugin.cs
// 作者: 不要理我 CJ
// 邮件: 869722304@qq测试数据(仅仅支持商业合作洽谈)
// 创建时间: 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测试数据(仅仅支持商业合作洽谈)
// 创建时间: 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测试数据(仅仅支持商业合作洽谈)
// 创建时间: 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测试数据/?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测试数据(仅仅支持商业合作洽谈)
// 创建时间: 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 , 插件 , 架构设计
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息