解析 COM 互操作类型时出现 SimpleInjector ActivatorException

SimpleInjector ActivatorException when resolving COM interop type

当试图从我的 Simple Injector 容器解析类型时,它抛出一个 ActivatorException 说我的类型没有注册,虽然我很确定它已经注册了。

ThisAddin.cs

 private void ThisAddIn_Startup(object sender, EventArgs e)
 {
     var container = new Container();
     container.RegisterSingleton<Microsoft.Office.Interop.Excel.Application>(() => this.GetHostItem<Microsoft.Office.Interop.Excel.Application>(
            typeof(Microsoft.Office.Interop.Excel.Application), "Application"));
     var application = container.GetInstance<IApplicationAdapter>();
 }

在另一个大会中,在这种情况下 ExcelInterface

ApplicationAdapter.cs

internal class ApplicationAdapter : IApplicationAdapter
{
    public Application(Microsoft.Office.Interop.Excel.Application excelApplication)
    {
    }
}

我ApplicationAdapter.cs

public interface IApplicationAdapter
{
}

但是在解决 Excel.Application 时,我得到的异常是:

所以尝试调试这个我认为它实际上没有被正确注册,但是当检查容器中添加的注册时我可以看到 Excel.Application 已经被添加:

我还检查并 100% 确定这两个 类 引用的是同一个 Excel.Application 程序集。

最后我将 Excel.Application 实例添加到容器中,但由于这是 __COMObject 我无法将其注册为 Excel.Application.

我完全不知道为什么 Simple Injector 无法正确解析接口。

我不确定为什么会这样。我可以确认在您的示例中尝试注册时发生异常。

对于你正在尝试做的事情,我同意史蒂文的评论,哎呀!!在应用程序对象上创建您自己的、可能的多个抽象应该是可行的方法。

不过,只需稍作改动即可实现您想要的效果。您可以像这样注册一个 IApplicationProvider,而不是注册应用程序对象本身(它会因某些奇怪的原因而抛出):

internal interface IApplicationProvider
{
    Excel.Application CurrentApplication { get; }
}

class ApplicationProvider : IApplicationProvider
{
    public ApplicationProvider(Excel.Application application)
    {
        this.CurrentApplication = application;
    }
    // c# 6 syntax
    public Excel.Application CurrentApplication { get; } 
}

您可以注册为:

var container = new Container();
var app = this.GetInstance<Microsoft.Office.Interop.Excel.Application>("Application");
var appicationProvider = new ApplicationProvider(app);

container.RegisterSingleton<IApplicationProvider>(appicationProvider);

//Make other registrations....

container.Verify();

为了可读性,我做了一个小辅助方法:

public TInstance GetInstance<TInstance>(string key) where TInstance : class
{
   return this.GetHostItem<TInstance>(typeof (TInstance), key);
}

你现在需要应用程序对象的任何地方你都可以注入 IApplicationProvider 并像这样使用:

class SomeService
{
    private readonly IApplicationProvider applicationProvider;

    public SomeService(IApplicationProvider applicationProvider)
    {
        this.applicationProvider = applicationProvider;
    }

    public int GetWorkbookCount()
    {
        return this.currentApplication.Workbooks.Count;
    }

    // c# 6 syntax
    private Excel.Application currentApplication => 
               this.applicationProvider.CurrentApplication;
}

已使用 Office 2016 进行测试,这按预期工作。