Why is my DB context being disposed - c#

As with most of my recent posts, I will start by saying this is all new to me, and I am on the edge of my understanding. I am working on an existing application and have come across the above error.
The application is an MVC application that has 3 layers, and is being run through Swagger:
Rest
Services
DAL
In the service layer DependencyConfig, I do the following in the Register Method, the context is registered:
container.RegisterWebApiRequest<DbContext>(() => new LocalContext("name=DefaultConnection"));
So far this all seems to be working fine, as parts of the application are reading and writing from the database - although there is a lot in this application and I do not understand all of it.
Next, on the Rest layer, I have the following:
public class AccountController : ApiController
{
private readonly WindowsAuthenticationProvider _windowsAuthentication;
private readonly AuthorizationManager _authorizationManager;
private readonly IApplicationUserService _userService;
private readonly IProfileService _profileService;
private readonly IAccountLogsService _accountLogsService;
/// <summary>
/// Constructor
/// </summary>
/// <param name="authorizationManager">Authorization Manager</param>
/// <param name="windowsAuthentication">Enables windows reauthentication without a session</param>
public AccountController(AuthorizationManager authorizationManager, WindowsAuthenticationProvider windowsAuthentication,
IApplicationUserService userService, IProfileService profileService, IAccountLogsService accountLogsService)
{
_windowsAuthentication = windowsAuthentication;
_authorizationManager = authorizationManager;
_userService = userService;
_profileService = profileService;
_accountLogsService = accountLogsService;
}
/// <summary>
/// Get logged in user details
/// </summary>
/// <remarks>Retrieves details of the currently logged in user</remarks>
[Authorize]
[HttpGet]
[Route("")]
[ResponseType(typeof(AccountDetailsModel))]
public IHttpActionResult Details()
{
var userId = User.Identity.GetUserId<int>();
var model = //...
if (model.HasAccount)
{
var user = _authorizationManager.FindUser(User.Identity);
}
return Ok(model);
}
}
and also from the services layer:
public class AuthorizationManager
{
private readonly IApplicationUserService _userService;
public ApplicationUser FindUser(IIdentity identity)
{
var userId = identity.GetUserId<int>();
if (userId != 0)
{
return _userService.FindById(userId);
}
//...
}
}
and finally also on the services layer:
public class ApplicationUserService : UnitOfWork<LocalContext>, IApplicationUserService
{
private readonly UserManager<ApplicationUser, int> _userManager;
private readonly RoleManager<ApplicationRole, int> _roleManager;
/// <summary>
/// Finds a user by id
/// </summary>
/// <param name="id">User id</param>
/// <returns>ApplicationUser</returns>
public ApplicationUser FindById(int id)
{
return _userManager.FindById(id);
}
}
Where ApplicationUser is a model on the DAL layer.
I hope this all makes sense so far!
The problem is that when the code gets to this line:
return _userManager.FindById(id);
it throws an InvalidOperationException: The operation cannot be completed because the DbContext has been disposed.
Which seems to me to be saying it has lost the context eg database connection.
It seems to have disposed of the DbContext from the register method - but I have no idea why?
If I manually create a context like this:
Context.Users.Find(id);
I am able to retrieve the required entry, but the problem re occurs further down the line - and I do not think the application was intended to work like this.
So my question is, why is it disposing of my context and how can I stop it doing so?
Stepping through the code does not help and I am out of ideas.

The problem was to do with this line:
container.Register<IUserStore<ApplicationUser, int>, UserStore <ApplicationUser, ApplicationRole, int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>>(Lifestyle.Scoped);
Because of lifestlye.scoped, the context was being disposed of at this point.
I needed to add this to the container:
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
from these instructions: http://simpleinjector.readthedocs.io/en/latest/lifetimes.html#perwebrequest
Which only disposed of the object at the end of the web request

Related

How to initialize a scoped injected class in ASP.NET Core involving asynchronous calls

