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
Related
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.
I have a multi-layer application that I started writing in ASP.NET Core 1.1 which I'm still learning along the way. I have organized it like previous apps I've done in the Web API, I have host service (net core app), business layer and data layer that is above database. Business and data layers were net core standard libraries, but when I wanted to add entity framework I had to modify data layer to look like net core app, so now I have Startup.cs with configurations there. That allowed me to configure entity framework service and to create migrations in the data layer. But now I have a problem as I wanted to add asp.net identity. Every tutorial on the net is about SPAs that have everything in one project.
I have added identity to Startup.cs and database is generated well
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddEntityFramework(connectionString);
services.AddMyIdentity();
services.Configure<IdentityOptions>(options =>
{
// Password settings
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = false;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
// User settings
options.User.RequireUniqueEmail = true;
});
}
public void Configure(IApplicationBuilder app)
{
app.UseIdentity();
}
but now I need to use UserManager from a class that is not a Controller and I don't know how to deal with dependency injection.
To explain better, I have an Account controller in my Host Service
[HttpPost]
[Route("Register")]
public async Task<IActionResult> Register([FromBody]RegisterUserDto dto)
{
var result = await Business.Commands.Accounts.Register(dto);
return Ok(result);
}
Business layer just calls the Data layer
public async static Task<ResponseStatusDto> Register(RegisterUserDto dto)
{
// some code here
var identityLogon = await Data.Commands.ApplicationUsers.Register(dto);
// some code here as well
return new ResponseStatusDto();
}
Now the question is, how do I get UserManager in the Data Register method? It's a simple class, it doesn't inherit from a controller, dependency injection is not working for constructors like in the examples found here
Core Identity
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ISmsSender _smsSender;
private static bool _databaseChecked;
private readonly ILogger _logger;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
}
//
// GET: /Account/Login
So, how do I pass UserManager that is configured in Startup to some random class somewhere in the middleware? I have seen this question, but the answer to just pass null values to UseManager constructor is not working nor I think it's good.
//EDIT as per Set's answer
I have removed all static references, but I'm still not quite there. I have followed this dependency injection instructions, but I'm not sure how to instantiate and call Add method.
I have created an interface
public interface IIdentityTransaction
{
Task<IdentityResult> Add(ApplicationUser appUser, string password);
}
and implemened it
public class IdentityTransaction : IIdentityTransaction
{
private readonly ApplicationDbContext _dbContext;
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public IdentityTransaction(ApplicationDbContext context, UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
{
_roleManager = roleManager;
_userManager = userManager;
_dbContext = context;
}
public async Task<IdentityResult> Add(ApplicationUser applicationUser, string password)
{
return await _userManager.CreateAsync(applicationUser, password);
}
}
then I injected it to a service collection in Startup.cs
services.AddScoped<IIdentityTransaction, IdentityTransaction>();
but how to call Add method from IdentityTransaction service?
I cannot instantiate it nor use dependency injection on constructor as it just loops my problem. #Set mentioned
or pass UserManager userManager as parameter to method
pass it from where?
I think I'm very close, but I'm missing something.
I have tried using
IIdentityTransaction it = services.GetRequiredService<IIdentityTransaction>();
but services which is IServiceProvider is null, I don't know where to get it from either.
DI in ASP.NET Core works the same for controller and non-controller classes using "constructor injection" approach.
You have the problem as Register method is static, so doesn't have access to instance variables/properties. You need to
make Register method non-static
or pass UserManager<ApplicationUser> userManager as parameter to method
In general, you should avoid using static classes for business logic as they don't help to test your code properly and produce the code coupling. Search via internet/SO and you will find a lot of topics why static is bad.
Use DI to get the instance of Data.Commands.ApplicationUsers class in your controller. If you need only one instance of this class for your application - use singleton lifetime for it.
Update. Again, use constructor injection: modify your "Data Layer" class so it can get the instance of IIdentityTransaction as constructor parameter:
public class YourDataLayerClass : IYourDataLayerClass
{
private IIdentityTransaction _identityTransaction;
public YourDataLayerClass(IIdentityTransaction identityTransaction)
{
_identityTransaction = identityTransaction;
}
public void MethodWhereYouNeedToCallAdd()
{
_identityTransaction.Add(...);
}
}
And idea the same for IYourDataLayerClass instance: register dependency
services.AddScoped<IYourDataLayerClass, YourDataLayerClass>();
and then the class (middleware in your case, if I understand you properly) that depends on it should receive that instance via constructor:
public class YourMiddleware
{
private IYourDataLayerClass _yourDataLayerClass;
public YourMiddleware(IYourDataLayerClass yourDataLayerClass)
{
_yourDataLayerClass = yourDataLayerClass;
}
...
}
Yes you are very close.
First thing, either remove context parameter from the IdentityTransaction constructor as in your code snipped it appears to be useless. Or if you plan to use it later, declare it in the DI container:
services.AddScoped<ApplicationDbContext, ApplicationDbContext>();
Second thing, you simply need to add IIdentityTransaction as a dependency in the controller's constructor, and remove SignInManager and UserManager from its dependencies as eventually you won't use these directly within the controller:
public class AccountController : Controller
{
private readonly IEmailSender _emailSender;
private readonly ISmsSender _smsSender;
private static bool _databaseChecked;
private readonly ILogger _logger;
IIdentityTransaction _identityTransaction;
public AccountController(
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory,
IIdentityTransaction identityTransaction)
{
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
_identityTransaction = identityTransaction;
}
If you need an additional business layer (IBusinessLayer) between the controller, same process, declare the class in the DI container at startup, add IIdentityTransaction as a dependency in the business class constructor, and update the controller's dependencies from IIdentityTransaction to IBusinessLayer.
A couple more precisions.
services.AddScoped<IIdentityTransaction, IdentityTransaction>();
This piece of code does NOT inject instances or dependencies. It declares an interface and its associated implementation in the DI container, so it can be injected later when required. Actual instances are injected when the objects that required them are actually created. I.e. the controller gets its dependencies injected when it is instantiated.
IIdentityTransaction it = services.GetRequiredService<IIdentityTransaction>();
What you tried to do here is called the dependency locator pattern, and is often considered as an anti-pattern. You should stick to dependency injection via the constructor, it's much cleaner.
The key is to declare everything in the DI container at startup, even your custom business/data layers classes, never instantiate them yourself anymore, and declare them as required dependencies in any classes' constructor that need them.
I have a Asp.Core project with dependency injection. The problem is that when I get an instance of a CustomerService my session is null. But I pass it through with dependency injection.
My Controller looks like this:
private ISessionService _sessionService;
private IContainer _container;
public AuthController(ISessionService sessionService, IContainer container) {
_container = container;
_sessionService = sessionService;
// here my session is NOT NULL
string userName = _sessionService.Username;
}
public IActionResult Index() {
// here I have some code so the line below is not always needeed and therefore not injected in the constructor
IUserService userService = _container.GetInstance<IUserService>();
// here my session is NULL
string name = userService.GetUserName();
}
public class UserService : IUserService {
private ISessionService _sessionService;
private IHttpContextAccessor _httpContextAccessor;
public UserService(ISessionService sessionSerivce, IHttpContextAccessor httpContextAccessor) {
_sessionService = sessionSerivce;
_httpContextAccessor = httpContextAccessor;
}
public string GetUserName() {
return _sessionService.User.Name;
}
}
my StartUp.cs where I'm using StructureMap
Container container = new Container(expr => {
expr.For<IHttpContextAccessor>().Use<HttpContextAccessor>();
expr.For<ISessionService>().Use<SessionService>();
expr.For<IUserService>().Use<UserService>();
});
So why is my session null when I instantiate a UserService object when using the container class ?
UPDATE
I know now that the Session object is null because the life cycle of a MVC page. In my BaseController class I created a method named InitContainer like this:
public void InitContainer(Type typeOfInterface, Type typeOfClass) {
Configure(expr =>
For(typeOfInterface).Use(typeOfClass)
.Ctor<ISessionService>().Is(_sessionService)
.Ctor<IHttpContextAccessor>().Is(_httpContextAccessor)
);
}
}
When I want to use an instance of a service than I do this in my Controller method:
public IActionResult Test() {
InitContainer(typeof(ICustomerService), typeof(CustomerService));
ICustomerService customerService = _container.GetInstance<ICustomerService>();
}
I don't know if it's ugly or the right way to do this, but it works for me now.
Has someone a better way to do this?
I have a problem with the Automapper on my website and I can't find a solution.
I've created a class called AutoMapperProfile where I'd like to put all my Maps
public class AutoMapperProfile: Profile
{
private readonly IConfiguration _mapper;
public AutoMapperProfile(IConfiguration mapper)
{
_mapper = mapper;
}
protected override void Configure()
{
base.Configure();
_mapper.CreateMap<SlideDTO, Slide>();
_mapper.CreateMap<Slide, SlideDTO>();
}
}
For DI purposes I'm using Ninject, so I've added the following bindings in NinjectWebCommon:
kernel.Bind<IMappingEngine>().ToMethod(ctx => Mapper.Engine);
kernel.Bind<IConfigurationProvider>().ToMethod(x => Mapper.Engine.ConfigurationProvider);
The controller looks like this:
private readonly ISlideRepository slideRepository;
private readonly IMappingEngine mappingEngine;
public HomeController(
ISlideRepository slideRepository,
IMappingEngine mappingEngine)
{
this.slideRepository = slideRepository;
this.mappingEngine = mappingEngine;
}
[HttpGet]
public ActionResult Index()
{
var model = new IndexViewModel();
var slide = slideRepository.GetSlide();
model.Slide = mappingEngine.Map<SlideDTO, Slide>(slide);
return View(model);
}
When I map from SlideDTO to Slide I get the following error:
Missing type map configuration or unsupported mapping.
So my best guess is that I didn't do the binds correctly so that Automapper can see my maps, but I'm not sure how can I fix it.
You don't need to inject IConfiguration into AutoMapperProfile, it already inherits a CreateMap method from Profile.
Make sure that AutoMapperProfile has a parameterless constructor like this:
public class AutoMapperProfile : Profile
{
protected override void Configure()
{
this.CreateMap<SlideDTO, Slide>();
this.CreateMap<Slide, SlideDTO>();
}
}
And then you need to make sure that AutoMapper knows about this profile, here is how you can do it:
Mapper.Engine.ConfigurationProvider.AddProfile<AutoMapperProfile>();
Please note that you can invoke the AddProfile method on any IConfigurationProvider (if you decide not to use the global ConfigurationProvider and Engine).
I have an application with a GenericHandler and would like to inject dependencies using Unity. No matter what I try I get the error:
[MissingMethodException: No parameterless constructor defined for this object.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean
I have tried to follow the example at http://geekswithblogs.net/Rhames/archive/2012/09/11/loosely-coupled-.net-cache-provider-using-dependency-injection.aspx.
My constructor for the handler is as follows:
public class GetPerson : IHttpHandler
{
private IPersonRepository repo;
public GetPerson(IPersonRepository repo)
{
this.repo = repo;
}
IPersonRepository is implemented by CachedPersonRepository. CachedPersonRepository wraps the PersonRepository (which is used for DataAccess if an item cannot be found in the cache). Both CachedPersonRepository and PersonRepository are IPersonRepository:
public class CachedPersonRepository : IPersonRepository
{
private ICacheProvider<Person> cacheProvider;
private IPersonRepository personRepository;
public CachedPersonRepository(IPersonRepository personRepository, ICacheProvider<Person> cacheProvider)
{
This IPersonRepository personRepository is parameterless.
ICacheProvider<Person> is implemented by MemcachedCacheProvider<T>:
public class MemcachedCacheProvider<T> : ICacheProvider<T>
{
public T Get(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan relativeExpiry)
{
I have tried unsuccessfully to initialise the Unity Container in my Global.asax file Application_Start. DI is new to me and I would very much appreciate any advice on where I'm going wrong.
There were actually two issues here.
Firstly, CachedPersonRepository uses the Decorator pattern which I didn't properly understand before. Once I understood this I was able to register and resolve the PersonRepository appropriately using this configuration:
public static void Configure(IUnityContainer container)
{
container.RegisterType<ICacheProvider<Person>, MemcachedCacheProvider<Person>>();
container.RegisterType<IPersonRepository, PersonRepository>("PersonRepository", new ContainerControlledLifetimeManager());
container.RegisterType<IPersonRepository, CachedPersonRepository>(
new InjectionConstructor(
new ResolvedParameter<IPersonRepository>("PersonRepository"),
new ResolvedParameter<ICacheProvider<Person>>()));
container.Resolve<IPersonRepository>();
}
Having fixed this I still saw the same "No parameterless constructor defined for this object" error.
The reason for this, is that I was working with an IHttpHandler and it is not possible to inject dependencies in the constructor.
I got around this by using Property injection:
A Repository property with the Dependency Attribute has been added to the GetPerson handler:
public class GetPerson : HandlerBase
{
[Dependency]
public IPersonRepository Repository { get; set; }
A new http module was needed to check for requests from handlers which implemented my HandlerBase:
public class UnityHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
}
public void Dispose() { }
private void OnPreRequestHandlerExecute(object sender, EventArgs e)
{
IHttpHandler currentHandler = HttpContext.Current.Handler as HandlerBase;
if (currentHandler != null)
{
HttpContext.Current.Application.GetContainer().BuildUp(
currentHandler.GetType(), currentHandler);
}
}
}
Resources:
http://download.microsoft.com/download/4/D/B/4DBC771D-9E24-4211-ADC5-65812115E52D/DependencyInjectionWithUnity.pdf (Chapter 4, pages 60-63)
http://msdn.microsoft.com/en-us/library/ff664534(v=pandp.50).aspx