如何:将 MEF 用于 MVC
本主题解释了如何创建使用 Managed Extensibility Framework (MEF) 的 ASP.NET 模型视图控制器 (MVC) 应用。 你可以使用 MEF 来连接组成 MVC 应用的请求处理机制的模型、视图和控制器。 执行应用的业务逻辑的应用特定对象可以表示为 MEF 部件。 MEF 组合引擎为 MVC 控制器提供完整的、现成的部件,并且自动处理这些部件的处置和拆卸。
本主题假定你熟悉在 MEF 概述中讨论的概念。
重要
本主题中的过程需要 Visual Studio 2012 或更高版本。
创建 MVC 项目
从 Visual Studio 2012 开始,Visual Studio 包括你用于创建 ASP.NET MVC 解决方案的模板。
创建 MVC 项目
在 Visual Studio 中,创建一个类型为 ASP.NET MVC 3 Web 应用程序的新项目,并且将它命名为 MEFMVCApp。
在**“新建 ASP.NET MVC 3 项目”对话框中,选中“Internet 应用程序”**。
在你的项目中创建一个称为“部件”的文件夹。 部件是 MEF 组合的基本单位,并且可以用于提供 MVC 应用自身无法提供的所有应用服务:访问数据、执行计算、访问其他站点或服务以及实现你的业务逻辑。
导出和导入部件
在 ASP.NET MVC 应用中,你可以使用接口来定义一个部件提供给其他部件的协定。
导出和导入部件
打开针对“部件”文件夹的快捷菜单,并且添加一个名为 ILogger.cs 的接口。 添加以下代码:
public interface ILogger { void Write(string text); }
“部件”文件夹中的任何具体类均假定为针对托管组合。 对 MEF 而言,将会导出这些类(请参阅 MEF 概述)。 按照约定,任何由部件实现的接口均假定为其希望导出的协定。
打开针对“部件”文件夹的快捷菜单,并且添加一个名为 TraceLogger.cs 的类。 添加以下代码:
public class TraceLogger : ILogger { public void Write(string text) { System.Diagnostics.Trace.WriteLine(text); } }
此部件将在协定类型 ILogger 下导出。 若要使用 MVC 应用中的此部件,你可以将它导入到控制器中。
在“控制器”文件夹中打开 HomeController.cs。 为命名空间 MEFMVCApp.Parts 添加 using 语句。 添加以下成员和构造函数:
ILogger _logger; public HomeController() : this(new TraceLogger()) { } public HomeController(ILogger logger) { _logger = logger; }
将以下行添加到 Index() 方法的主体以演示 TraceLogger:
_logger.Write("MEFMVCApp: Executing the Index() action method.");
生成并运行该项目。 当显示索引页面时,已记录的消息出现在跟踪窗口中。
更改默认行为
MVC 组合引擎作出有关应基于约定对部件执行哪些操作的假设。 通过将合适的 MEF 特性添加到部件,你可以重写这些默认行为。
重写默认行为
在 TraceLogger.cs 中,为 System.ComponentModel.Composition 添加 using 语句,然后将以下特性添加到该类:
[Export("myTraceLogger", typeof(ILogger))]
HomeController 将无法导入 TraceLogger,因为它们的协定名称不再匹配。
若要将协定名称添加到导入,则在 HomeController.cs 中,为 System.ComponentModel.Composition 添加 using 语句,然后将类中的构造函数更改为以下内容:
public HomeController([Import("myTraceLogger")]ILogger logger) { _logger = logger; }
导入和导出现在重新匹配。 有关 MEF 特性的详细信息,请参见特性化编程模型概述。
请求和应用程序范围
在 MVC 应用中创建的部件实例存在于以下一种范围中:请求范围或应用程序范围。 默认情况下,在 Web 请求期间创建的部件实例以请求范围形式存在。 在同一个请求中的部件实例是共享的,所以如果多个部件导入一个给定部件,则所有的导入程序都会收到对相同实例的引用。 每个 Web 请求具有其自身的范围,因此在一个请求中创建的部件从不用于在另一个请求中填充导入。
当一个请求结束时,与它关联的范围将销毁并且为它所创建的任何部件也将销毁。 实现 IDisposable 对象的部件将释放。 这样可以确保敏感资源(如数据库连接)都能正确关闭。
有时候,你可能不希望针对每个请求创建部件实例(例如,当你实现应用范围的缓存时)。 在以下情况中,通过应用 SharedAttribute 特性,你可以强制在应用程序范围内创建部件。 在应用程序范围内的部件始终由应用中的所有请求共享。 在应用程序范围内的部件只有在针对其导入时,才可能依赖应用程序范围中的其他部件。 应用程序范围中的部件必须小心成为线程安全的部件。
通过使用 MEF 特性,你可以重写这些默认值用于共享,所用方法与在之前部分中所使用的导入和导出特性的方法相同。 有关 MEF 特性的详细信息,请参见特性化编程模型概述。
操作筛选器特性
你可以将操作筛选器特性应用到控制器和操作以更改操作执行的方式。 尽管操作筛选器特性并非由组合提供程序创建,但通过使用 Import 特性,它们可以随部件一起提供。
提供操作筛选器
- 使用 Import 特性,如以下示例所示:
public class SaveChangesAttribute : ActionFilterAttribute
{
[Import]
public IDbContext DbContext { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception == null)
DbContext.SaveChanges();
}
}
请参见
概念
Managed Extensibility Framework (MEF)