I have been working on a project, using OnionWebApiStarterKit as a foundation for learning my way around CQRS.
While the WebApi StudentsController example in the above OnionWebApiStarterKit project only injects IMediator, I decided it would be easier to also inject my custom IApplicationUserManager in the AccountController constructor, given its heavy reliance on user operations:
public AccountsController(
IMediator mediator,
IApplicationUserManager userManager)
{
// and so on...
}
But, this produces the following error:
"The requested service 'OnionWebApiStarterKit.Data.ISchoolDbContext' has not been registered."
Full stack trace is below:
"message": "An error has occurred.",
"exceptionMessage": "An error occurred when trying to create a controller of type 'AccountsController'. Make sure that the controller has a parameterless public constructor.",
"exceptionType": "System.InvalidOperationException",
"stackTrace": " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Tracing.Tracers.HttpControllerActivatorTracer.<>c__DisplayClass2.<System.Web.Http.Dispatcher.IHttpControllerActivator.Create>b__0()\r\n at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEnd(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Action execute, Action`1 endTrace, Action`1 errorTrace)\r\n at System.Web.Http.Tracing.Tracers.HttpControllerActivatorTracer.System.Web.Http.Dispatcher.IHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Tracing.Tracers.HttpControllerDescriptorTracer.<>c__DisplayClass2.<CreateController>b__0()\r\n at System.Web.Http.Tracing.ITraceWriterExtensions.TraceBeginEnd(ITraceWriter traceWriter, HttpRequestMessage request, String category, TraceLevel level, String operatorName, String operationName, Action`1 beginTrace, Action execute, Action`1 endTrace, Action`1 errorTrace)\r\n at System.Web.Http.Tracing.Tracers.HttpControllerDescriptorTracer.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"innerException": {
"message": "An error has occurred.",
"exceptionMessage": "The requested service 'OnionWebApiStarterKit.Data.ISchoolDbContext' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.",
"exceptionType": "Autofac.Core.Registration.ComponentNotRegisteredException",
"stackTrace": " at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)\r\n at OnionWebApiStarterKit.Bootstrapper.IdentityModule.<>c.<Load>b__2_0(IComponentContext b) in C:\\Projects\\OnionWebApiStarterKit\\OnionWebApiStarterKit.Bootstrapper\\App_Start\\IdentityModule.cs:line 33\r\n at Autofac.RegistrationExtensions.<>c__DisplayClass10`1.<Register>b__f(IComponentContext c, IEnumerable`1 p)\r\n at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass1`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p)\r\n at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()\r\n at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)\r\n at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)\r\n at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)\r\n at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)\r\n at OnionWebApiStarterKit.Bootstrapper.IdentityModule.<>c.<Load>b__2_1(IComponentContext b) in C:\\Projects\\OnionWebApiStarterKit\\OnionWebApiStarterKit.Bootstrapper\\App_Start\\IdentityModule.cs:line 37\r\n at Autofac.RegistrationExtensions.<>c__DisplayClass10`1.<Register>b__f(IComponentContext c, IEnumerable`1 p)\r\n at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass1`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p)\r\n at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()\r\n at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)\r\n at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)\r\n at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()\r\n at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()\r\n at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()\r\n at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)\r\n at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)\r\n at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()\r\n at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()\r\n at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Registration.ExternalRegistrySource.<>c__DisplayClass8.<RegistrationsFor>b__3(IComponentContext c, IEnumerable`1 p)\r\n at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)\r\n at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters)\r\n at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType)\r\n at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
I am registering my dependencies from my bootstrapped Startup class:
IocConfig.RegisterDependencies(app);
And I confirmed it does get hit by setting a break-point. Below are my registrations:
public static void RegisterDependencies(IAppBuilder app)
{
DbContextScopeExtensionConfig.Setup();
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
// register Auto Mapper
AutoMapperConfig.Initialize();
// register api routing.
WebApiConfig.Register(config);
// Run optional steps, like registering filters,
// per-controller-type services, etc.
var builder = new ContainerBuilder();
// Register Web API controller in executing assembly.
builder.RegisterApiControllers(Assembly.Load("OnionWebApiStarterKit.WebApi"));
//Helper nuget for managing the DbContext lifetime in Entity Framework. Please see: http://mehdi.me/ambient-dbcontext-in-ef6/
builder.RegisterType<DbContextScopeFactory>().As<IDbContextScopeFactory>().SingleInstance();
builder.RegisterType<AmbientDbContextLocator>().As<IAmbientDbContextLocator>().SingleInstance();
// Registers our IMediator (abstraction for observer pattern, which lets us use CQRS)
builder.RegisterModule(new MediatorModule(Assembly.Load("OnionWebApiStarterKit.Services")));
// Registers our Fluent Validations that we use on our Models
builder.RegisterModule(new FluentValidationModule(Assembly.Load("OnionWebApiStarterKit.WebApi"), Assembly.Load("OnionWebApiStarterKit.Services")));
// Registers our AutoMapper Profiles
builder.RegisterModule(new AutoMapperModule(Assembly.Load("OnionWebApiStarterKit.WebApi"), Assembly.Load("OnionWebApiStarterKit.Services")));
// Registers our ASP.NET Identity custom classes.
builder.RegisterModule(new IdentityModule(Assembly.Load("OnionWebApiStarterKit.Data"), Assembly.Load("OnionWebApiStarterKit.Core")));
// Set the dependency resolver to be Autofac.
var container = builder.Build();
// helps view registered autofac dependencies.
// container.IsRegistered();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseCors(CorsOptions.AllowAll); // Enables crossdomain requests
app.UseWebApi(config);
}
In the above file, the below module handles Identity registrations, which IApplicationUserManager is part of:
// Registers our ASP.NET Identity custom classes.
builder.RegisterModule(new IdentityModule(Assembly.Load("OnionWebApiStarterKit.Data"), Assembly.Load("OnionWebApiStarterKit.Core")));
And here is how my Identity stuff is registered:
public IdentityModule(params System.Reflection.Assembly[] assembliesToScan)
: base()
{
_assembliesToScan = assembliesToScan;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType(typeof(ApplicationUserManager)).As(typeof(IApplicationUserManager)).InstancePerRequest();
builder.RegisterType(typeof(ApplicationRoleManager)).As(typeof(IApplicationRoleManager)).InstancePerRequest();
builder.RegisterType(typeof(ApplicationIdentityUser)).As(typeof(IUser<int>)).InstancePerRequest();
builder.Register(b => b.Resolve<ISchoolDbContext>() as DbContext).InstancePerRequest();
builder.Register(b =>
{
var manager = IdentityFactory.CreateUserManager(b.Resolve<DbContext>());
if (Startup.DataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationIdentityUser, int>(
Startup.DataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}).InstancePerRequest();
builder.Register(b => IdentityFactory.CreateRoleManager(b.Resolve<DbContext>())).InstancePerRequest();
builder.Register(b => HttpContext.Current.Request.GetOwinContext().Authentication).InstancePerRequest();
}
As you can see, ISchoolDbContext is clearly registered at this line:
builder.Register(b => b.Resolve<ISchoolDbContext>() as DbContext).InstancePerRequest();
This is the same line that Autofac complains about in the stack trace:
at OnionWebApiStarterKit.Bootstrapper.IdentityModule.<>c.b__2_0(IComponentContext b) in C:\Projects\OnionWebApiStarterKit\OnionWebApiStarterKit.Bootstrapper\App_Start\IdentityModule.cs:line 33
I am a bit stumped as to why injecting IApplicationUserManager is telling me I have not registered my ISchoolDbContext?
Thanks.
UPDATE
It looks like I wasn't scanning my passed-in assemblies in the IdentityModule. So, I have updated my code accordingly:
// Register our UserManager
builder.RegisterAssemblyTypes(_assembliesToScan)
.As<IApplicationUserManager>().InstancePerRequest();
//// Register our RoleManager
builder.RegisterAssemblyTypes(_assembliesToScan)
.As<IApplicationRoleManager>().InstancePerRequest();
builder.RegisterAssemblyTypes(_assembliesToScan)
.As<IUser<int>>().InstancePerRequest();
I assume you have a persistence layer or a similar class library for your database operations. Have you registered all the types in that assembly? Something like below:
var assembly = typeof(DbContextScopeFactory).Assembly;
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.StartsWith("SomeInterface"))
.AsImplementedInterfaces();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("DbContext"))
.AsImplementedInterfaces();