2016-02-04 3 views
0

При попытке разрешить тип из моего контейнера Simple Injector он бросает ActivatorException, говоря, что мой тип не зарегистрирован, хотя я уверен, что он был.SimpleInjector ActivatorException при разрешении типа COM-взаимодействия

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) 
    { 
    } 
} 

IApplicationAdapter.cs

public interface IApplicationAdapter 
{ 
} 

Но когда дело доходит до разрешить Excel.Application я получаю исключение, как:

enter image description here

Так пытается отлаживая это, я думал, что это не было LY был зарегистрирован правильно, но при проверке добавленных регистраций в контейнере, я могу видеть, что Excel.Application было добавлено:

enter image description here

Я также проверил и сделал 100% уверен, что два класса ссылки на такой же Excel.Application сборка который они.

Наконец, я бы добавил экземпляр Excel.Application в контейнер, но так как это __COMObject Я не могу зарегистрировать его как Excel.Application.

Я совершенно не понимаю, почему Simple Injector не может правильно разрешить интерфейс.

+0

Что бы вы хотели, чтобы я опубликовал? Это все, что я делаю для обработки Excel.Application'. Я не создаю его, и все, что я пытаюсь сделать, это зарегистрировать его в контейнере, как указано выше. –

+0

Вы непосредственно вводите COM-объекты в свои приложения? Тьфу! Это может быть нарушение принципа инверсии зависимостей. В DIP указано, что ваши классы должны разговаривать с конкретными абстракциями приложения. Вероятно, это означает, что вы создаете адаптер, который обертывает COM-объект. Это не позволяет вам вводить COM-объект. COM-объекты такие, потому что вы разговариваете с прокси. Такой прокси-объект может заставить SI видеть два разных типа; это может беспокоить вас. – Steven

+0

Да, это очень здорово. Но я ввожу его, так что мне не нужно создавать свой «ApplicationAdapter», а затем добавлять его в контейнер. Я бы не хотел, если бы с помощью перегрузки, которая принимает значение «Func », будет создаваться тип upfront и будет основываться на интерфейсе Excel.Application, который я регистрирую как? Как я вижу, в контейнере есть интерфейс 'Excel.Application'. –

ответ

3

Я не уверен, почему это происходит. Я могу подтвердить, что возникает исключение при попытке зарегистрировать это как в вашем примере.

С тем, что вы пытаетесь сделать, я согласен с комментарием Стивена, yuck !! Создание собственных, возможных множественных абстракций над объектом приложения должно быть способом.

Однако то, что вы хотите, возможно с некоторыми незначительными изменениями. Вместо регистрации самого объекта приложения, который бросает по какой-то странной причине, вы можете зарегистрировать 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, и это работает должным образом.

+0

Я не думал об обертывании объекта и добавлял это, поскольку я обертывал его своим «ApplicationAdapter», но это работает очень хорошо. Я был просто удивлен, что интерфейс не был разрешен, это то, что мне нужно будет изучить только для моих собственных интересов, но это очень хороший ответ. –

Смежные вопросы