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.
Related
I have created a hub in my Web API. It is very simple:
public class DashboardHub : Hub
{
public async Task SendMessage(InfoSummary infoSummary)
{
await Clients.All.SendAsync("ReceiveMessage", infoSummary);
}
}
I am trying to send a message to the Hub from a controller in the same Web API when data is updated.
I have seen 100 different answers, and nothing works. Basically my hub object in my controller is null, and I can't seem to get it instantiated.
private readonly IRepository _repo;
private readonly Helpers.Convert _convert;
private readonly CoreContext _context;
private readonly IMapper _mapper;
private readonly NotifyService _service;
private readonly DashboardHub _hub;
public MyController(IRepository repo,
CoreContext context,
IMapper mapper)
{
_convert = new Helpers.Convert(repo, mapper);
_repo = repo;
_context = context;
_mapper = mapper;
_hub = new DashboardHub();
_service = new NotifyService(_hub);
}
[HttpPost("updatestatus")]
public async Task<IActionResult> UpdateStatus(Header header) {
var returnVal = await _repo.ChangeStatus(header.HeaderId, header.Status);
headerSummary = _convert.ToReturnStatusHeader( await _repo.GetHeader(header.HeaderId));
// await _service.SendNotificationAsync(headerSummary);
await _hub.SendMessage(headerSummary);
return Ok(returnVal);
}
I have the
services.AddSignalR();
services.AddScoped(typeof(DashboardHub));
and
endpoints.MapHub<DashboardHub>("/Hubs/DashboardHub");
in the proper sections in the startup.cs file
I know I am missing something very small, but I would love to know what it is.
I have also tried creating a strongly typed hub, but that introduced even more problems.
Thanks in advance.
You have done there or four mistakes.
You don't need this line to be in your ConfigureServices method of Startup.cs. services.AddScoped(typeof(DashboardHub));
Remove it. Just keep services.AddSignalR();
Why are you using new key word, since .net core provide in-built dependency
injection service. Remove below lines.
_hub = new DashboardHub();
_service = new NotifyService(_hub);
Instead create a new interface INotifyService.cs for NotifyService.cs.
Register this service in ConfigureServices method of Startup.cs.
services.AddScoped<INotifyService, NotifyService>();
Your MyController.cs should be like below
Add this line.
using Microsoft.AspNetCore.SignalR;
private readonly IRepository _repo;
private readonly Helpers.Convert _convert;
private readonly CoreContext _context;
private readonly IMapper _mapper;
private readonly INotifyService _service;
private readonly IHubContext<DashboardHub> _hubContext
public MyController(IRepository repo, CoreContext context, IMapper mapper,INotifyService service,IHubContext<DashboardHub> hubContext)
{
_convert = new Helpers.Convert(repo, mapper);
_repo = repo;
_context = context;
_mapper = mapper;
_service = service;
_hubContext = hubContext;
}
[HttpPost("updatestatus")]
public async Task<IActionResult> UpdateStatus(Header header) {
var returnVal = await _repo.ChangeStatus(header.HeaderId, header.Status);
headerSummary = _convert.ToReturnStatusHeader( await _repo.GetHeader(header.HeaderId));
// await _service.SendNotificationAsync(headerSummary);
await hubContext.Clients.All.SendAsync("ReceiveMessage", headerSummary);
return Ok(returnVal);
}
Use same concept if you are sending messages inside your NotifyService.cs.
Well, I feel like a complete and utter newb. The fix is very simple. You must add the using statement telling the controller you want to use SignalR. OMG.. I am almost too embarrassed to put this up, but hope it will help someone else.
FIX:
using Microsoft.AspNetCore.SignalR;
:facepalm
What you could do is inject your hub using dependency injection in your controller. You can't just instanciate the hub in the controller like you are doing, and I would change it to a Singleton also.
services.AddSingleton(typeof(DashboardHub));
internal DashboardHub DashboardHub
{
get
{
return this.HttpContext.RequestServices.GetRequiredService<DashboardHub>();
}
}
I'm currently following a .Net Core Angular 8 tutorial in Udemy. I'm able do get/post requests in Postman and I can also see what I've posted in a .db file using sqlite as my database and viewing the data through Db Browser. Everything seems to be working great but is all for nothing if I can't comprehend what's going on in some areas of the application. I would really appreciate it if someone could help me answer a few questions.
My entire project is in GitHub: https://github.com/cjtejada/ASP.NetCoreAngular8/tree/master/DatingApp.API
Problem 1: I have the following the following controller:
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly IAuthRepository _repo;
private readonly IConfiguration _config;
public AuthController(IAuthRepository repo, IConfiguration config)
{
_repo = repo;
_config = config;
}
[HttpPost("register")]
public async Task<IActionResult> Register(UserForRegisterDto userForRegisterDto)
{
// validate request
userForRegisterDto.Username = userForRegisterDto.Username.ToLower();
if (await _repo.UserExists(userForRegisterDto.Username))
return BadRequest("User already exists");
var userToCreate = new User
{
Username = userForRegisterDto.Username
};
var createdUser = await _repo.Register(userToCreate, userForRegisterDto.Password);
return StatusCode(201);
}
}
I know that when the client makes a request to register, the register() method will be called and the Username that gets passed in will set the Username from DTO userForRegisterDto. After this then we call method UserExists() to check if the user exists in our database.
Question 1:
How is _repo aware of the logic in method UserExists() when it is only using the interface IAuthRepository? I know that IAuthRepository and class AuthRepository are somehow linked but I don't see anywhere in the app where Constructor DI is happening. My suspicion is that it has something to do with this line in startup.cs under the ConfigureServices method :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(x => x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors();
services.AddScoped<IAuthRepository, AuthRepository>(); //<---- This Line
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
After these two are "linked up", then the UserExists() method can be accessed through the AuthRepository class:
public class AuthRepository : IAuthRepository
{
private readonly DataContext _context;
public AuthRepository(DataContext context)
{
_context = context;
}
public async Task<User> Login(string username, string password)
{
}
private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
}
public async Task<User> Register(User user, string password)
{
byte[] passwordHash, passwordSalt;
CreatePasswordHash(password, out passwordHash, out passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
await _context.Users.AddAsync(user);
await _context.SaveChangesAsync();
return user;
}
private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
}
public async Task<bool> UserExists(string username)
{
if (await _context.Users.AnyAsync(x => x.Username == username))
return true;
return false;
}
}
I've been reading about the AddScoped method and what it does but this is not clear to me that this is the case. Any clarification as to how this works would be great.
Problem 2:
This one is more or less the same. If we keep following the path of the request we will hit the register() method in the AuthRepository class.
Question 2:
How does this class have access to the properties of DataContext _context when I also can't spot any instances of constructor DI anywhere?
Here are the rest of my project files if needed:
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(x => x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors();
services.AddScoped<IAuthRepository, AuthRepository>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
app.UseAuthentication();
app.UseMvc();
}
}
DataContext.cs
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> options) : base (options){}
public DbSet<Value> Values { get; set; }
public DbSet<User> Users { get; set; }
}
Any clarifications and suggestions are greatly appreciated. Thanks, all.
You are correct. The line services.AddScoped<IAuthRepository, AuthRepository>(); simply instructs the ASP.NET Core service container to substitute an instance of concrete class AuthRepository wherever it sees a reference to IAuthRepository at runtime.
The various Add* methods all do the same thing under the hood regarding registering the mapping of interfaces => classes, the key difference is the scope of the created class, i.e. how long it persists for:
AddScoped classes will be created at the beginning of every request to the server, and destroyed at the end of every request. In other words, every request results in a new instance of that class being created.
AddSingleton classes are created when your ASP.NET Core application starts up, and are destroyed when it shuts down. In other words, only a single instance of that class exists within your application.
AddTransient classes are recreated whenever they are requested. In other words, if a page on your site used the same service transient twice, there would be two instances created. (Contrast this with a scoped service, where only a single instance would be created, as each page is a single request.)
A fuller explanation, including examples: https://stackoverflow.com/a/38139500/70345
In order to fulfill (1) by creating an instance of your class AuthRepository, the service container needs to call that class's constructor. The container inspects your class to find the first public constructor and retrieves any arguments to that constructor, in this case an instance of the DataContext class. The container then searches its internal class mappings for that class and, because you have registered that mapping via services.AddDbContext<DataContext>(...), is able to construct and return the class instance. Thus it's able to pass that instance to AuthRepository, so AuthRepository is constructed successfully.
The AddDbContext method is simply a wrapper around AddScoped, that performs some additional scaffolding to allow Entity Framework DbContexts to work correctly.
For the official explanation, refer to Microsoft's official page on DI and IoC.
Question 1 - You've right this line in Startup.cs provide creating a new object AuthRepository. For this example you must to know that DI container creates an AuthRepository object for you based on the interface and his own implementation and you only need to pass an interface in properly constructor. AddScope() is related with lifetime of created objects. When you register object by method AddScope() then the object will be created for a single request and after the request, the object will be disposed.
Question 2 - Your dbContext is registered in DI container. AddDbContext() is a specific extension method provided to registration of entity framework dbContextes. This line of code registers your dbContext with connection strings got from the appSetting.json file.
services.AddDbContext<DataContext>(x =>
x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
This DbContext is injected into the constructor of the AuthRepository class and when you use this class DI container created DbContext instance for you.
private readonly DataContext _context;
public AuthRepository(DataContext context)
{
_context = context;
}
I'm learning .Net Core SignalR and investigating how I could use it with my app live charts. I play with some examples on the net and they all work, but I don't know how to use SignalR with database polling. I'm getting below error:
Cannot access a disposed object ...
I'm assuming it is related to my contex is being disposed after request is completed. I'm using dependency injection.
ChatController
public class ChatController : ControllerBase
{
private IChatService _chatService;
private IChatContext<ChatHub> _hub;
public ChatController(IChatContext<ChatHub> hub, IChatService chatService)
{
_hub = hub;
_chatService = chatService;
}
public IActionResult Get()
{
var timerManager = new TimerManager(() => _hub.Clients.All.SendAsync("transferchatdata", _chatService.ChatDataByProds()));
return Ok(new { Message = "Request Completed" });
}
}
ChatService
public interface IChatService
{
IEnumerable<ChatDataByProd> ChatDataByProds();
}
public class ChatService : IChatService
{
private ChatContext _context;
public ChatService(ChatContext context)
{
_context = context;
}
public IEnumerable<ChatDataByProd> ChatDataByProds()
{
return _context.ChatDataByProds;
}
}
ChatHub
public class ChatHub : Hub
{
}
It seems that you are using a EF Core context that is a scoped lifetime service, which means per-request lifetime in ASP.NET Core. Your ChatService must have a longer lifetime than a HTTP request, and a single instance of the database context would be disposed by the container while you are still holding the reference to it.
Thus, you need to obtain an IServiceProvider container in the ctor of ChatService, and GetService the database context each time when you need to access the database.
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
I can get details of logged in user from controller injecting IHttpContextAccessor httpContextAccessor. But when I try it in my service, it does not work. I get these error
{System.Exception: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you a...
What I have done is create an IUserService interface. Then added GetUser method there with its implementation as:
public class UserService : IUserService
{
private readonly IHttpContextAccessor _context;
private readonly UserManager<User> _userManager;
public UserService(IHttpContextAccessor context, UserManager<User> userManager)
{
_context = context;
_userManager = userManager;
}
public async Task<User> GetUser()
{
return await _userManager.FindByNameAsync(_context.HttpContext.User.Identity.Name);
}
}
I have added services.AddSingleton<IUserService, UserService>(); in my IServiceCollection too.
Don't add UserService as a singleton. It has an injected UserManager that itself has an injected DbContext that will explode if you try to use it like this and it is almost certainly getting disposed so on second use it won't work. Instead you are safest adding it as a transient object:
services.AddTransient<IUserService, UserService>();
To add to this, you must consider your hierarchy of objects. If a singleton object has a transient one injected into it, that transient object will remain with the singleton for the lifetime and will likely be disposed by the DI framework, leaving your singleton in an unsafe state.