您的位置:首页 > 编程语言 > ASP

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

2013-11-04 19:35 507 查看
先回顾一下上篇决定的做法:

1、定义程序集搜索目录(临时目录)。

2、将要使用的各种程序集(插件)复制到该目录。

3、加载临时目录中的程序集。

4、定义模板引擎的搜索路径。

5、在模板引擎的查找页面方法里,给指定插件的页面加上相应的程序集。

6、检测插件目录,有改变就自动重新加载。

--------------------------------------------我是分割线--------------------------------------------

先创建一个空的MVC4项目。

namespace PluginMvc.Framework
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web.Hosting;

/// <summary>
/// 插件管理器。
/// </summary>
public static class PluginManager
{
/// <summary>
/// 插件字典。
/// </summary>
private readonly static IDictionary<string, PluginDescriptor> _plugins = new Dictionary<string, PluginDescriptor>();

/// <summary>
/// 初始化。
/// </summary>
public static void Initialize()
{
//遍历所有插件描述。
foreach (var plugin in PluginLoader.Load())
{
//卸载插件。
Unload(plugin);
//初始化插件。
Initialize(plugin);
}
}

/// <summary>
/// 初始化插件。
/// </summary>
/// <param name="pluginDescriptor">插件描述</param>
private static void Initialize(PluginDescriptor pluginDescriptor)
{
//使用插件名称做为字典 KEY。
string key = pluginDescriptor.Plugin.Name;

//不存在时才进行初始化。
if (!_plugins.ContainsKey(key))
{
//初始化。
pluginDescriptor.Plugin.Initialize();

//增加到字典。
_plugins.Add(key, pluginDescriptor);
}
}

/// <summary>
/// 卸载。
/// </summary>
public static void Unload()
{
//卸载所有插件。
foreach (var plugin in PluginLoader.Load())
{
plugin.Plugin.Unload();
}

//清空插件字典中的所有信息。
_plugins.Clear();
}

/// <summary>
/// 卸载。
/// </summary>
public static void Unload(PluginDescriptor pluginDescriptor)
{
pluginDescriptor.Plugin.Unload();

_plugins.Remove(pluginDescriptor.Plugin.ToString());
}

/// <summary>
/// 获得当前系统所有插件描述。
/// </summary>
/// <returns></returns>
public static IEnumerable<PluginDescriptor> GetPlugins()
{
return _plugins.Select(m => m.Value).ToList();
}

/// <summary>
/// 根据插件名称获得插件描述。
/// </summary>
/// <param name="name">插件名称。</param>
/// <returns>插件描述。</returns>
public static PluginDescriptor GetPlugin(string name)
{
return GetPlugins().SingleOrDefault(plugin => plugin.Plugin.Name == name);
}
}
}


View Code

创建一个插件控制器工厂,来获得插件程序集中的控制器类型。



对 RazorViewEngine 的 FindPartialView 方法与 FindView 方法,根据插件来把该插件相关的程序集增加到 Razor 模板的编译项里。



关键代码:

/// <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)
{
provider.AssemblyBuilder.AddAssemblyReference(plugin.Assembly);
}
};
}


到现在,该方法已经初步完成,现在就是把整个插件丢到插件目录下,重启就能加载了!

现在,就给它加上自动检测功能,FileSystemWatcher 类,设置当程序集发生修改、创建、删除和重命名时,自动重新加载插件。

namespace PluginMvc.Framework
{
using System.IO;
using System.Web.Hosting;

/// <summary>
/// 插件检测器。
/// </summary>
public static class PluginWatcher
{
/// <summary>
/// 是否启用。
/// </summary>
private static bool _enable = false;

/// <summary>
/// 侦听文件系统。
/// </summary>
private static readonly FileSystemWatcher _fileSystemWatcher = new FileSystemWatcher();

static PluginWatcher()
{
_fileSystemWatcher.Path = HostingEnvironment.MapPath("~/Plugins");
_fileSystemWatcher.Filter = "*.dll";

_fileSystemWatcher.Changed += _fileSystemWatcher_Changed;
_fileSystemWatcher.Created += _fileSystemWatcher_Created;
_fileSystemWatcher.Deleted += _fileSystemWatcher_Deleted;
_fileSystemWatcher.Renamed += _fileSystemWatcher_Renamed;

_fileSystemWatcher.IncludeSubdirectories = true;

Enable = false;
}

/// <summary>
/// 是否启用。
/// </summary>
public static bool Enable
{
get
{
return _enable;
}
set
{
_enable = value;

_fileSystemWatcher.EnableRaisingEvents = _enable;
}
}

/// <summary>
/// 启动。
/// </summary>
public static void Start()
{
Enable = true;
}

/// <summary>
/// 停止。
/// </summary>
public static void Stop()
{
Enable = false;
}

private static void _fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
ResetPlugin();
}

private static void _fileSystemWatcher_Deleted(object sender, FileSystemEventArgs e)
{
ResetPlugin();
}

private static void _fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
ResetPlugin();
}

private static void _fileSystemWatcher_Renamed(object sender, RenamedEventArgs e)
{
ResetPlugin();
}

/// <summary>
/// 重置插件。
/// </summary>
private static void ResetPlugin()
{
PluginManager.Unload();
PluginManager.Initialize();
}
}
}


把该方法进行注册:



又或者可以使用 System.Web.PreApplicationStartMethod 方法来启动(推荐)。

[assembly: System.Web.PreApplicationStartMethod(typeof(PluginMvc.Framework.Bootstrapper), "Initialize")]
namespace PluginMvc.Framework
{
using System.Web.Mvc;

using PluginMvc.Framework;
using PluginMvc.Framework.Mvc;

/// <summary>
/// 引导程序。
/// </summary>
public static class Bootstrapper
{
/// <summary>
/// 初始化。
/// </summary>
public static void Initialize()
{
//注册插件控制器工厂。
ControllerBuilder.Current.SetControllerFactory(new PluginControllerFactory());

//注册插件模板引擎。
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new PluginRazorViewEngine());

//初始化插件。
PluginManager.Initialize();

//启动插件检测器。
PluginWatcher.Start();
}
}
}


到这里,框架部分已经完成了!下面说下插件的开发。

1、创建一个空的 ASP.NET MVC 4 项目,并清理好。



2、定义一个实现 IPlugin 接口的类。



3、完成一个简单的页面显示功能。



将该插件站点发布。



将已发布的插件包含目录一起复制到站点的插件目录下即可。



完成了,现在不但可以把插件复制到插件目录就马上能使用,要调试什么的,也可以直接启动插件 WEB 项目了,具体的完善就不多说了!

不过,目前还有个小BUG,如果目录下没有任何插件的时候,插件检测将不会启动><。

注意!Views目录下必须要存在 Web.Config 文件,.NET 会根据该文件自动配置 cshtml 页面的基类等信息,假如没有该文件,编译页面时,会出现找不到基类错误。

源码:

点击下载

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

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: