Open Generic类型不会在目录中注册

时间:2013-08-09 13:07:08

标签: c# mef

我们正在使用.NET 4.5,直到一个月前突然停止工作时,MEF中的开放式通用导出也没有问题。我们的CI服务器上的70个测试变为红色,我们将其追溯到容器中缺少的部分。

我发现它很奇怪,所以我写了这个测试代码:

var catalog = new TypeCatalog(typeof(Impersonator<>), typeof(Cache<>));
var parts = catalog.Parts;

但看起来没有任何开放的泛型类型会在目录中注册。 PartsTypeCatalog Types = <Empty>

通常我们通过使用this SO question中的属性的声明性导出来解决这个问题,但是没有一个替代方案似乎已经起作用了。

任何想法都会受到最高的赞赏。

5 个答案:

答案 0 :(得分:2)

知道什么触发它开始失败了吗?您是否在该时间范围内获得了.NET更新?

出于好奇,如果你写一个针对.NET 4.5的简单控制台应用程序,这个问题是否重现?

我问的原因是我相信有一个针对.NET 4.5发布的更新,以确保打开的泛型不破坏现有的.NET 4.0应用程序,因此如果出于某种原因,您的测试在.NET 4.0模式下运行,那么将禁用开放式通用支持,这可能会导致您所看到的内容。

答案 1 :(得分:2)

我在我的网络应用中通过输入条目&lt; httpRuntime targetFramework =“4.5”/&gt;在我的web.config中。对于非Web应用程序,请确保app.config具有该条目         &LT; supportedRuntime version =“v4.0”sku =“。NETFramework,Version = v4.5”/&gt;。

请参阅http://blogs.msdn.com/b/webdev/archive/2012/11/19/all-about-httpruntime-targetframework.aspx了解详情。

答案 2 :(得分:1)

我知道这是一个老问题,但我有一些可能对其他人有帮助的其他信息。

我遇到了同样的问题。我的单元测试工作然后突然停止。我们将其缩小为一对Windows更新:KB2840642v2和KB2840642。卸载这些后,MEF在单元测试中再次开始正常工作。我没有在发行说明中看到任何可能影响事情的更新,但你知道这是怎么回事。

然而,不幸的是,我现在正在运行Windows 8,并且问题又出现了。我没有安装这些更新。我认为它们本身已合并到操作系统中。

答案 3 :(得分:1)

当您说“在我们的CI服务器上”时,这并没有告诉我们您如何运行测试。但是,我似乎使用vstest.console.exe获得了与您相同的体验。

我发现MEF的自动开放式关闭功能(.net-4.5中的新功能)在使用vstest.console.exe运行测试时似乎会中断。基本上,vstest.console.exe可能决定在.net-4.0兼容模式下运行,就像传递了/Framework:Framework40一样。即使由.net-4.0运行时加载,.net-4.5程序集也会加载并运行完全正常,但MEF检测到您正在.net-4.0模式下运行并禁用其对自动关闭开放泛型类型的支持。您可以通过传递vstest.console.exe开关强制/Framework:Framework45以.net-4.5模式运行来让MEF再次正常运行。

(这在安装了.net-4.6.1的计算机上进行了测试,但不确定这是否会改变更多内容)。

Minimal Repro

当我针对.net-4.5框架创建一个简单的测试程序集时,vstest.console.exe正确地猜测它应该使用.net-4.5运行测试。但是,当我组装一个集成到更复杂的构建环境的程序集时,vstest.console.exe突然开始以.net-4.0模式而不是.net-4.5模式运行。所以我从复杂的构建环境开始,开始削减一切,直到问题消失。

要让vstest.console.exe猜错框架,需要两个程序集。在一个方面,定义自定义程序集Attribute。在另一个应用程序中,应用该自定义程序集属性并定义单元测试。

第一次集会:

using System;

[AttributeUsage(AttributeTargets.Assembly)]
public class BreakVSTestFrameworkDetectionAttribute : Attribute
{
}

