Autofac in MVC 5 - asp.net

I'm trying to learn how to use autofac in MVC and not having a great deal of luck.
I installed Autofac.mvc5 from Nuget version 4.01
and Autofac v4.6.1
I have the following controller:
[Authorize]
public class NotificationsController : ApiController
{
private ApplicationDbContext _context;
private readonly IMapper _mapper;
public NotificationsController(IMapper notificationMapper)
{
_context = new ApplicationDbContext();
_mapper = notificationMapper;
}
public IEnumerable<NotificationDto>GetNewNotifications()
{
var userId = User.Identity.GetUserId();
var notifications = _context.UserNotifications
.Where(un => un.UserId==userId)
.Select(un=>un.Notification)
.Include(n=>n.Gig.Artist).ToList();
return notifications.Select(notification => _mapper.Map<NotificationDto>(notification)).ToList();
}
}
My Global.Asax is:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
ConfigureAutofac();
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
private void ConfigureAutofac()
{
var autoMapperConfig = new MapperConfiguration(c =>
{
c.AddProfile(new NotificationProfile());
});
var mapper = autoMapperConfig.CreateMapper();
var builder = new ContainerBuilder();
builder.RegisterInstance(mapper);
builder.Register(x => new NotificationsController(x.Resolve<IMapper>()));
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
What I'm finding is that when I call this using postman I get an error saying I need a parameterless consturctor, but then if I put in the constructor _mapper is null.
Could someone point me in the right direction please?

Your controller derives from ApiController, so you are not using MVC, you are using WebApi (I assume WebApi2). So, you should use either Controller and MVC, or install Autofac.WebApi2 NuGet package to handle WebApi2.
Also, instead of registering all your controllers manually, you could use RegisterControllers() for MVC or RegisterApiControllers() for WebApi to have all your controllers registered at once. Especially, when your NotificationController does not use any fancy injection to require more custom registration.
The documentation describes very well, how you should use Autofac with MVC or WebApi, you should start there.

Related

How to configure dependency injection for self hosted MVC 4 API controllers

After checking all the similar questions on SO, my issue persists so I'm opening a new question for it.
I have a unit test that references anther project that contains a MVC 4 ApiController which has a constructor for dependency injection.
public class DataController : ApiController
{
public DataController(IRepository repository){}
}
In my test, I'm using Microsoft.Extensions.DependencyInjection and have the following setup:
// Note: this redundant type access is necessary to load controllers from a different assembly,
// see https://stackoverflow.com/a/11758025/1468097
var type = typeof(DataController);
var services = new ServiceCollection().AddSingleton<IRepository>(new ImMemoryRepository());
var httpConfiguration = new HttpConfiguration
{
DependencyResolver = new DependencyResolver(services.BuildServiceProvider()),
IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always
};
httpConfiguration.Routes.MapHttpRoute("Default", "{controller}/{action}");
httpConfiguration.DependencyResolver = new DependencyResolver(services.BuildServiceProvider());
var httpServer = new HttpServer(httpConfiguration);
var client = new HttpClient(httpServer);
var response = await client.GetAsync("http://whatever/data/getdata?id=000");
and I have a fairly barebone implementation of the dependency resolver as nested private class inside the test class:
private class DependencyResolver : IDependencyResolver
{
private readonly ServiceProvider _serviceProvider;
public DependencyResolver(ServiceProvider serviceProvider) => _serviceProvider = serviceProvider;
public void Dispose() => _serviceProvider.Dispose();
public object GetService(Type serviceType) => _serviceProvider.GetService(serviceType);
public IEnumerable<object> GetServices(Type serviceType) => _serviceProvider.GetServices(serviceType);
public IDependencyScope BeginScope() => new Scope(_serviceProvider.CreateScope());
private class Scope : IDependencyScope
{
private readonly IServiceScope _scope;
public Scope(IServiceScope scope) => _scope = scope;
public void Dispose() => _scope.Dispose();
public object GetService(Type serviceType) => _scope.ServiceProvider.GetService(serviceType);
public IEnumerable<object> GetServices(Type serviceType) => _scope.ServiceProvider.GetServices(serviceType);
}
}
The response I get from the test is a 500 server error saying
Type 'Mvc.DataController' does not have a default constructor
It seems I'm doing what all the others are doing for dependency injection in MVC 4, even for this question that has a very similar symptom.
Am I missing something obvious here?
Update
I've tried NinjectResolver comes down to the same problem:
var kernel = new StandardKernel();
kernel.Bind<IRepository>().ToConstant(new InMemoryRepository());
var httpConfiguration = new HttpConfiguration
{
DependencyResolver = new NinjectResolver(kernel)
};
I figured this out.
The key is that you also need to add the controller you are hitting in your dependency configuration.
In my case, I just need to add:
var services = new ServiceCollection();
// This is what was missing.
services.AddTransient<DataController>();
Taken from here (although I'm not using OWIN at all): How to add Microsoft.Extensions.DependencyInjection to OWIN Self-Hosted WebApi
Another example using Autofac:
var builder = new ContainerBuilder();
// You need to register the assembly that contains your controller.
builder.RegisterApiControllers(typeof(DataController).Assembly);
Taken from here: Dependency injection not working with Owin self-hosted Web Api 2 and Autofac

Autofac Web API error Make sure that the controller has a parameterless public constructor

I am getting this error while configuring Autofac with ASP.NET WebAPI.
An error occurred when trying to create a controller of type 'UserController'. Make sure that the controller has a parameterless public constructor.
Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var file = HostingEnvironment.MapPath("~/log4net.config");
if (file != null)
{
var configFile = new FileInfo(file);
if (configFile.Exists)
XmlConfigurator.ConfigureAndWatch(configFile);
else
BasicConfigurator.Configure();
}
else
{
BasicConfigurator.Configure();
}
var builder = new ContainerBuilder();
var config = new HttpConfiguration();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
builder.RegisterModule(new WebModule(app));
// Register your MVC controllers.
builder.RegisterControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register model binders that require DI.
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
// OPTIONAL: Register web abstractions like HttpContextBase.
builder.RegisterModule<AutofacWebTypesModule>();
// OPTIONAL: Enable property injection in view pages.
builder.RegisterSource(new ViewRegistrationSource());
// OPTIONAL: Enable property injection into action filters.
builder.RegisterFilterProvider();
// register config
builder.Register(ct => config).AsSelf().SingleInstance();
HelpPageConfig.Register(config);
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseAutofacMvc();
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
config.EnsureInitialized();
}
}
Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
}
WebModule.cs
public class WebModule : Module
{
private readonly IAppBuilder _app;
public WebModule(IAppBuilder app)
{
_app = app;
}
protected override void Load(ContainerBuilder builder)
{
// ---- Utilities -----------------------------------
builder.RegisterType<Log4NetLogger>()
.As<ILogger>().SingleInstance();
builder.RegisterType<DataAccessConfigurationSettings>()
.As<IDataAccessSettings>().SingleInstance();
builder.RegisterType<ApplicationServicesConfigurationSettings>()
.As<IApplicationServicesSettings>().SingleInstance();
builder.RegisterType<ValidationExceptionHandler>()
.As<IExceptionHandler<ValidationException>>().SingleInstance();
builder.RegisterType<SqlExceptionHandler>()
.As<IExceptionHandler<SqlException>>().SingleInstance();
builder.RegisterType<GeneralExceptionHandler>()
.As<IExceptionHandler<Exception>>().SingleInstance();
// ---- Business ------------------------------------
builder.RegisterType<UserBusiness>()
.As<IUserBusiness>().InstancePerRequest();
// ---- Validator -----------------------------------
builder.RegisterType<UserSignupModelValidator>()
.AsSelf().SingleInstance();
// ---- Controllers -----------------------------------
builder.RegisterType<DeflateCompressionActionFilter>()
.AsWebApiActionFilterFor<UserController>().InstancePerRequest();
base.Load(builder);
}
}
UserController.cs
[RoutePrefix("api/User")]
public class UserController : ApiController
{
private readonly IUserBusiness _userBusiness;
public UserController(IUserBusiness userBusiness)
{
_userBusiness = userBusiness;
}
...
}
I believe I'm missing some minor thing which I have no idea, any help would be appreciated.
Have a look on this answer: MVC Web API not working with Autofac Integration
Maybe you just need to do set you container like it was described on the link above:
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(container);
Theoretically you get a different exception but it could also be the case.

