一直以来都想把控制器的代码部署到单独的程序集里。昨天研究Asp.Net MVC的源代码,偶然发现有一个奇特的类“ControllerBuilder”,MSDN上的介绍相当简略,就一句话“表示一个类,该类负责动态生成控制器。”。小试了一把,竟然成功了!原来Asp.Net MVC程序的Controllers不是只能定义在程序根目录的Controllers文件夹下面的。

  要实现控制器单独部署的重点在于“ControllerBuilder”的“SetControllerFactory”方法,该方法的一个重载要求一个类型为“IControllerFactory”的参数。所以,实现“IControllerFactory”是前提。

  “IControllerFactory”,顾名思义,就是控制器工厂类要继承的接口。如果实现了该接口,就表示我们可以按自已的方法来替换MVC框架中搜索控制器的操作。该接口要求实现三个方法,它们是“CreateController、GetControllerSessionBehavior、ReleaseController”。

  1、实现“CreateController”:这个方法很容易理解,它返回“IController”接口。因为“ControllerBase”实现了该接口,当然我们定义的所有控制器类型也必然实现了这个接口。所以只要返回控制器的实例就可以了。方法传入“RequestContext requestContext,  string controllerName” 两个参数,这就需要先根据controllerName生成一个没有请求上下文对象的空的控制器,再为这个控制器指定“ControllerContext”,然后返回这个控制器实例就搞定了。

  2、实现“GetControllerSessionBehavior”:这个方法比较难懂,它的返回值类型“SessionStateBehavior”是一个枚举类型,表示的是请求对会话状态的支持类型。这个东西从哪儿得到呢?方法传入的参数还是“RequestContext requestContext, string controllerName”这两个,可见,这个返回的值还是得从实际执行请求的那个控制器那里得到。这时候我想到都可以对控制器使用“SessionState”标记类,它正好是“Behavior”属性,就它了。获取到“controllerName”对应的控制器类型中定义的“SessionState”属性的实例,返回它的“Behavior”就OK了;当然,有可能没有给控制器加那个标记,那就要返回“SessionStateBehavior.Default”了。

  3、实现“ReleaseController”:这个太容易了,判断一下传入的参数有没有实现“IDisposable”,如果有,就调用它的“Dispose()”方法就行了。

  上面说那么多,上点实际的东西,来看看我的代码是怎么写的。

    /// <summary>
/// 控制器工厂类
/// </summary>
public class ControllerFactory : IControllerFactory
{
readonly string _AssemblyName;
/// <summary>
/// 获取控制器所在的程序集名称
/// </summary>
public string AssemblyName
{
get { return _AssemblyName; }
} readonly string _DefaultNameSpace;
/// <summary>
/// 获取控制器的默认名称空间
/// </summary>
public string DefaultNameSpace
{
get { return _DefaultNameSpace; }
} Assembly _ControllerAssembly;
/// <summary>
/// 获取控制器所在的程序集的Assembly实例
/// </summary>
Assembly ControllerAssembly
{
get
{
if (_ControllerAssembly == null)
{
_ControllerAssembly = Assembly.Load(AssemblyName);
}
return _ControllerAssembly;
}
} public ControllerFactory(string assemblyName)
{
_AssemblyName = assemblyName;
} public ControllerFactory(string assemblyName, string defaultNameSpace)
{
_AssemblyName = assemblyName;
_DefaultNameSpace = defaultNameSpace;
} /// <summary>
/// 获取控制器类的全名
/// </summary>
/// <param name="controllerName"></param>
/// <returns></returns>
string GetControllerFullName(string controllerName)
{
return string.Format(
"{0}.{1}Controller", string.IsNullOrEmpty(DefaultNameSpace) ? AssemblyName : DefaultNameSpace, controllerName);
} public IController CreateController(RequestContext requestContext, string controllerName)
{
var controller =
ControllerAssembly.CreateInstance(GetControllerFullName(controllerName)) as Controller;
if (controller != null)
{
if (controller.ControllerContext == null)
{
controller.ControllerContext = new ControllerContext(requestContext, controller);
}
else
{
controller.ControllerContext.RequestContext = requestContext;
}
return controller as IController;
}
return null;
} public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
{
var controllerType = ControllerAssembly.GetType(GetControllerFullName(controllerName), true, true);
var sessionStateAttr =
Attribute.GetCustomAttribute(controllerType ,typeof(SessionStateAttribute), false) as SessionStateAttribute;
return sessionStateAttr == null ? SessionStateBehavior.Default : sessionStateAttr.Behavior;
} public void ReleaseController(IController controller)
{
IDisposable disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}

  现在有了“IControllerFactory”,需要在注册路由规则前利用“ControllerBuilder”指定使用刚才自定义的工厂类作为创建当前MVC应用程序的工厂类。在Global.asax的“RegisterRoutes()”方法里面的第一句前加上这样一句:“ControllerBuilder.Current.SetControllerFactory(new ControllerFactory("APP.Controlers"));”,这样就行了,“APP.Controlers”是一个独立程序集的名称,因为我是通过返回来获取Controller的实例,必须要知道控制器在哪个和程序集里。当然,总是有更好的方法的。

