C# 在MEF中正确使用[Import]属性
我正在学习MEF,我想创建一个简单的示例(应用程序),看看它是如何工作的。于是我想到了一个简单的翻译。我创建了一个包含四个项目(DLL文件)的解决方案: 合同C# 在MEF中正确使用[Import]属性,c#,asp.net-mvc-3,model-view-controller,mef,extensibility,C#,Asp.net Mvc 3,Model View Controller,Mef,Extensibility,我正在学习MEF,我想创建一个简单的示例(应用程序),看看它是如何工作的。于是我想到了一个简单的翻译。我创建了一个包含四个项目(DLL文件)的解决方案: 合同 网络 BingTranslator 谷歌翻译 合同包含ITranslate界面。由于名称适用,它将只包含合同(接口),因此出口商和进口商可以使用它 public interface ITranslator { string Translate(string text); } BingTranslator和GoogleTransl
网络
BingTranslator
谷歌翻译 合同包含
ITranslate
界面。由于名称适用,它将只包含合同(接口),因此出口商和进口商可以使用它
public interface ITranslator
{
string Translate(string text);
}
BingTranslator和GoogleTranslator均为本合同的出口商。他们都执行这项合同并提供(出口)不同的翻译服务(一个来自Bing,另一个来自Google)
而BingTranslator
是:
[Export(typeof(ITranslator))]
public class BingTranslator : ITranslator
{
public string Translate(string text)
{
return "Translated by Bing";
}
}
现在,在我的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)
});
}
}
拼图的最后一块应该是将这些组件(部分)粘在一起(用较小的片段组成整个歌曲)。因此,在Web项目的Application\u Start
中,我有:
var parts = new AggregateCatalog
(
new DirectoryCatalog(Server.MapPath("/parts")),
new DirectoryCatalog(Server.MapPath("/bin"))
);
var composer = new CompositionContainer(parts);
composer.ComposeParts();
其中/parts
是我放置GoogleTranslator.dll和BingTranslator.dll文件的文件夹(导出程序位于这些文件中),以及/bin
文件夹
我只是有一个包含导入器的Web.dll文件。但是,我的问题是,MEF没有使用所需的转换器填充GeneralController
的Translator
属性。我在这个网站上阅读了几乎所有与MEF相关的问题,但我不知道我的例子有什么问题。有人能告诉我我错过了什么吗?好的,你需要做的是(没有性能方面的规定,这只是为了看到它起作用)
我不是MEF方面的专家,坦率地说,我使用它的目的对我没有多大帮助,因为我只使用它来加载DLL,然后我有一个依赖注入的入口点,从那时起我使用DI容器,而不是MEF
就我所见,MEF是必不可少的。在您的情况下,您需要主动撰写需要MEFed的内容,即您的控制器因此您的控制器工厂需要组合控制器实例。
由于我很少在MVC应用程序中使用MEFed组件,因此我为那些需要MEF的操作提供了一个过滤器(而不是在我的控制器Facry中对所有控制器进行MEF):
这里的UniversalCompositionContainer.Current.Container
是一个用我的目录目录初始化的单例容器
我个人对MEF的看法
MEF虽然不是DI框架,但它做了很多工作。因此,与DI和有很大的重叠,如果您已经使用DI框架,它们必然会发生冲突
MEF在运行时加载DLL方面非常强大,尤其是当您有WPF应用程序时,您可能正在加载/卸载插件,并且希望其他一切都能正常工作,添加/删除功能
对于web应用程序来说,这没有多大意义,因为您实际上不应该在工作的web应用程序中删除DLL。因此,其用途非常有限
我将在ASP.NETMVC中写一篇关于插件的文章,并用一个链接更新这篇文章 正如@Aliostad所提到的,您确实需要在控制器创建期间/之后运行组合初始化代码,以使其工作-仅将其放在global.asax文件中是不起作用的
但是,您还需要使用[ImportMany]
,而不仅仅是[Import]
,因为在您的示例中,您可以使用发现的二进制文件中的任意数量的ITranslator实现。要点是,如果您有许多ITranslator
,但要将它们导入到单个实例中,您可能会从MEF获得一个异常,因为它不知道您实际需要哪个实现
因此,您使用:
[ImportMany]
public IEnumerable<ITranslator> Translator { get; set; }
[ImportMany]
公共IEnumerable转换器{get;set;}
快速示例:
MEF将只在其自身构造的对象上填充导入。在ASP.NET MVC的情况下,创建控制器对象的是ASP.NET。它将无法识别[Import]
属性,因此您会发现缺少依赖项
要使MEF构造控制器,必须执行以下操作:
用[Export]
标记控制器类本身
实现一个封装MEF容器的实现。您可以通过向MEF容器请求匹配的导出来实现。您可以使用AttributedModelServices.GetContractName
从请求的类型生成MEF合同字符串
通过调用应用程序\u Start
注册该解析器
您可能还需要使用[PartCreationPolicy(CreationPolicy.NonShared)]
标记大多数导出的部件,以防止在多个请求中同时重用同一实例。在你的MEF部件中保留的任何状态都将受制于比赛条件
编辑:这是整个过程的一个很好的示例
edit2:可能还有另一个问题。MEF容器将保存对它创建的任何IDisposable
对象的引用,以便在容器本身被释放时可以释放这些对象。但是,这不适用于具有“每个请求”生存期的对象!对于任何实现IDisposable
的服务,您都会出现内存泄漏
使用类似的替代方案可能更容易,它有一个NuGet软件包,并且支持。感谢您回答@Aliostad,但坦率地说,我不知道我该怎么做才能让[Import]
在我的t上工作
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)
});
}
}
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);
}
}
[ImportMany]
public IEnumerable<ITranslator> Translator { get; set; }