I need to initialize an injected class at the scope level in ASP.NET Core - the initialization involves asynchronous method calls. You wouldn't do this in the constructor, nor a property accessor.
A common DI use in an asp.net core application is getting the current user. I implemented this by creating an IUserContext abstraction and injecting it at the scoped level:
public sealed class AspNetUserContext : IUserContext
{
private readonly UserManager<User> userManager;
private readonly IHttpContextAccessor accessor;
private User currentUser;
public AspNetUserContext(IHttpContextAccessor a, UserManager<User> userManager) {
accessor = a;
if (userManager == null)
throw new ArgumentNullException("userManager");
this.userManager = userManager;
}
public string Name => accessor.HttpContext.User?.Identity?.Name;
public int Id => accessor.CurrentUserId();
public User CurrentUser {
get {
if (currentUser == null) {
currentUser = this.UserManager.FindByIdAsync(Id.ToString()).ConfigureAwait(false).GetAwaiter().GetResult();
}
return currentUser;
}
}
}
I am struggling trying to find out how to correctly initialize the CurrentUser property.
Since there is no longer any way to get a user from the UserManager class sychronously, I am not comfortable running an async method from within a property getter when initializing the CurrentUser, nor from the constructor (there are no long any synchronous methods on the UserManager class with ASP.NET Core).
I feel like the correct way to do this would be to run an initialization method on the injected instance somehow once per request since it is scoped (perhaps with an action filter/middleware/Controller base class (or perhaps in the dependency injection AddScoped method itself as a factory method?)
This seems like a pretty common problem and I'm wondering how others have resolved this.
In this case you will need to forgo the property and have an asynchronous method.
This would also mean having an asynchronous lazy initialization for the User using
/// <summary>
/// Provides support for asynchronous lazy initialization.
/// </summary>
/// <typeparam name="T"></typeparam>
public class LazyAsync<T> : Lazy<Task<T>> {
/// <summary>
/// Initializes a new instance of the LazyAsync`1 class. When lazy initialization
/// occurs, the specified initialization function is used.
/// </summary>
/// <param name="valueFactory">The delegate that is invoked to produce the lazily initialized Task when it is needed.</param>
public LazyAsync(Func<Task<T>> valueFactory) :
base(() => Task.Run(valueFactory)) { }
}
This now makes it possible to refactor the context to use lazy initialization,
public sealed class AspNetUserContext : IUserContext {
private readonly UserManager<User> userManager;
private readonly IHttpContextAccessor accessor;
private readonly LazyAsync<User> currentUser;
public AspNetUserContext(IHttpContextAccessor accessor, UserManager<User> userManager) {
this.accessor = accessor;
if (userManager == null)
throw new ArgumentNullException(nameof(userManager));
this.userManager = userManager;
currentUser = new LazyAsync<User>(() => this.userManager.FindByIdAsync(Id.ToString()));
}
public string Name => accessor.HttpContext.User?.Identity?.Name;
public int Id => accessor.CurrentUserId();
public Task<User> GetCurrentUser() {
return currentUser.Value;
}
}
And used where needed
User user = await context.GetCurrentUser();
Now a property could have still been used like
public Task<User> CurrentUser => currentUser.Value;
as the getter is a method, but that is not a very intuitive design in my personal opinion.
User user = await context.CurrentUser;
and can have undesirable results if accessed too early.
I only mention it because of the design of the original context shown in the example.
You can try following,
1) Register IUserContext and UserContext as Scoped
2) Retrieve IUSerContext or UserContext via httpContext,
IUserContext userContext = (IUserContext)httpContext.RequestServices.GetService(typeof(IUserContext));
My personal approach is a little bit different from nkosi's answer.
Your final requirement is to access one or more User property, right?
So, you can take advantange by using delegates mixed with async:
public interface IUserAccessor
{
Task<TValue> GetValueAsync<TValue>(Func<User, TValue> func);
}
public class UserAccessor
{
public UserAccessor(MyDbContext db)
{
this.db = db;
}
private readonly MyDbContext db;
public async Task<TValue> GetValueAsync<TValue>(Func<User, TValue> func)
{
return func(await this.db.FindUsersBySomeConditions().FirstOrDefaultAsync());
}
}
If your service is scoped, you can also use a persistence and avoid a second call to DB:
private User user;
public async Task<TValue> GetValueAsync<TValue>(Func<User, TValue> func)
{
if (this.user == null)
{
this.user = await this.db.FindUsersBySomeConditions().FirstOrDefaultAsync();
}
return func(this.user);
}
You can use like this:
#inject IUserService userService
// ...
<div>
<div>#await userService.GetValueAsync(u => u.Name)</div>
<div>#await userService.GetValueAsync(u => u.Role)</div>
<div>#await userService.GetValueAsync(u => u.BirthDate)</div>
<div>#await userService.GetValueAsync(u => u.ComplexProperty.SubProperty)</div>
</div>

