Why is my Controller being passed a UserManager which is Disposed? - asp.net-core-mvc

When i set a breakpoint in the constructor of this controller, I'm seeing a System.ObjectDisposedException from userManager.Users . Why might .NET be giving me a disposed UserManager? I have other controllers that seem to be set up the same way and their UserManagers work fine (this one dies when it calls GetUserAsync)
[RequireHttps]
public class HomeController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RegionService _regionService;
private readonly ILogger _logger;
public HomeController(UserManager<ApplicationUser> userManager, RegionService regionService, ILoggerFactory loggerFactory)
{
_userManager = userManager;
_regionService = regionService;
_logger = loggerFactory.CreateLogger<HomeController>();
}
[HttpGet]
public async Task<IActionResult> Index()
{
var user = await _userManager.GetUserAsync(HttpContext.User);
...
}
...and i shouldn't be accessing a database in Home/Index; I'll change that afterward
Edit: This is how services are being configured:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 6;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
services.Configure<AuthMessageSenderOptions>(Configuration);
services.AddTransient<RegionService>();
// require SSL
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
});
}

The issue was in the constructor of a class I created called RegionService
public RegionService(IServiceProvider serviceProvider)
{
using (var context = serviceProvider.GetService<ApplicationDbContext>())
{
...
}
}
The 'using' statement causes 'context' to be disposed after it's done with that block of code. I should have just been making a new instance of the DbContext that can be disposed:
public RegionService(IServiceProvider serviceProvider)
{
using (var context = new ApplicationDbContext(
serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
{
...
}
}

Related

how to fix Error No DataBase Provider when Everything is okay

When I want to Insert A New Object into the db bellow Error Occured:
No database provider has been configured for this DbContext
Services:
private IConfiguration config;
public Startup(IConfiguration config) => this.config = config;
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkSqlServer().AddDbContext<DataContext>(options => options.UseSqlServer(config["ConnectionStrings:MainConnection"]));
services.AddMvc();
}
DataContext:
public class DataContext:DbContext
{
public DataContext() { }
public DataContext(DbContextOptions<DataContext> options) : base(options) { }
public DbSet<Request> Request { get; set; }
public DbSet<AdminAccept> AdminAccept { get; set; }
public DbSet<Payment> Payment { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
base.OnConfiguring(builder);
}
}
Insert command :
public async Task <int> SaveToStorageAsync()
{
using (DataContext context=new DataContext())
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
}
however migrations and database created succefully
I solved it finally.
everything is okay but use of using expression cause an error.(I wonder why)
to solving it first of all I removed a using and declare a DataContext as parameter:
public async Task<int> SaveToStorageAsync(DataContext context)
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
after it initiate constructor in the main controller :
DataContext context;
public HomeController(DataContext context)
{
this.context = context;
}
and finally call function by sending context as a parameter.
hopped you used in your scenarios and good luck
Since you register the DataContext with the constructor receiving a DbContextOptions<DataContext> option.You also need to pass that when you create a DataContext
var optionsBuilder = new DbContextOptionsBuilder<DataContext >();
optionsBuilder.UseSqlServer("Your connection string");
using (DataContext context = new DataContext (optionsBuilder.Options))
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
I suggest that you could use dbContext by DI in controller which is a more recommended way in asp.net core:
public class StudentsController : Controller
{
private readonly DataContext _context;
public StudentsController(DataContext context)
{
_context = context;
}
public async Task <int> SaveToStorageAsync()
{
_context.Request.Add(this);
return await context.SaveChangesAsync();
}
}
The two ways are included in below link:
https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext#configuring-dbcontextoptions

Dependency is not getting resolved in WebAPI (including OWIN) with Autofac

My global.asax looks like below
private void BuildIocContainer()
{
var builder = new ContainerBuilder();
builder.RegisterModule(new BootstrapModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); //Set the WebApi DependencyResolver
}
protected void Application_Start()
{
BuildIocContainer();
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
I have built a bootstrap module for autofac like the one below
public class BootstrapModule : Autofac.Module
{
private Assembly AssemblyOf<T>()
{
return typeof(T).Assembly;
}
private Assembly WebAssembly
{
get { return Assembly.GetExecutingAssembly(); }
}
private void RegisterMvc(ContainerBuilder builder)
{
builder.RegisterType<AsyncControllerActionInvoker>()
.As<IActionInvoker>();
builder.RegisterControllers(WebAssembly)
.InjectActionInvoker();
builder.RegisterApiControllers(WebAssembly).InjectActionInvoker();
}
private void RegisterLogger(ContainerBuilder builder)
{
builder.Register(CreateLogger)
.SingleInstance();
builder.Register(_ => new NLogWrapper(LogManager.GetLogger("DefaultLogger")))
.As<Logging.ILogger>()
.SingleInstance();
}
private static System.Func<Type, Logging.ILogger> CreateLogger(IComponentContext componentContext)
{
return type => new NLogWrapper(LogManager.GetLogger(type.FullName));
}
protected override void Load(ContainerBuilder builder)
{
RegisterLogger(builder);
RegisterMvc(builder);
builder.RegisterAssemblyTypes(WebAssembly)
.AsImplementedInterfaces();
builder.RegisterType<UserService>()
.As<IUserService>()
.InstancePerRequest();
builder.RegisterAssemblyTypes(typeof(IUserService).Assembly)
.AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(IUserRepository).Assembly)
.AsImplementedInterfaces();
builder.RegisterFilterProvider();
}
}
Now, when I try to hit account controller through postman client,
private IUserService _userService;
public AccountController(IUserService userService)
{
_userService = userService;
}
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public HttpStatusCode Register(User model)
{
if (!ModelState.IsValid)
{
return HttpStatusCode.BadRequest;
}
// TODO : Write mapper if needed
var user = new ToolUser()
{
FirstName = model.FirstName,
LastName = model.LastName,
EmailID = model.EmailID,
DOB = Convert.ToDateTime(model.DateOfBirth),
Gender = model.Gender.ToString(),
TenandID = model.TenantID,
Password = model.Password
};
HttpStatusCode result = _userService.RegisterUser(user);
return result;
}
I get the error
"An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor."
What am I doing wrong?
You should have something like
HttpConfiguration config = new HttpConfiguration();
somewhere, which you use to register your routes etc.
Pass that config to your BuildIocContainer() mehod and add the line
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
instead of
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); //Set the WebApi DependencyResolver
Hope that helps

