Sae*_*ati 7 c# model-view-controller extensibility mef asp.net-mvc-3
我正在学习MEF,我想创建一个简单的例子(应用程序),看看它是如何运作的.因此我想到了一个简单的翻译.我创建了一个包含四个项目(DLL文件)的解决方案:
合同
Web
BingTranslator
GoogleTranslator
合同包含ITranslate界面.正如名称所适用的那样,它只包含合同(接口),因此出口商和进口商可以使用它.
public interface ITranslator
{
string Translate(string text);
}
Run Code Online (Sandbox Code Playgroud)
BingTranslator和GoogleTranslator都是这份合同的出口商.他们都实施这份合同并提供(出口)不同的翻译服务(一个来自Bing,另一个来自Google).
[Export(typeof(ITranslator))]
public class GoogleTranslator: ITranslator
{
public string Translate(string text)
{
// Here, I would connect to Google translate and do the work.
return "Translated by Google Translator";
}
}
Run Code Online (Sandbox Code Playgroud)
而且BingTranslator是:
[Export(typeof(ITranslator))]
public class BingTranslator : ITranslator
{
public string Translate(string text)
{
return "Translated by Bing";
}
}
Run Code Online (Sandbox Code Playgroud)
现在,在我的Web项目中,我只想从用户那里获取文本,将其翻译成其中一个翻译者(Bing和Google),然后将结果返回给用户.因此,在我的Web应用程序中,我依赖于翻译.因此,我用这种方式创建了一个控制器:
public class GeneralController : Controller
{
[Import]
public ITranslator Translator { get; set; }
public JsonResult Translate(string text)
{
return Json(new
{
source = text,
translation = Translator.Translate(text)
});
}
}
Run Code Online (Sandbox Code Playgroud)
拼图的最后一部分应该是将这些组件(部件)粘合在一起(从较小的部分组成整首歌曲).所以,在Application_Start对的网站项目,我有:
var parts = new AggregateCatalog
(
new DirectoryCatalog(Server.MapPath("/parts")),
new DirectoryCatalog(Server.MapPath("/bin"))
);
var composer = new CompositionContainer(parts);
composer.ComposeParts();
Run Code Online (Sandbox Code Playgroud)
其中/parts是我删除GoogleTranslator.dll和BingTranslator.dll文件的文件夹(导出程序位于这些文件中),在/bin文件夹中我只有我的Web.dll文件,其中包含导入程序.但是,我的问题是,MEF不会使用所需的翻译器填充Translator属性GeneralController.我在这个网站上几乎阅读了与MEF相关的所有问题,但我无法弄清楚我的例子有什么问题.谁能告诉我我错过了什么?
好的你需要做的是(没有规定性能,这只是为了看它工作)
public class GeneralController : Controller
{
[Import]
public ITranslator Translator { get; set; }
public JsonResult Translate(string text)
{
var container = new CompositionContainer(
new DirectoryCatalog(Path.Combine(HttpRuntime.BinDirectory, "Plugins")));
CompositionBatch compositionBatch = new CompositionBatch();
compositionBatch.AddPart(this);
Container.Compose(compositionBatch);
return Json(new
{
source = text,
translation = Translator.Translate(text)
});
}
}
Run Code Online (Sandbox Code Playgroud)
我不是MEF的专家,坦率地说我使用它,它对我没有太大帮助,因为我只使用它来加载DLL然后我有一个入口点依赖注入从那时起我使用DI容器而不是MEF.
就我所见,MEF势在必行.在您的情况下,您需要主动撰写您需要MEFed的内容,即您的控制器.所以你的控制器工厂需要组成你的控制器实例.
由于我很少在我的MVC应用程序中使用MEFed组件,因此我有一个过滤器用于需要MEF的操作(而不是MEFing我的控制器库中的所有控制器):
public class InitialisePluginsAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
CompositionBatch compositionBatch = new CompositionBatch();
compositionBatch.AddPart(filterContext.Controller);
UniversalCompositionContainer.Current.Container.Compose(
compositionBatch);
base.OnActionExecuting(filterContext);
}
}
Run Code Online (Sandbox Code Playgroud)
这UniversalCompositionContainer.Current.Container是一个用我的目录编目初始化的单例容器.
MEF,虽然不是DI框架,但它做了很多.因此,与DI存在很大的重叠,如果您已经使用DI框架,它们必然会发生冲突.
MEF在运行时加载DLL的功能非常强大,尤其是当您有WPF应用程序时,您可能正在加载/卸载插件并期望其他所有内容都可以正常工作,添加/删除功能.
对于Web应用程序,这没有多大意义,因为您实际上不应该在工作的Web应用程序中删除DLL.因此,它的用途非常有限.
我将在ASP.NET MVC上写一篇关于插件的帖子,并将用链接更新这篇文章.
MEF将仅填充其构造自身的对象的导入.对于ASP.NET MVC,它是创建控制器对象的ASP.NET.它不会识别该[Import]属性,因此您就会看到缺少依赖项的原因.
要使MEF构建控制器,您必须执行以下操作:
[Export].AttributedModelServices.GetContractName.Application_Start.您可能还需要标记大部分导出的部分,[PartCreationPolicy(CreationPolicy.NonShared)]以防止同时在多个请求中重复使用同一个实例.保留在MEF部件中的任何州都将受到竞赛条件的限制.
编辑:这篇博文有一个很好的整个过程的例子.
edit2:可能还有其他问题.MEF容器将保存IDisposable对其创建的任何对象的引用,以便在容器本身被放置时它可以处置这些对象.但是,这不适用于具有"每个请求"生命周期的对象!对于任何实现的服务,您将有效地进行内存泄漏IDisposable.
可能更容易使用像AutoFac这样的替代方案,它具有用于ASP.NET MVC集成的NuGet包,并且支持每个请求的生命周期.
| 归档时间: |
|
| 查看次数: |
12312 次 |
| 最近记录: |