How to inject RoleManager

I need to inject RoleManager into Controller using Ninject in ASP.NET MVC 5 application. I am totally new in DI and Ninject, so I am not fully understand what Ninject do. I use Ninject 3.3.4, standard RoleManager from Identity 2.0 and EF6.2. My bindings are below:
public class NinjectRegistrations : NinjectModule
{
public override void Load()
{
Bind<HeroesContext>().ToSelf();
Bind<IRepository<Hero>>().To<HeroRepository>();
Bind<IRepository<Ability>>().To<AbilityRepository>();
Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>().WithConstructorArgument("context", new HeroesContext());
Bind<UserManager<ApplicationUser>>().ToSelf();
Bind<HttpContextBase>().ToMethod(ctx => new HttpContextWrapper(HttpContext.Current)).InTransientScope();
Bind<ApplicationSignInManager>().ToMethod(context =>
{
var cbase = new HttpContextWrapper(HttpContext.Current);
return cbase.GetOwinContext().Get<ApplicationSignInManager>();
});
Bind<ApplicationUserManager>().ToSelf();
Bind<IRoleStore<IdentityRole, string>>().To<RoleStore<IdentityRole, string, IdentityUserRole>>();
Bind<RoleManager<IdentityRole, string>>().ToSelf();
}
}
Before RoleManager I have successfully inject two repositories in HomeController, their work fine. Also I injected ApplicationUserManager in AdminController and AccountController and ApplicationSignInManager in AccountController, it seems their work fine too because I can log in. Current problem is connected with RoleManager, at first nothing worked at all. After some googling I found this question, it helped partly. Now when I try do get list of users using AdminController I get this and basic recommendations:
Ninject.ActivationException: Error activating DbConnection
No matching bindings are available, and the type is not self-bindable.
Activation path:
5) Injection of dependency DbConnection into parameter existingConnection of constructor of type DbContext
4) Injection of dependency DbContext into parameter context of constructor of type RoleStore{IdentityRole, string, IdentityUserRole}
3) Injection of dependency IRoleStore{IdentityRole, string} into parameter store of constructor of type RoleManager{IdentityRole, string}
2) Injection of dependency RoleManager{IdentityRole, string} into parameter roleManager of constructor of type AdminController
1) Request for AdminController
I tried to find solution, but found nothing useful. Below you can find code of AdminController's constructor, Application_Start() and context (I'm not sure it is needed). Please help, my hiring depends on this.
public class AdminController : Controller
{
private readonly ApplicationUserManager _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public AdminController(ApplicationUserManager userManager, RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
}
protected void Application_Start()
{
Database.SetInitializer<HeroesContext>(new DbInitializer());
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var registrations = new NinjectRegistrations();
var kernel = new StandardKernel(registrations);
kernel.Unbind<ModelValidatorProvider>();
DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));
}
public class HeroesContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Hero> Heroes { get; set; }
public DbSet<Ability> Abilities { get; set; }
public HeroesContext() : base("DefaultConnection", throwIfV1Schema: false)
{
}
public static HeroesContext Create()
{
return new HeroesContext();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Hero>().HasMany(n => n.Abilities)
.WithRequired(n => n.Hero)
.HasForeignKey(n => n.HeroId);
}
}
I guess that your RoleStore class is expecting dependency of type DbContext. And since you don't have any binding to DbContext, Ninject falls back to implicit self-binding. That means it tries to create DbContext trough the constructor:
public DbContext(DbConnection existingConnection, bool contextOwnsConnection)
but before that it can't create DbConnection as explained in the message.
Solution is:
change your binding: Bind<DbContext>().To<HeroesContext>();
or change type of the dependency in RoleStore toHeroesContext