Simple Injector: Implementation that depends on http request

I'm a beginner with Simple Injector and have a scenario where I need help to implement. I will try to simplify what I need to do.
I have a WebAPI where I need to authenticate users and based on the type of user choose an implementation.
Consider this structure
public interface ICarRepository {
void SaveCar(Car car);
}
//Some implementation for ICarRepository
public interface ICarLogic {
void CreateCar(Car car);
}
public class CarLogicStandard: ICarLogic {
private ICarRepository _carRepository;
public CarLogicStandard(ICarRepository carRepository) {
_carRepository = carRepository;
}
public void CreateCar(Car car) {
car.Color = "Blue";
_carRepository.SaveCar();
//Other stuff...
}
}
public class CarLogicPremium: ICarLogic {
private ICarRepository _carRepository;
public CarLogicPremium(ICarRepository carRepository) {
_carRepository = carRepository;
}
public void CreateCar(Car car) {
car.Color = "Red";
_carRepository.SaveCar();
//Other stuff 2...
}
}
And now I have a controller
public class CarController: ApiController {
private ICarLogic _carLogic;
public CarController(ICarLogic carLogic) {
_carLogic = carLogic;
}
public void Post(somePostData) {
//Identify the user based on post data
//....
Car car = somePostData.SomeCar();
_carLogic.CreateCar(car);
}
}
The code above will not work because in my request I need to identify the user. If it is a premium user the controller should use the CarLogicPremium and if it is a standard user the controller should use the CarLogicStandard.
I can configure the repository and others interfaces that don't need this logic on Global.asax however, since this case I need the request to decide which implementation should be used, I supose that I need to solve this in some other way.
There is a "Simple Injector" way to handle this? Or should I try another approach?
The simplest solution would be to configure the decision in the composition root, along with the rest of the container's configuration:
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
var container = new Container();
container.Register<CarLogicStandard>();
container.Register<CarLogicPremium>();
container.RegisterPerWebRequest<ICarRepository, CarRepository>();
container.Register<ICarLogic>(
() =>
HttpContext.Current != null &&
HttpContext.Current.User != null &&
HttpContext.Current.User.IsInRole("Premium")
? (ICarLogic)container.GetInstance<CarLogicPremium>()
: (ICarLogic)container.GetInstance<CarLogicStandard>()
);
// This is an extension method from the integration package.
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
}
You could also create an abstraction over the current user and decorate standard features with premium features
public class CarLogicPremium : ICarLogic
{
private readonly ICarLogic decorated;
private readonly ICurrentUser currentUser;
private readonly ICarRepository carRepository;
public CarLogicPremium(
ICarLogic decorated,
ICurrentUser currentUser,
ICarRepository carRepository)
{
this.decorated = decorated;
this.currentUser = currentUser;
this.carRepository = carRepository;
}
public void CreateCar(Car car)
{
if (currentUser.IsPremiumMember)
{
car.Color = "Red";
this.carRepository.SaveCar(car);
//Other stuff 2...
}
else
{
this.decorated.CreateCar(car);
}
}
}
which would be configured a bit like this
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
var container = new Container();
container.Register<ICurrentUser, HttpCurrentUserProxy>();
container.RegisterPerWebRequest<ICarRepository, CarRepository>();
container.Register<ICarLogic, CarLogicStandard>();
container.RegisterDecorator(typeof(ICarLogic), typeof(CarLogicPremium));
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
}
But it really depends how many variations of services you will be creating over time. If you will be constantly adding new premium features you should look to implement a variation of the Try-X pattern. Let me know if one of the above works for you or if you need more info ...

