【问题标题】:Autofac fails to resolve types from certain assemblies at runtime, works from debuggerAutofac 无法在运行时从某些程序集中解析类型,在调试器中工作
【发布时间】:2017-01-06 12:06:26
【问题描述】:

在我的解决方案中,我有更多的程序集。其中一些包括一个带有来自程序集的注册的 Autofac 模块。我在启动后立即将所有注册连接在一起。到目前为止一切正常,我通过构造函数注入创建了依赖项,Autofac 帮助我解决了依赖项。

(在这个项目中,我在控制台应用程序中托管 SignalR 和 WebApi 功能。我也使用 OWIN。)

在我添加了 WebApi 并使用 DI 创建了我的第一个控制器后,我遇到了一个问题。在MyController 的构造函数中,我依赖于MyInterface。当我尝试调用控制器上的任何方法时,我得到了普通的

在“MyController”类型上使用“Autofac.Core.Activators.Reflection.DefaultConstructorFinder”找到的任何构造函数都不能被可用的服务和参数调用: 无法解析构造函数“Void .ctor(MyInterface)”的参数“MyInterface myInt”。

异常。我注意到了什么:

  • 如果我将 MyInterface 替换为来自另一个程序集的另一个,则会加载控制器。
  • MyInterface 可以在我的代码中的另一个位置(在另一个程序集中)解决

我继续进行一些调试。我试图在我的 OWIN Startup 课程中在启动时解决一些课程。我现在看到的是

  • 我无法解析来自MyAssembly1MyAssembly2 的任何类型
  • 我可以解析来自MyAssembly3MyAssembly4的所有类型
  • container.Resolve<MyInterface> 从代码中抛出异常
  • container.Resolve<MyInterface> 如果我在调试期间通过 Visual Studio 中的 Watch 窗口解决它,则返回 已解决的类
  • 我在container.ComponentRegistry.Registrations 看到所有注册

你能告诉我,我做错了什么吗?

更新

我尽量提供所有必要的信息,如果我仍然忘记了什么,请告诉我。

这是 AssemblyA 中的 Autofac 模块定义

public class AutofacModuleConfig : Module, IAutofacModuleConfig
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<MyWorkingImplementation>().As<IMyWorkingInterface>();

        base.Load(builder);
    }

这是 AssemblyB 中的 Autofac 模块定义

public class AutofacModuleConfig : Module, IAutofacModuleConfig
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<MyNotWorkingImplementation>().As<IMyNotWorkingInterface>();

        base.Load(builder);
    }
}

在设置 WebHost 的程序集中,有一个控制器注册(与以前的结构相同)

builder.RegisterApiControllers(System.Reflection.Assembly.GetExecutingAssembly());

这是我在应用程序启动时注册东西的方式

private void RegisterModuleDependencies()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<Core.Logger.Log4NetLogger>().As<ILogger>();

    var moduleConfigs = GetModuleConfigurations();
    foreach (var module in moduleConfigs)
        builder.RegisterModule(module);

    container = builder.Build();
}

private List<Autofac.Module> GetModuleConfigurations()
{
    var type = typeof(IAutofacModuleConfig);
    var types = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(s => s.GetTypes())
        .Where(p => type.IsAssignableFrom(p) && p.GetConstructor(Type.EmptyTypes) != null);
    return types.Select(t => (Autofac.Module)Activator.CreateInstance(t)).ToList();
}

这是 SignalR 和 WebApi 的启动方法