  F5运行,你会发现MVC不会再从你Controllers目录下面找控制器了……

将Asp.Net MVC应用程序的控制器定义在单独的程序集(类库)中的更多相关文章

  1. 04 入门 - ASP.NET MVC应用程序的结构

    目录索引:<ASP.NET MVC 5 高级编程>学习笔记 用Visual Studio创建了一个新的ASP.NET MVC应用程序后,将自动向这个项目中添加一些文件和目录. 如图所示: ...

  2. 使用Metrics.NET 构建 ASP.NET MVC 应用程序的性能指标

    通常我们需要监测ASP.NET MVC 或 Web API 的应用程序的性能时,通常采用的是自定义性能计数器,性能计数器会引发无休止的运维问题(损坏的计数器.权限问题等).这篇文章向你介绍一个新的替代 ...

  3. 学习ASP.NET MVC(一)——我的第一个ASP.NET MVC应用程序

    学习ASP.NET MVC系列: 学习ASP.NET MVC(一)——我的第一个ASP.NET MVC应用程序 学习ASP.NET MVC(二)——我的第一个ASP.NET MVC 控制器 学习ASP ...

  4. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序读取相关数据

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第七篇:为ASP.NET MVC应用程序 ...

  5. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序更新相关数据

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第八篇:为ASP.NET MVC应用程序 ...

  6. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序使用异步及存储过程

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第九篇:为ASP.NET MVC应用程序 ...

  7. [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序处理并发

    这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第十篇:为ASP.NET MVC应用程序 ...

  8. ASP.NET MVC应用程序执行过程分析

    ASP.NET MVC应用程序执行过程分析 2009-08-14 17:57 朱先忠 朱先忠的博客 字号:T | T   ASP.NET MVC框架提供了支持Visual Studio的工程模板.本文 ...

  9. 在ASP.NET MVC应用程序中实现Server.Transfer()类似的功能

    在ASP.NET MVC应用程序中,如果使用Server.Transfer()方法希望将请求转发到其它路径或者Http处理程序进行处理,都会引发“为xxx执行子请求时出错”的HttpException ...

随机推荐

  1. 跟我一起学习ASP.NET 4.5 MVC4.0(一)(转)

    由于上面一个项目使用的是ASP.NET4.0 MVC3.0,在招人的时候发现很多人有听说过MVC,但是却是没用过,对MVC也只是一知半解,最近想给团队成员做一个系统的解说,让大家都可以学习一下ASP. ...

  2. 搭建Cocos2d-JS开发环境

    使用Cocos2d-JS引擎开发游戏,主要的程序代码是JavaScript语言,因此,凡是能够开发JavaScript语言工具都适用于Cocos2d-JS游戏开发.本书我们推荐WebStorm和Coc ...

  3. 实例介绍Cocos2d-x精灵菜单和图片菜单

    精灵菜单类是MenuItemSprite,图片菜单类是MenuItemImage.由于MenuItemImage继承于MenuItemSprite,所以图片菜单也属于精灵菜单.为什么叫精灵菜单呢?那是 ...

  4. 标识映射(Identify Map)

    通过在Map中保存每个已加载过的对象,确保每个对象只加载一次. 当要访问对象时,首先检查标识映射,看需要的对象是否已经存在其中. 使用Identify来确保不重复加载相同的数据,不仅有助于保证正确性( ...

  5. javascript笔记——前端实现分页和查询

    //Modal function Modal(obj){ var that = this; that.ref = ""; that.obj = obj; that.init(); ...

  6. 【风马一族_Android】Button 按钮之记录

    Button button = new Button(); Button button = (Button)findViewById(R.id.bt_button);//让按钮显示灰色,失效 butt ...

  7. C#使用SocketAsyncEventArgs操作套接字的简单异步通讯

    SocketAsyncEventArgs是一个套接字操作的类,主要作用是实现socket消息的异步接收和发送,跟Socket的BeginSend和 BeginReceive方法异步处理没有多大区别,它 ...

  8. 如何查看 Apache 的版本

    查看 Apache 服务器版本的命令行为: httpd -v 或者 apachectl -v 例如:用 Xshell 连接到服务器后,输入:httpd -v 或者:apachectl -v 返回: S ...

  9. 浅析php fwrite写入txt文件的时候用 \r\n不能换行的问题

    以下是对php中fwrite写入txt文件的时候用 \r\n不能换行的问题进行了介绍,需要的朋友可以过来参考下今天遇到了一个问题就是用fwrite写入txt文件的时候用 rn不能换行试了很久都没找到办 ...

  10. python autopy

    今天学习了python autopy 主要包括alert,color,mouse,key,bitmap,screen等的操作 文档在http://www.autopy.org/documentatio ...