Ninject binding to IKernel fails in ApiController with error "Error loading Ninject component ICache"

I have the following simple ApiController example that is failing.
public class TestAPIController : ApiController
{
public TestAPIController(IKernel kernel) { }
[HttpGet]
public string Test()
{
return "success! " + DateTimeOffset.Now.ToString("F");
}
}
This gives me the error:
Error loading Ninject component ICache
No such component has been registered in the kernel's component container.
I have the package Ninject.WebApi.DependencyResolver installed but it is still failing.
Here is my CreateKernel class in NinjectWebCommon:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel(new VBNinjectModule());
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
//GlobalConfiguration.Configuration.DependencyResolver = new VBNinjectDependencyResolver(kernel);
GlobalConfiguration.Configuration.DependencyResolver = new Ninject.WebApi.DependencyResolver.NinjectDependencyResolver(kernel);
return kernel;
}
Using:
Ninject 3.0.1.10
Ninject.MVC3 3.0.0.6
Ninject.Web.Common: 3.0.0.7
Ninject.WebApi.DependencyResolver 0.1.4758.24814
Thanks in advance for the help.
Cheers!
You do not want to inject IKernel to a controller. Instead, you want to register your service, and inject that service to the controller.
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
GlobalConfiguration.Configuration.DependencyResolver =
new NinjectDependencyResolver(kernel);
return kernel;
}
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMyService>().To<MyService>().InRequestScope();
}
// Your api controller
public class TestAPIController : ApiController
{
private readonly IMyService _myService ;
public TestAPIController(IMyService myService)
{
_myService = myService;
}
}

Castle Windsor: master controller not resolving the registered components in the container

