MEF部分无法导入Autofac自动生成的工厂
这是一个(对我来说)非常奇怪的问题,因为它已经完美运行,但在一些不相关的更改之后完全南下。
我有一个 Repository
,它通过 Autofacs MEF 集成在其构造函数中导入 IExtensions
列表。这些扩展之一包含对 Repository
的反向引用,作为 Lazy(Of IRepository)
(因为会发生循环引用而延迟)。
但是,一旦我尝试使用存储库,Autofac 就会抛出 ComponentNotRegisteredException
,并显示消息“请求的服务‘ContractName=Assembly.IRepository()’尚未注册。”
然而,这并不完全正确,因为当我在容器构建后立即中断并探索服务列表时,它就在那里 - Exported() 并具有正确的 ContractName。
如果有任何帮助,我将不胜感激...
Michael
[编辑] 这是代码的精简版本:
Repository
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
Plugin
<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
Bootstrapper
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
This is a (to me) pretty weird problem, because it was already running perfectly but went completely south after some unrelated changes.
I've got a Repository
which imports in its constructor a list of IExtensions
via Autofacs MEF integration. One of these extensions contains a backreference to the Repository
as Lazy(Of IRepository)
(lazy because of the circular reference that would occur).
But as soon as I try to use the repository, Autofac throws a ComponentNotRegisteredException
with the message "The requested service 'ContractName=Assembly.IRepository()' has not been registered."
That is, however, not really correct, because when I break right after the container-build and explore the list of services, it's there - Exported() and with the correct ContractName.
I'd appreciate any help on this...
Michael
[Edit] Here's a thinned-out version of the code:
Repository
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
Plugin
<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
Bootstrapper
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
啊,在我发布最后一条评论后,我想我明白了:
请注意,合约名称后面有一对括号 - 这是因为合约是一个函数,即该消息是由以下构造函数生成的,即与示例中的稍有不同:
请注意其中的“Func”。 MEF 与 Autofac 不同,它并不将 Func 视为特殊类型,因此不会将其转换为与 Lazy 相同的合约。
如果要向 MEF 组件提供 Func,则需要将其作为 Func 从 Autofac 导出。这有点棘手:
您可能需要稍微调整一下语法,我的 VB.NET 相当不稳定。
我的猜测是 /Extensions 目录中存在过时的二进制文件,这些二进制文件会干扰调试。
希望这是正确的!
缺口
Ah immediately after I posted that last comment I think I figured it out:
Note that there is a pair of parentheses after the contract name - this is because the contract is a function, i.e., this message was produced by the following constructor, which is slightly different from the one in your sample:
Note the 'Func' in there. MEF, unlike Autofac, does not regard Func as a special type and so will not translate this into the same contract as for Lazy.
If you want to provide a Func to a MEF component, you need to export it as a Func from Autofac. This is a bit tricky:
You may need to play with the syntax a bit, my VB.NET is fairly shaky.
My guess is that there are stale binaries in your /Extensions directory that are interfering with debugging this.
Hope this is on the mark!
Nick