Getting ninject to dispose of resources InRequestScope

I have a project that I'm working with and I'm trying to integrate ninject into. The way I have it set up is I have several service classes that inherit from two similar base classes AbstractService & AbstractReadableService, from which give them access to the data layer through my unit of work. The main dependency I want to be disposed is the DataContext which is held by the UnitOfWork which is in turn injected by ninject.
The way I have all these components set up is, I have the ServiceFactory put into the controller, which gets the needed dependencies from ninject. Then whenever I need a service I use the GetService method which sets the needed dependencies for that service drawn from the ServiceFactory’s copy and returns a copy of that service ready to use. However when I navigate to a new page or do any other action the Dispose method on the UnitOfWork is never called.
My thought was that the ServiceFactory and it's dependencies would be created on each request and that each time I set a new request the UnitOfWork would dispose of the database context. However I'm not hitting the dispose method and was hoping someone could point me in the right direction.
AbstractService:
AbstractReadableService holds the unit of work.
public abstract class AbstractService : AbstractReadableService
{
/// <summary>
/// Gets the current user id all lowercase at run time
/// </summary>
protected string UserId; //TODO: Change, to a more complete object, ex: We can resolve the employee number at startup time and get all that from an object returned by ICustomPrincipalService
public AbstractService() { }
/// <summary>
/// Constructor for abstract service that we can use to create a new service inside of other services
/// </summary>
/// <param name="user"></param>
/// <param name="unitOfWork"></param>
public AbstractService(ICustomPrincipalService user, IUnitOfWork unitOfWork)
{
if (base._unitOfWork == null || this.UserId == null)
{
this.UserId = user.GetUser();
base._unitOfWork = unitOfWork;
}
}
public void SetDependencies(ICustomPrincipalService user, IUnitOfWork unitOfWork)
{
if (base._unitOfWork == null || this.UserId == null)
{
this.UserId = user.GetUser();
base._unitOfWork = unitOfWork;
}
else
{
// Throw some really nasty error
}
}
}
Unit of work class
public class UnitOfWork : IUnitOfWork
{
private DataContext _dataContext;
public UnitOfWork(DataContext dataContext)
{
//Misc
_dataContext = dataContext;
ISomeRepo SomeRepo { get; private set; }
//Repositories
SomeRepo = new SomeRepo(dataContext);
}
public void SaveChanges(string userId)
{
RecordAuditProperties(userId);
_epmsContext.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
_dataContext.Dispose();
}
}
disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Service factory
public class ServiceFactory : IServiceFactory
{
private IUnitOfWork _unitOfWork;
private ICustomPrincipalService _userInfo;
private IEmployeeCredentialService employeeCredentials;
public ServiceFactory(IUnitOfWork unitOfWork, ICustomPrincipalService userInfo, IEmployeeCredentialService employeeCredentials)
{
_unitOfWork = unitOfWork;
_userInfo = userInfo;
}
public T GetService<T>() where T : AbstractService, new()
{
T svc = new T();
svc.SetDependencies(_userInfo, _unitOfWork);
return svc;
}
public T GetReadOnlyService<T>() where T : AbstractReadableService, new()
{
T svc = new T();
svc.SetDependencies(_unitOfWork);
return svc;
}
}
Ninject bindings:
private void AddBindings()
{
// Binding context to ensure only one context is used in the lifetime of the request
kernel.Bind<DataContext>().ToSelf().InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
//Deals with pulling the current HTTP context user id into the services
kernel.Bind<ICustomPrincipalService>().To<CustomPrincipalService>().InRequestScope();
kernel.Bind<IHttpContextFactory>().To<HttpContextFactory>().InRequestScope();
kernel.Bind<IEmployeeCredentialService>().To<EmployeeCredentialService>().InRequestScope();
//Disposible dependencies are passed here
kernel.Bind<IServiceFactory>().To<ServiceFactory>().InRequestScope();
}
Everything was correct, I was able to get it working after I installed the Ninject MVC4 solution from nuget