Having the code below in my Global.asax.cs and two controller (one based on a the other: MasterController) I don't seem to find how can I resolve the repository register in my WindsorContainer from the MasterController... the same applies in the HomeController and works perfectly... what am I doing wrong?
Global.asax.cs:
private IWindsorContainer _container;
protected void Application_Start()
{
InitializeContainer();
RegisterRoutes(RouteTable.Routes);
}
protected void Application_End()
{
this._container.Dispose();
}
protected void Application_EndRequest()
{
if (_container != null)
{
var contextManager = _container.Resolve<IContextManager>();
contextManager.CleanupCurrent();
}
}
private void InitializeContainer()
{
_container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_container));
// Register context manager.
_container.Register(
Component.For<IContextManager>()
.ImplementedBy<EFContextManager>()
.LifeStyle.Singleton
.Parameters(
Parameter.ForKey("connectionString").Eq(ConfigurationManager.ConnectionStrings["ProvidersConnection"].ConnectionString)
)
);
//Products repository
_container.Register(
Component.For<IProductRepository>()
.ImplementedBy<ProductRepository>()
.LifeStyle.Singleton
);
// Register all MVC controllers
_container.Register(AllTypes.Of<IController>()
.FromAssembly(Assembly.GetExecutingAssembly())
.Configure(c => c.LifeStyle.Transient)
);
}
Controller base:
public class MasterController : Controller
{
private IProductRepository _productRepository;
public ProductController(IProductRepository product)
{
_productRepository = product;
}
public ActionResult Index()
{
ViewData["product"] = _productRepository.FindOne(123);
return View();
}
}
Controller based on MasterController:
public class ProductController : MasterController
{
private IProductRepository _productRepository;
public ProductController(IProductRepository product)
{
_productRepository = product;
}
public ActionResult Search(int id)
{
ViewData["product"] = _productRepository.FindOne(id);
return View();
}
}
It is working as expected now and the ViewDatas are accessible from any controller/view.
First I created a public class where I store my Windsor container so it can be accessed from any controller:
public static class IOCcontainer
{
public static IWindsorContainer Container { get; set; }
}
Then in my global.asax.cs I have:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
InitializeContainer();
}
private void InitializeContainer()
{
_container = new WindsorContainer();
// Register context manager.
_container.Register(
Component.For<IContextManager>()
.ImplementedBy<EFContextManager>()
.LifeStyle.Singleton
.Parameters(
Parameter.ForKey("connectionString").Eq(ConfigurationManager.ConnectionStrings["ProvidersConnection"].ConnectionString)
)
);
//Products repository
_container.Register(
Component.For<IProductRepository>()
.ImplementedBy<ProductRepository>()
.LifeStyle.Singleton
);
// Register all MVC controllers
_container.Register(AllTypes.Of<IController>()
.FromAssembly(Assembly.GetExecutingAssembly())
.Configure(c => c.LifeStyle.Transient)
);
IOCcontainer.Container = _container; //set the container class with all the registrations
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_container));
}
So now in my master controller I can use:
public class MasterController : Controller
{
private IProductRepository g_productRepository;
public MasterController() : this(null,null,null,null,null)
{
}
public MasterController(IProductRepository productRepository)
{
g_productRepository = productRepository ?? IOCcontainer.Container.Resolve<IProductRepository>();
}
//I don't use an action here, this will make execute it for any action in any controller
protected override void OnActionExecuting(ActionExecutingContext context)
{
if (!(context.ActionDescriptor.ActionName.Equals("Index") && context.Controller.ToString().IndexOf("Home")>0)) {
//I now can use this viewdata to populate a dropdownlist along the whole application
ViewData["products"] = g_productRepository.GetProducts().ToList().SelectFromList(x => x.Id.ToString(), y => y.End.ToShortDateString());
}
}
}
Then the rest of controllers:
//will be based on MasterController
public class AboutController : MasterController
{
}
public ActionResult Index()
{
return View();
}
etc...
Probably not the most elegant way to do it but it will do until I find a better way or someone else brighten my mind up!

Resources