Деталь MEF не может импортировать автоматически созданную фабрику Autofac

Это (для меня) довольно странная проблема, потому что она уже работала отлично, но после некоторых несвязанных изменений полностью исчезла.

У меня есть Repository, который импортирует в свой конструктор список IExtensions через интеграцию Autofacs MEF. Одно из этих расширений содержит обратную ссылку на Repository как на Lazy(Of IRepository) (ленивый из-за циклической ссылки, которая может возникнуть).

Но как только я пытаюсь использовать репозиторий, Autofac выдает ComponentNotRegisteredException с сообщением. Запрошенная служба «ContractName = Assembly.IRepository ()» не зарегистрирована.

Это, однако, не совсем правильно, потому что, когда я прерываю работу сразу после сборки контейнера и исследую список служб, он там - Exported () и с правильным ContractName.

Буду признателен за любую помощь в этом ...
Майкл

[Edit] Вот урезанная версия кода:

Репозиторий

Public Class DocumentRepository
    Implements IDocumentRepository

    Private _extensions As IEnumerable(Of IRepositoryExtension)
    
    Public Sub New(ByVal extensions As IEnumerable(Of IRepositoryExtension))
        _extensions = extensions
    End Sub

    Public Sub AddDocument(ByVal document As Contracts.IDocument) Implements Contracts.IDocumentRepository.AddDocument
        For Each extension In _extensions
            extension.OnAdded(document.Id)
        Next
    End Sub
End Class

Плагин

<Export(GetType(IRepositoryExtension))>
<PartCreationPolicy(ComponentModel.Composition.CreationPolicy.Shared)>
Public Class PdfGenerator
    Implements IRepositoryExtension

    Private _repositoryFactory As Lazy(Of IDocumentRepository)
    
    Public Sub New(ByVal repositoryFactory As Lazy(Of IDocumentRepository))
        _repositoryFactory = repositoryFactory
    End Sub

    Public Sub CreatePdf(ByVal id As Guid) Implements Contracts.IRepositoryExtension.OnAdded
        Dim document = _repositoryFactory.Value.GetDocumentById(id)
    End Sub
End Class

Бутстраппер

Public Class EditorApplication
    Inherits System.Web.HttpApplication

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        Dim builder As New ContainerBuilder()
        
        Dim catalog1 As New TypeCatalog(GetType(DataRepositoryScheme))
        Dim catalog2 As New DirectoryCatalog(HttpContext.Current.Server.MapPath("/Plugins"))
        builder.RegisterComposablePartCatalog(New AggregateCatalog(catalog1, catalog2))
        
        builder.RegisterType(Of DocumentRepository).As(Of IDocumentRepository).SingleInstance().Exported(Function(x) x.As(Of IDocumentRepository)())
        
        AutofacServiceHostFactory.Container = builder.Build()
    End Sub
End Class

person wagi    schedule 09.06.2010    source источник
comment
Возможно, вам придется опубликовать образец кода, воспроизводящий это, я не могу придумать ничего очевидного, исходя из предоставленной вами информации.   -  person Nicholas Blumhardt    schedule 10.06.2010
comment
@Ruben Bartelink: Извините, я особо не думал о редактировании оригинала, спасибо за внимание   -  person wagi    schedule 11.06.2010
comment
Привет, Майкл! Я преобразовал примеры компонентов в консольное приложение (требуются некоторые незначительные исправления / дополнения, такие как атрибут ImportingConstructor в PdfCreator) - плохая новость в том, что я могу Resolve ‹IDocumentRepository› () и успешно добавить документ , вызывая PdfCreator в процессе. Если возможно, следующий шаг - поднять вопрос здесь code.google.com/p / autofac / issues / list и прикрепите неудачный тестовый случай или пример приложения. Кстати, Lazy ‹T› возвращает один и тот же экземпляр каждый раз, поэтому он не ведет себя как фабрика. Ваше здоровье! Ник   -  person Nicholas Blumhardt    schedule 13.06.2010


Ответы (1)


Ах, сразу после того, как я опубликовал этот последний комментарий, я думаю, что понял это:

The requested service 'ContractName=ConsoleApplication7.IDocumentRepository()'
has not been registered.

Обратите внимание, что после имени контракта есть пара круглых скобок - это потому, что контракт является функцией, то есть это сообщение было создано следующим конструктором, который немного отличается от того, что в вашем примере:

Public Sub New(ByVal repositoryFactory As Func(Of IDocumentRepository))
    _repositoryFactory = repositoryFactory
End Sub

Обратите внимание на «Func» там. MEF, в отличие от Autofac, не рассматривает Func как особый тип и поэтому не переводит его в тот же контракт, что и для Lazy.

Если вы хотите предоставить Func компоненту MEF, вам необходимо экспортировать его как Func из Autofac. Это немного сложно:

builder.RegisterType(Of DocumentRepository).As(Of IDocumentRepository)

builder.Register(Function(c) c.Resolve(Of Func(Of IDocumentRepository))) _
    .As(New UniqueService()) _
    .Exported(Function(x) x.As(Of Func(Of IDocumentRepository))

Возможно, вам придется немного поиграть с синтаксисом, мой VB.NET довольно шаткий.

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

Надеюсь, это удачно!

Ник

person Community    schedule 12.06.2010
comment
Привет, Николас - Отлично, большое спасибо за отслеживание! Оказывается, при компиляции и перезапуске сервер фактически загружает предыдущую версию вместо текущей, и я этого особо не заметил. В любом случае, также хорошо знать, что мне нужно вручную зарегистрировать Func(Of T), если я хочу, чтобы MEF разрешил эту проблему. - person wagi; 13.06.2010