Why is the identity not loaded when resolving WebApi but is when resolving Mvc controllers

I am using Autofac for an Inversion of Control container which is configured like this
public void Configuration(IAppBuilder app) {
configureIoC(app);
configureAuth(app);
}
void configureIoC(IAppBuilder app) {
var b = new ContainerBuilder();
//...
b.Register(c => HttpContext.Current?.User?.Identity
?? new NullIdentity()).InstancePerLifetimeScope();
var container = b.Build();
app.UseAutofacMiddleware(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
I believe the fact that this is Autofac versus some other container is probably irrelevant to what I'm seing. They key line here is the one configuring any dependency on IIdentity to be plucked from HttpContext.Current.
I use it like this so that I can have stub-able access to the current user anywhere I want.
public interface ICurrentUser {
Task<AppUser> Get();
}
public class CurrentUserProvider : ICurrentUser {
public async Task<AppUser> Get() => await users.FindByNameAsync(currentLogin.GetUserId());
public CurrentUserProvider(AppUserManager users, IIdentity currentLogin) {
this.users = users;
this.currentLogin = currentLogin;
}
}
I've used this pattern on past projects and it works fine. I'm currently applying it to an existing project and seeing a very strange thing.
When an Asp.net Mvc controller depends on ICurrentUser everything works fine
When a WebApi controller gets an instance of ICurrentUser the Get operation fails since the instance of IIdentity has not been parsed from the cookie and does not yet have Claims loaded into it (AuthenticationType == null)! Oddly, if I pause the debugger after the WebApi controller is instantiated I can hit HttpContext.Current.User.Identity and see that AuthenticationType == "Cookie" and all claims are there.
What this leads me to conclude is that somehow things are happening in the following order
If this is a web api route, the Web Api controller creates an instance
Asp.Net Identity fills out the current HttpContext Identity
If this is an mvc route, the mvc controller creates an instance
Any actions are executed
This of course makes no sense at all!
So the questions are as follows
Is my inference of the order of things in the pipeline correct?
How can I control it to work properly? Why would this have worked on other projects but be causing problems here? Am I wiring something up in the wrong order?
Please don't suggest that I create an IdentityProvider to late-resolve IIdentity. I understand how I can fix the issue, what I don't understand is why this is happening to begin with and how to control the pipeline order of things.
I modified your code just a little, since I don't have NullIdentity() and your CurrentUserProvider wasn't compiling here.
I'm installed these packages:
Autofac
Autofac.Owin
Autofac.Owin
Autofac.Mvc5
Autofac.Mvc5.Owin
Autofac.WebApi2
Autofac.WebApi2.Owin
My Startup.cs looks like this:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
configureIoC(app);
ConfigureAuth(app);
}
void configureIoC(IAppBuilder app) {
var b = new ContainerBuilder();
//...
b.RegisterType<CurrentUserProvider>().As <ICurrentUser>().InstancePerLifetimeScope();
b.Register(c => HttpContext.Current.User.Identity).InstancePerLifetimeScope();
b.RegisterControllers(typeof(MvcApplication).Assembly);
b.RegisterApiControllers(typeof(MvcApplication).Assembly);
var x = new ApplicationDbContext();
b.Register<ApplicationDbContext>(c => x).InstancePerLifetimeScope();
b.Register<UserStore<ApplicationUser>>(c => new UserStore<ApplicationUser>(x)).AsImplementedInterfaces().InstancePerLifetimeScope();
b.RegisterType<ApplicationUserManager>().InstancePerLifetimeScope();
b.RegisterType<ApplicationSignInManager>().InstancePerLifetimeScope();
var container = b.Build();
app.UseAutofacMiddleware(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
}
Your ICurrentUser stuff:
public interface ICurrentUser
{
Task <ApplicationUser> Get();
}
public class CurrentUserProvider : ICurrentUser
{
private ApplicationUserManager users;
private IIdentity currentLogin;
public async Task<ApplicationUser> Get()
{
return await users.FindByNameAsync(currentLogin.GetUserId());
}
public CurrentUserProvider(ApplicationUserManager users, IIdentity currentLogin)
{
this.users = users;
this.currentLogin = currentLogin;
}
}
Therefore Global.asax:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
My HomeController which is quite simple:
public class HomeController : Controller
{
private ICurrentUser current;
public HomeController(ICurrentUser current)
{
this.current = current;
}
public ActionResult Index()
{
var user = current.Get();
if (user == null)
throw new Exception("user is null");
return View();
}
}
...and finally a simple ApiController, which I access by typing localhost/api/TestApi/5:
public class TestApiController : ApiController
{
private ICurrentUser current;
public TestApiController(ICurrentUser current)
{
this.current = current;
}
public string Get(int id)
{
var user = current.Get();
if (user == null)
throw new Exception("user is null");
return "";
}
}
If I just start the project (without even logging in), I receive a GenericIdentity object to support IIdentity interface, look at this:
And when I step in (F11) in the Get() method, the IIdentity is properly set with that GenericIdentity, because actually there is no one Logged in the application. That's why I think you don't actually need that NullableIdentity.
Try comparing your code with mine and fix yours so we can see if it works, then eventually you'll find out what was the real cause of the problem, rather than just fixing it (we developers like to know why something just got working).

Unity injection into asp.net web api controllers and filters

I have WebForms project, and there I have WebApi controller.
How I can inject to controller constructor and to action filter constructor?
I have implemented IDependencyResolver and use it in Global.asax (GlobalConfiguration.Configuration.DependencyResolver), but it doesn't help:
on request controller says that there is no default constructor and filter on application start says that it does not contain a constructor that takes 0 arguments.
Moreover, i need singletone injection to action filter.
Thanks.
UPD
public class ScopeContainer : IDependencyScope
{
protected readonly IUnityContainer _container;
public ScopeContainer(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.IsRegistered(serviceType) ? _container.ResolveAll(serviceType) : new List<object>();
}
public void Dispose()
{
_container.Dispose();
}
}
public class IoCContainer : ScopeContainer, IDependencyResolver
{
public IoCContainer(IUnityContainer container) : base(container)
{
}
public IDependencyScope BeginScope()
{
var child = _container.CreateChildContainer();
return new ScopeContainer(child);
}
}
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
ConfigureApi(GlobalConfiguration.Configuration);
}
void ConfigureApi(HttpConfiguration config)
{
var unity = new UnityContainer();
unity.RegisterInstance<ILogger>(new Logger());
unity.RegisterType<IRepository, DbRepository>();
config.DependencyResolver = new IoCContainer(unity);
}
private static void RegisterRoutes()
{
RouteTable.Routes.MapHttpRoute("ServiceApi", "api/{controller}/{action}");
}
}
I think this may be the way you are registering your routes.
WebApi routes are registered in the default project examples via the GlobalConfiguration.Routes rather than the RouteTable.Routes which is used by MVC controllers. If the ApiController is being incorrectly loaded by the MVC routing method it won't find your dependency resolver.
Try modifying your code to this:
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(GlobalConfiguration.Configuration);
ConfigureApi(GlobalConfiguration.Configuration);
}
void ConfigureApi(HttpConfiguration config)
{
var unity = new UnityContainer();
unity.RegisterInstance<ILogger>(new Logger());
unity.RegisterType<IRepository, DbRepository>();
config.DependencyResolver = new IoCContainer(unity);
}
private static void RegisterRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute("ServiceApi", "api/{controller}/{action}");
}
}
I was having the same issue, I was working on a project trying to help modernize an old web forms project by converting page by page to Web API / Angular and getting the plumbing just right to use Unity was key.
When I was tracing I noticed unity was trying to resolve the controller classes but not the types to inject into their constructors, so I registered my controllers and it all worked. See my example below
Config setup, register controller and dependency
void ConfigureApi(HttpConfiguration config)
{
var container = UnitySingleton.UnityContainer;
container.RegisterType<IDashboardManager, ExampleStuff>();
container.RegisterType<DashboardController>(new InjectionConstructor(container.Resolve<IDashboardManager>()));
config.DependencyResolver = new UnityIoCContainer(container);
}
And my controller example:
public class DashboardController : ApiController
{
private readonly IDashboardManager _dashboardManager;
public DashboardController(IDashboardManager dashboardManager)
{
_dashboardManager = dashboardManager;
}
public async Task<IEnumerable<string>> Get()
{
return await _dashboardManager.GetDatas();
}
}
This is how I got mine working. It was a little different than the article above.

Resources