private void Startup(IAppBuilder app)
{
    IDependencyResolver resolver = new AutofacDependencyResolver(container);
    GlobalHost.DependencyResolver = resolver;

    ...

    ConfigureOAuth(app, resolver.Resolve<IAuthorizationService>());

    app.UseCors(CorsOptions.AllowAll);
    app.MapSignalR(new HubConfiguration
    {
        Resolver = resolver,
        EnableDetailedErrors = true,
        EnableJavaScriptProxies = false
    });

    //Host WebApi
    HttpConfiguration webApiConfiguration = new HttpConfiguration();
    webApiConfiguration.MapHttpAttributeRoutes();
    webApiConfiguration.Routes.MapHttpRoute("DefaultWebApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });
    webApiConfiguration.Services.Add(typeof(System.Web.Http.ExceptionHandling.IExceptionLogger), new WebApiExceptionLogger());
    webApiConfiguration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    app.UseWebApi(webApiConfiguration);
}

出于测试目的,我包含了常见示例中使用的 ValuesController。使用默认构造函数,它自然可以正常工作。如果我使用IMyWorkingInterface 添加构造函数,那么,顾名思义,它可以完美运行。但是,如果我使用 IMyNotWorkingInterface 包含构造函数而不是工作构造函数,那么我得到了异常。

public class ValuesController : ApiController
{
    //private readonly TestNamespaceInAssemblyB.IMyNotWorkingInterface notWorkingInstance;

    //public ValuesController(TestNamespaceInAssemblyB.IMyNotWorkingInterface notWorkingInstance)
    //{
    //  this.notWorkingInstance = notWorkingInstance;
    //}

    private readonly TestNamespaceInAssemblyA.IMyWorkingInterface workingInstance;

    public ValuesController(TestNamespaceInAssemblyA.IMyWorkingInterface workingInstance)
    {
        this.workingInstance = workingInstance;
    }

当我将 IMyNotWorkingInterface 添加为另一个程序集(比如说 AssemblyC)中的依赖项时,我想再次指出它,然后它会被 Autofac 解析而不会出错。

在调试器中,我在 Watch 窗口中看到了注册 MyNotWorkingImplementation。更重要的是,我什至可以从调试器中解决它,正如您在图像上看到的那样。

更新 2

我为 Autofac 事件创建了事件处理程序,这里的日志显示了当我尝试注入 IMyNotWorkingInterface 时会发生什么

2017-01-08 13:32:36.920753 | [0x00002acc] | DEBUG | Core        - WebHost                                   | AGENT  | Chile lifetime scope started
2017-01-08 13:32:36.934754 | [0x00002acc] | DEBUG | Core        - WebHost                                   | AGENT  | Resolve operation started
2017-01-08 13:32:36.936754 | [0x00002acc] | DEBUG | Core        - WebHost                                   | AGENT  | Instance lookup is beginning for Activator = ValuesController (DelegateActivator), Services = [API.Agent.Web.Controllers.ValuesController], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = ExternallyOwned
2017-01-08 13:32:36.938754 | [0x00002acc] | DEBUG | Core        - WebHost                                   | AGENT  | Instance lookup is beginning for Activator = ValuesController (ReflectionActivator), Services = [API.Agent.Web.Controllers.ValuesController], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope
2017-01-08 13:32:36.939754 | [0x00002acc] | DEBUG | Core        - AutofacModuleConfig                       | AGENT  | Resolve for was requested by Activator = ValuesController (ReflectionActivator), Services = [API.Agent.Web.Controllers.ValuesController], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope
2017-01-08 13:32:36.966757 | [0x00002acc] | DEBUG | Core        - WebHost                                   | AGENT  | Resolve operation finished
2017-01-08 13:32:36.967757 | [0x00002acc] | ERROR | Core        - WebHost                                   | AGENT  | 
Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'API.Agent.Web.Controllers.ValuesController' can be invoked with the available services and parameters:
Cannot resolve parameter 'TestNamespaceInAssemblyB.IMyNotWorkingInterface notWorkingInstance' of constructor 'Void .ctor(TestNamespaceInAssemblyB.IMyNotWorkingInterface)'.
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)
   at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
   at Autofac.Core.Resolving.InstanceLookup.Execute()
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
2017-01-08 13:32:38.085869 | [0x000029c4] | DEBUG | Core        - WebHost                                   | AGENT  | Child lifetime scope closed

知道我可以在哪里将一些调试代码粘贴到 Autofac 中吗? (顺便说一下,我用的是 Autofac 3.5.2)

【问题讨论】:

  • 信息不足。您需要发布代码,显示您如何枚举程序集以及在何处注册内容。您所看到的长短:Autofac 没有注册 MyInterface
  • 我看不出这与您的问题有什么关系,或者即使您可能忘记将其包含在代码中,但是当您使用 Autofac、OWIN 和 Web API 时,您应该调用 @ 987654348@ 和app.UseAutofacWebApi(HttpConfiguration) 在调用app.UseWebApi 之前,如the documentation 所示。你能试试以防万一吗?
  • @MickaëlDerriey 感谢您的提示,但不幸的是它没有帮助。问题是一样的

标签: c# dependency-injection signalr asp.net-web-api2 autofac


【解决方案1】:

确保您注册了您的控制器。您需要为 autofac 包含 WebApi 特定的 nuget 包,并在启动时从容器构建器中调用以下方法:

RegisterApiControllers(Assembly.GetExecutingAssembly());

【讨论】:

  • 可悲的是,问题并不是那么简单。我的代码中有这个调用。
  • 如果你能分享你的样品,我会看看。
【解决方案2】:

好的,我可以解决这个问题,但我就是不知道为什么它不起作用。

所以这里是输出的结构:

.\Modules\AssemblyB.dll
.\AssemblyA.dll
.\Autofac.dll
.\...
.\Application.exe

在我的任何项目中都没有任何关于 AssemblyB 的参考。在启动期间,我扫描 Module 文件夹中的模块并通过调用 Assembly.LoadFrom("...\Modules\AssemblyB.dll") 加载它们在加载所有模块后,我调用问题中描述的 RegisterModuleDependencies() 方法。完成此设置后,我得到了DependencyResolutionException

解决方案:

如果我只是将 AssemblyB.dll 从 Modules 文件夹复制到根文件夹并修改程序集加载逻辑以从根文件夹加载此模块,那么我的问题就会消失,我可以将 ValuesController 与我的 IMyNotWorkingInterface 一起使用好吧。

如果有人能告诉我这里发生了什么以及为什么原始解决方案不起作用(甚至告诉我如何将模块保存在不同的文件夹中),我会接受这个答案。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 2017-09-20
相关资源
最近更新 更多