Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在MEF中正确使用[Import]属性_C#_Asp.net Mvc 3_Model View Controller_Mef_Extensibility - Fatal编程技术网

C# 在MEF中正确使用[Import]属性

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

我正在学习MEF,我想创建一个简单的示例(应用程序),看看它是如何工作的。于是我想到了一个简单的翻译。我创建了一个包含四个项目(DLL文件)的解决方案:

合同
网络
BingTranslator
谷歌翻译

合同包含
ITranslate
界面。由于名称适用,它将只包含合同(接口),因此出口商和进口商可以使用它

public interface ITranslator
{
    string Translate(string text);
}
BingTranslatorGoogleTranslator均为本合同的出口商。他们都执行这项合同并提供(出口)不同的翻译服务(一个来自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; }