使用TFS工件

时间:2017-02-03 09:00:39

标签: c# tfs mef appdomain

我有一个简单的MEF导入设置,以便使用单独的appdomain允许我的二进制文件的运行时更新。问题如下:

  • 当我在Debug配置上运行Visual Studio中的代码时:Works
  • 当我在Visual Studio上运行代码时,发布配置:Works
  • 当我使用Release上的TFS工件丢弃运行代码时 配置:未找到导出
  • 当我使用PS脚本手动压缩和上传(表单POST)时 TFS构建到Web主机,然后将该版本复制到我的本地PC: 作品

我们在办公室拉出毛发为什么会发生这种情况,特别是因为我们的测试人员使用了神器掉落。

我使用的代码的缩小版本:

接口(Service.Common):

public interface IService
{
    void Config(string machineName, string instanceName, string description);
}

导出类(Service.Core):

[Export(typeof(IService)), Serializable]
public class Service : IService
{
    public void Config(string machineName, string instanceName, string description)
    {
        Debugger.Break();
    }
}

主机类(Service.Host):

[Serializable]
public class ServiceShell
{
    private static readonly string BinPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "bin");
    private static readonly string CachePath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "cache");
    private static IService _service;
    private static AppDomainSetup _setup;

    private AppDomain _domain;

    public ServiceShell(string machineName, string instanceName, string description)
    {
        Directory.CreateDirectory(BinPath);
        Directory.CreateDirectory(CachePath);

        Console.WriteLine($"Binpath: {BinPath}");
        Console.WriteLine($"Cachepath: {CachePath}");

        Console.WriteLine($"Host domain fully trusted appdomain: {AppDomain.CurrentDomain.IsFullyTrusted}");


        _setup = new AppDomainSetup
        {
            ApplicationName = "Service_Core",
            ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
            CachePath = CachePath,
            ShadowCopyFiles = "true",
            ConfigurationFile = Path.Combine(BinPath, Directory.GetFiles(BinPath, "*.dll.config")[0]),
            AppDomainInitializer = ServiceDomainConfig,
            AppDomainInitializerArguments = new[] { machineName, instanceName, description }
        };

        Console.WriteLine(_setup.ConfigurationFile);

        Compose();
    }

    private static void ServiceDomainConfig(string[] arguments)
    {
        var aggregateCatalog = new AggregateCatalog();
        aggregateCatalog.Catalogs.Add(new DirectoryCatalog(BinPath));
        var container = new CompositionContainer(aggregateCatalog);

        Console.WriteLine($"Service domain fully trusted appdomain: {AppDomain.CurrentDomain.IsFullyTrusted}");

        _service = container.GetExportedValue<IService>();
        _service.Config(arguments[0], arguments[1], arguments[2]);
    }

    private void Compose()
    {
        if (_domain != null)
            AppDomain.Unload(_domain);

        try
        {
            _domain = AppDomain.CreateDomain("ServiceDomain", AppDomain.CurrentDomain.Evidence, _setup);
        }
        catch(Exception ex)
        {
            Console.WriteLine($"Unable to create domain: {ex}");
            throw;
        }
    }

有问题的错误的示例输出:

Binpath: C:\Builds\Service\bin
Cachepath: C:\Builds\Service\cache
Host domain fully trusted appdomain: True
C:\Builds\Service\bin\Service.Core.dll.config
Service domain fully trusted appdomain: True
Unable to create domain: System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint:
        ContractName Service.Common.IService
        RequiredTypeIdentity Service.Common.IService
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExportsCore(Type type, Type metadataViewType, String contractName, ImportCardinality cardinality)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExportedValueCore[T](String contractName, ImportCardinality cardinality)
   at Service.Host.ServiceShell.ServiceDomainConfig(String[] arguments)
   at System.AppDomain.RunInitializer(AppDomainSetup setup)
   at System.AppDomain.Setup(Object arg)
   at System.AppDomain.nCreateDomain(String friendlyName, AppDomainSetup setup, Evidence providedSecurityInfo, Evidence creatorsSecurityInfo, IntPtr parentSecurityDescriptor)
   at System.AppDomain.InternalCreateDomain(String friendlyName, Evidence securityInfo, AppDomainSetup info)
   at System.AppDomain.CreateDomain(String friendlyName, Evidence securityInfo, AppDomainSetup info)
   at Service.Host.ServiceShell.Compose()

Unhandled Exception: System.ComponentModel.Composition.ImportCardinalityMismatchException: No exports were found that match the constraint:
        ContractName Service.Common.IService
        RequiredTypeIdentity Service.Common.IService
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExportsCore(Type type, Type metadataViewType, String contractName, ImportCardinality cardinality)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExportedValueCore[T](String contractName, ImportCardinality cardinality)
   at Service.Host.ServiceShell.ServiceDomainConfig(String[] arguments)
   at System.AppDomain.RunInitializer(AppDomainSetup setup)
   at System.AppDomain.Setup(Object arg)
   at System.AppDomain.nCreateDomain(String friendlyName, AppDomainSetup setup, Evidence providedSecurityInfo, Evidence creatorsSecurityInfo, IntPtr parentSecurityDescriptor)
   at System.AppDomain.InternalCreateDomain(String friendlyName, Evidence securityInfo, AppDomainSetup info)
   at System.AppDomain.CreateDomain(String friendlyName, Evidence securityInfo, AppDomainSetup info)
   at Service.Host.ServiceShell.Compose()
   at Service.Host.ServiceShell..ctor(String machineName, String instanceName, String description)
   at Service.Host.Program.Main()

1 个答案:

答案 0 :(得分:2)

我找到了导致这个问题的问题,但它并不像看起来那么明显。问题实际上是Windows中的安全性。

TFS drop的下载是来自互联网的拉链,这会导致Windows自动将zip标记为潜在不安全并向zip添加备用数据流。当您使用资源管理器解压缩时,该zip文件中的所有文件都会将相同的ADS传输给它们。事实证明,MEF不喜欢这个ADS,它导致它找不到导出。当我删除ADS图层时,它发现导出就好了,同样当我尝试解锁zip并解压缩时发现导出就好了。

这里的区别在于网络主机在我们的内部网络中,所以当我将文件复制到我的本地PC时,它没有收到这个不安全标志,因此没有收到ADS层。