Ninject not resolving dependencies for a Controller

I have no idea what is going on with this. It makes no sense to me.
I have a controller that throws the following error:
System.InvalidOperationException: An error occurred when trying to create a controller of type 'LandingController'. Make sure that the controller has a parameterless public constructor. ---> Ninject.ActivationException: Error activating IApiService using binding from IApiService to ApiService No constructor was available to create an instance of the implementation type. Activation path: 2) Injection of dependency IApiService into parameter apiService of constructor of type LandingController 1) Request for LandingController Suggestions: 1) Ensure that the implementation type has a public constructor. 2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.
No matter what I do nothing works.
If I have:
no constructors in the controller
one constructor with the service
two constructors with the service and parameterless
If I hope for the parameterless constructor to work, then it does not resolve the IApiService.
I have the following setup in NinjectWebCommon:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IApiService>().To<ApiService>();
kernel.Bind<IMembersClient>().To<MembersClient>();
}
Controller is:
public class LandingController : Controller
{
IApiService _apiService;
LandingController(IApiService apiService)
{
_apiService = apiService;
}
// GET: Landing
public ActionResult Index()
{
var avm = new ApplicationViewModel();
_apiService.GetAcc();
return View(avm);
}
}
API Service is:
public class ApiService : IApiService
{
private readonly IMembersClient _membersClient;
ApiService(IMembersClient membersClient)
{
_membersClient = membersClient;
}
public void GetAcc()
{
_membersClient.Test();
}
}
Member Client is:
public class MembersClient : IMembersClient
{
public MembersClient()
{
public void Test()
{
}
}
}
This was the best post I found:
Ninject Dependency Injection with Asp.Net MVC3 or MVC4
But it never helped solve the issue.
EDIT: Full NinjectWebCommon
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IApiService>().To<ApiService>();
kernel.Bind<IMembersClient>().To<MembersClient>();
}
EDIT : Trying Property Injection
Code for property injection:
[Inject]
public IApiService ApiServiceC { private get; set; }
Updated Error:
System.InvalidOperationException: An error occurred when trying to create a controller of type 'LandingController'. Make sure that the controller has a parameterless public constructor. ---> Ninject.ActivationException: Error activating IApiService using binding from IApiService to ApiService No constructor was available to create an instance of the implementation type. Activation path: 2) Injection of dependency IApiService into property ApiServiceC of type LandingController 1) Request for LandingController Suggestions: 1) Ensure that the implementation type has a public constructor. 2) If you have implemented the Singleton pattern, use a binding with InSingletonScope() instead.
Well.... after much testing and trying different things.
The solution was to delete IApiService and ApiService completely and recreate them.
That successfully made everything wire up correctly again.

How to apply business rules to a WCF data service in a generic way, backed up by EF6

