带有 web api 的 Autofac 未解析依赖项
Autofac with web api not resolving dependencies
我很难理解为什么我似乎无法让 autofac 3.5.2(也尝试使用 4.4 版)与 Web Api 2.2 + Owin 一起工作。
我有一个需要依赖 IClass1
的控制器。它似乎已注册,但由于某种原因无法在运行时解析。知道问题出在哪里吗?
有问题的注册似乎在那里(见第 4 行 - Class1
注册为 IClass1
):
并且lifetime scope是对的,设置为:AutofacWebRequest
代码
注册
public void Configuration(IAppBuilder app)
{
var suffix = typeof(DefaultHttpControllerSelector).GetField("ControllerSuffix", BindingFlags.Static | BindingFlags.Public);
if (suffix != null) suffix.SetValue(null, string.Empty);
var container = InitializeDiContainer(app);
var config = new HttpConfiguration
{
DependencyResolver = new AutofacWebApiDependencyResolver(container)
};
config.MapHttpAttributeRoutes();
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
Mapper.Initialize(cfg =>
{
foreach (var profile in container.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
});
OnEndpointConfigurationCompleted(app, container);
}
private IContainer InitializeDiContainer(IAppBuilder app)
{
var builder = new ContainerBuilder();
var allAssemblies = AssemblyUtils.GetAllAssemblies();
builder.RegisterApiControllers("Endpoint", AssemblyUtils.GetEndpointAssemblies());
builder.RegisterAssemblyTypes(AssemblyUtils.GetAllAssemblies())
.Where(t => typeof(IReadModelService).IsAssignableFrom(t) ||
typeof(IRepository).IsAssignableFrom(t))
.AsImplementedInterfaces()
.InstancePerRequest()
.PropertiesAutowired();
builder.RegisterAssemblyTypes(AssemblyUtils.GetAllAssemblies())
.Where(t => typeof(IProvider).IsAssignableFrom(t))
.AsImplementedInterfaces()
.InstancePerRequest()
.PropertiesAutowired();
var configFilePath = Path.Combine(HttpRuntime.BinDirectory, "endpointConfig.json");
builder.Register(ctx => JsonConvert.DeserializeObject<Class1Setting>(File.ReadAllText(configFilePath)))
.InstancePerRequest();
return builder.Build();
}
依赖关系
public class Class1 : IClass1
{ }
public interface IClass1 : IReadModelService
{ }
public class Class1Setting
{
public string DataSource { get; set; }
}
控制器
控制器无法解析 IClass1
实例。
public class DeviceQueriesEndpoint : ApiController, IDeviceQueriesEndpoint
{
private IClass1 _class1;
public DeviceQueriesEndpoint(IClass1 class1)
{
_class1 = class1;
}
}
异常
这是我在运行时得到的异常:
尝试创建 'DeviceQueriesEndpoint' 类型的控制器时出错。确保控制器具有无参数 public 构造函数。
Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
An error occurred when trying to create a controller of type 'DeviceQueriesEndpoint'. Make sure that the controller has a parameterless public constructor.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = DeviceQueriesEndpoint (DelegateActivator), Services = [xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = ExternallyOwned ---> An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = DeviceQueriesEndpoint (ReflectionActivator), Services = [xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope ---> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint' can be invoked with the available services and parameters: Cannot resolve parameter 'xpto.ClassLibrary1.IClass1 class1' of constructor 'Void .ctor(xpto.ClassLibrary1.IClass1)'. (See inner exception for details.) (See inner exception for details.)
</ExceptionMessage>
<ExceptionType>Autofac.Core.DependencyResolutionException</ExceptionType>
<StackTrace>
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) at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters) at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType) at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = DeviceQueriesEndpoint (ReflectionActivator), Services = [xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope ---> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint' can be invoked with the available services and parameters: Cannot resolve parameter 'xpto.ClassLibrary1.IClass1 class1' of constructor 'Void .ctor(xpto.ClassLibrary1.IClass1)'. (See inner exception for details.)
</ExceptionMessage>
<ExceptionType>Autofac.Core.DependencyResolutionException</ExceptionType>
<StackTrace>
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__DisplayClass2_0.<RegistrationsFor>b__2(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)
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint' can be invoked with the available services and parameters: Cannot resolve parameter 'xpto.ClassLibrary1.IClass1 class1' of constructor 'Void .ctor(xpto.ClassLibrary1.IClass1)'.
</ExceptionMessage>
<ExceptionType>Autofac.Core.DependencyResolutionException</ExceptionType>
<StackTrace>
at Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(IComponentContext context, IEnumerable`1 parameters) at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
</StackTrace>
</InnerException>
</InnerException>
</InnerException>
</Error>
我尝试过的事情
如果我手动注册它起作用的具体类型,它是奇数:
builder.RegisterType<Class1>().As<IClass1>();
如果我删除构造函数并手动尝试在动作中解析 IClass1
,它仍然会失败,这让我相信我正在使用的堆栈组合存在某种错误。
其实这与Autofac无关。我使用的 Assembly.LoadFile 没有考虑程序集绑定。
我很难理解为什么我似乎无法让 autofac 3.5.2(也尝试使用 4.4 版)与 Web Api 2.2 + Owin 一起工作。
我有一个需要依赖 IClass1
的控制器。它似乎已注册,但由于某种原因无法在运行时解析。知道问题出在哪里吗?
有问题的注册似乎在那里(见第 4 行 - Class1
注册为 IClass1
):
并且lifetime scope是对的,设置为:AutofacWebRequest
代码
注册
public void Configuration(IAppBuilder app)
{
var suffix = typeof(DefaultHttpControllerSelector).GetField("ControllerSuffix", BindingFlags.Static | BindingFlags.Public);
if (suffix != null) suffix.SetValue(null, string.Empty);
var container = InitializeDiContainer(app);
var config = new HttpConfiguration
{
DependencyResolver = new AutofacWebApiDependencyResolver(container)
};
config.MapHttpAttributeRoutes();
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
Mapper.Initialize(cfg =>
{
foreach (var profile in container.Resolve<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
});
OnEndpointConfigurationCompleted(app, container);
}
private IContainer InitializeDiContainer(IAppBuilder app)
{
var builder = new ContainerBuilder();
var allAssemblies = AssemblyUtils.GetAllAssemblies();
builder.RegisterApiControllers("Endpoint", AssemblyUtils.GetEndpointAssemblies());
builder.RegisterAssemblyTypes(AssemblyUtils.GetAllAssemblies())
.Where(t => typeof(IReadModelService).IsAssignableFrom(t) ||
typeof(IRepository).IsAssignableFrom(t))
.AsImplementedInterfaces()
.InstancePerRequest()
.PropertiesAutowired();
builder.RegisterAssemblyTypes(AssemblyUtils.GetAllAssemblies())
.Where(t => typeof(IProvider).IsAssignableFrom(t))
.AsImplementedInterfaces()
.InstancePerRequest()
.PropertiesAutowired();
var configFilePath = Path.Combine(HttpRuntime.BinDirectory, "endpointConfig.json");
builder.Register(ctx => JsonConvert.DeserializeObject<Class1Setting>(File.ReadAllText(configFilePath)))
.InstancePerRequest();
return builder.Build();
}
依赖关系
public class Class1 : IClass1
{ }
public interface IClass1 : IReadModelService
{ }
public class Class1Setting
{
public string DataSource { get; set; }
}
控制器
控制器无法解析 IClass1
实例。
public class DeviceQueriesEndpoint : ApiController, IDeviceQueriesEndpoint
{
private IClass1 _class1;
public DeviceQueriesEndpoint(IClass1 class1)
{
_class1 = class1;
}
}
异常
这是我在运行时得到的异常:
尝试创建 'DeviceQueriesEndpoint' 类型的控制器时出错。确保控制器具有无参数 public 构造函数。
Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
An error occurred when trying to create a controller of type 'DeviceQueriesEndpoint'. Make sure that the controller has a parameterless public constructor.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace>
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = DeviceQueriesEndpoint (DelegateActivator), Services = [xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = ExternallyOwned ---> An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = DeviceQueriesEndpoint (ReflectionActivator), Services = [xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope ---> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint' can be invoked with the available services and parameters: Cannot resolve parameter 'xpto.ClassLibrary1.IClass1 class1' of constructor 'Void .ctor(xpto.ClassLibrary1.IClass1)'. (See inner exception for details.) (See inner exception for details.)
</ExceptionMessage>
<ExceptionType>Autofac.Core.DependencyResolutionException</ExceptionType>
<StackTrace>
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) at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters) at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters) at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType) at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = DeviceQueriesEndpoint (ReflectionActivator), Services = [xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope ---> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint' can be invoked with the available services and parameters: Cannot resolve parameter 'xpto.ClassLibrary1.IClass1 class1' of constructor 'Void .ctor(xpto.ClassLibrary1.IClass1)'. (See inner exception for details.)
</ExceptionMessage>
<ExceptionType>Autofac.Core.DependencyResolutionException</ExceptionType>
<StackTrace>
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__DisplayClass2_0.<RegistrationsFor>b__2(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)
</StackTrace>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'xpto.Middleware.Api.Device.Endpoint.DeviceQueriesEndpoint' can be invoked with the available services and parameters: Cannot resolve parameter 'xpto.ClassLibrary1.IClass1 class1' of constructor 'Void .ctor(xpto.ClassLibrary1.IClass1)'.
</ExceptionMessage>
<ExceptionType>Autofac.Core.DependencyResolutionException</ExceptionType>
<StackTrace>
at Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(IComponentContext context, IEnumerable`1 parameters) at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
</StackTrace>
</InnerException>
</InnerException>
</InnerException>
</Error>
我尝试过的事情
如果我手动注册它起作用的具体类型,它是奇数:
builder.RegisterType<Class1>().As<IClass1>();
如果我删除构造函数并手动尝试在动作中解析 IClass1
,它仍然会失败,这让我相信我正在使用的堆栈组合存在某种错误。
其实这与Autofac无关。我使用的 Assembly.LoadFile 没有考虑程序集绑定。