引用前一个程序集的第二个程序集:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

[assembly: BreakVSTestFrameworkDetection]

[InheritedExport]
public interface IGenericService<T>
{
    void Print(T thing);
}

public class SomeGenericService<T> : IGenericService<T>
{
    public void Print(T thing) => Console.WriteLine($"{typeof(T)}:{thing}");
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void Run()
    {
        using (var catalogue = new ApplicationCatalog())
        using (var container = new CompositionContainer(catalogue))
        {
            container.GetExportedValue<IGenericService<string>>().Print("asdf"); // System.String:asdf
            container.GetExportedValue<IGenericService<int>>().Print(123); // System.Int32:123
        }
    }

    static void Main(string[] args) => new UnitTest1().Run();
}

通过这两个程序集和定义的测试,我在不同的场景中得到以下结果:

  1. 使用Visual Studio 2015社区版的GUI运行测试非常合适。

    Test Explorer / MefGenericsUnitTests (1) / 1 Test Passed

  2. 直接将代码作为可执行文件运行正常。

    C:\Users\ohnob\OneDrive\Documents\Visual Studio 2015\Projects\MefGenericsUnitTests>bin\Debug\MefGenericsUnitTests.exe
    System.String:asdf
    System.Int32:123
    
  3. 使用像mstest(except I can’t tell why one would or wouldn’t use this instead of vstest)之类的东西运行测试会神奇地起作用(至少在这种情况下)(输出修剪)。

    C:\Users\ohnob\OneDrive\Documents\Visual Studio 2015\Projects\MefGenericsUnitTests>"\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\MSTest.exe" /testcontainer:bin\Debug\MefGenericsUnitTests.exe
    Microsoft (R) Test Execution Command Line Tool Version 14.0.23107.0
    Copyright (c) Microsoft Corporation. All rights reserved.
    
    Loading bin\Debug\MefGenericsUnitTests.exe...
    Starting execution...
    
    Results               Top Level Tests
    -------               ---------------
    Passed                UnitTest1.Run
    1/1 test(s) Passed
    
  4. 直线上升vstest.console.exe失败(输出修剪):

    C:\Users\ohnob\OneDrive\Documents\Visual Studio 2015\Projects\MefGenericsUnitTests>"\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe" bin\Debug\MefGenericsUnitTests.exe
    Microsoft (R) Test Execution Command Line Tool Version 14.0.24720.0
    Copyright (c) Microsoft Corporation.  All rights reserved.
    
    Starting test execution, please wait...
    Failed   Run
    Error Message:
       Test method UnitTest1.Run threw exception:
    System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint:
            ContractName    IGenericService(System.String)
            RequiredTypeIdentity    IGenericService(System.String)
    
  5. 但是vstest.console.exe /Framework:Framework45成功了:

    C:\Users\ohnob\OneDrive\Documents\Visual Studio 2015\Projects\MefGenericsUnitTests>"\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe" /Framework:Framework45 bin\Debug\MefGenericsUnitTests.exe
    Microsoft (R) Test Execution Command Line Tool Version 14.0.24720.0
    Copyright (c) Microsoft Corporation.  All rights reserved.
    
    Starting test execution, please wait...
    Passed   Run
    
    Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
    Test Run Successful.
    Test execution time: 3.7855 Seconds
    

答案 4 :(得分:0)

我认为你不能使用open generic,应该提供一个具体的运行类,如:

var catalog = new TypeCatalog(typeof(Impersonator<type1>), typeof(Impersonator<type2>), typeof(Cache<type3>), typeof(Cache<type4>));
var parts = catalog.Parts;

我尝试使用IImpersonator和ICache等接口,但也不起作用:

interface IImpersonator { }
class Impersonator<T> : IImpersonator
...
var catalog = new TypeCatalog(typeof(IImpersonator), typeof(ICache));
var parts = catalog.Parts;
相关问题