I have this requirement to create a REST API to manipulate a database. I decided on WCF Data Services v5.6 because i don't want to rewrite the wheel and i think that way is becoming the standard.
BUT, i need to apply business rules to the objects. All entities involved derive from a base class that has control fields like IsDeleted and so that need checking for example, against a select/GET.
My design has 4 projects:
DomainModel: Contains only the POCO entities (made by separating the Model.tt into a new project
DataAccessLayer: Contains the Context.tt that generates the EventsDomainModel context class
BusinessLayer: Contains a custom DbContext that does the validation, more on this in a moment
RestApi: The website and the services.
Currently, this is the validation i have:
public class GenericBusinessValidator<T>:DbContext where T: class, IBaseEntity
{
private DbContext _ctx;
private DbSet<T> _set;
/// <summary>
/// Standard constructor
/// </summary>
/// <param name="context">The DbContext object</param>
public GenericBusinessValidator(DbContext context)
{
_ctx = context;
_set = _ctx.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _set.Where(x => x.IsActive == true);
}
}
and the code needed to make the service work (Events.svc) is the standard
public class Events : EntityFrameworkDataService<EventsDomainModel>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
// Examples:
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
Now, what i am trying to achieve is to REPLACE the EventsDomainModel class wich is the vanilla DbContext -derived class from the second piece of code with the first, that does the validation but i dont know how;
The way i understand, my validator deals with a specific DbSet inside a given DbContext; the code from the WCF service needs a specific dbContext.
So, how can i validate all DbSets without particularizing my class, ie, avoid making
public class GenericBusinessValidator<T>:DbContext where T: class, IBaseEntity
{
private DbContext _ctx;
private DbSet<T> _set;
/// <summary>
/// Standard constructor
/// </summary>
/// <param name="context">The DbContext object</param>
public GenericBusinessValidator(DbContext context)
{
_ctx = context;
_set = _ctx.Set<T>();
}
private DbSet<Venue> Venues;
private DbSet<EventCategory> Categories;
...
...
...
BASICALLY, what i'm trying to accomplish is
make sure that a call like
http://localhost/Events.svc/EventCategories?$format=application/json
returns me all EventCategories that have isActive=true (applied generically) WITHOUT resorting to ServiceOperations and thus avoiding defeating the purpose of using REST
As it turns out, what i needed were QueryInterceptors and ChangeInterceptors
https://msdn.microsoft.com/en-us/library/dd744842(v=vs.110).aspx

Asp.Net Identity Usermanager and Unit Of Work - how to mate them?

I am using the Unit Of Work Pattern and have defined a class for it in a separate sub-project called MyProject.Domain.DAL.UnitOfWork.
Unfortunately, the whole ASP.Net Identity infrastructure is in my main project (as in the tutorial), MyProject.
Even more problematic: As I understand it, the ASP.NET identity uses it's own DBContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationDbContext"/> class, using the EFDB context.
/// </summary>
public ApplicationDbContext()
: base("EFDBContext", throwIfV1Schema: false)
{
}
/// <summary>
/// Creates this instance.
/// </summary>
/// <returns>A database context</returns>
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I have a class called Project, which should have a user associated with it - but how to do that, without using conflicting db contexts?
Example:
public class Project
{
public ApplicationUser User {get; set;}
}
Example calling code:
public class IndexController : Controller
{
// uow and userManager are instantiated through Ninject
// example code, normally this would be properties of the controller
public ActionResult Create(IUnitOfWork uow, ApplicationUserManager userManager, int someID )
{
Project newProject = new Project();
ApplicationUser user = await UserManager.FindByIdAsync(someID);
// this should give a conflict, since two different DataContexts are involved
newProject.User = user;
uow.Projects.Insert(newProject);
uow.Save()
return this.View();
}
}
}
The template is a bit confusing. You shouldn't create a separate own DbContext but rather extend the existing ApplicationDbContext with the rest of the data model. You can move it to somewhere else in the project, as long as you change the type in IdentityConfig.cs.
There is a tougher problem to solve though when using unit of work and it is that the ASP.NET Identity methods call SaveChanges() internally and when using unit of work you typically only want that once all the work is done. A workaround could be to use a TransactionScope() but it could be messy to get it created before the per-request DbContext that ASP.NET Identity uses.

Categories