Search code examples
c#genericsninjectinversion-of-controlidisposable

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();
    }

Solution

  • Everything was correct, I was able to get it working after I installed the Ninject MVC4 solution from nuget