7

I want to know if there is a better to way to handle this.

I've set up Unity for dependency injection for our project. The project itself is an ASP.NET application that uses Web API.

I have the following packages installed.

  • Unity
  • Unity.ASPNet.WebAPI

I see no option to close/dispose the DBContext right after fetching the data.

My controller

public class NinjasController : ApiController
{
    public Ninja Get(int id)
    {
        INinjaRepository repository = UnityConfig.Container.Resolve(typeof(INinjaRepository), null) as INinjaRepository;
        Ninja ninja = repository.GetNinjaById(id);
        repository.CanBeDisposed = true;
        repository = null;
        UnityConfig.PerRequestLifetimeManager.Dispose();
        return ninja;
    }
}

UnityConfig

public static class UnityConfig
{
    private static Lazy<IUnityContainer> container =
      new Lazy<IUnityContainer>(() =>
      {
          var container = new UnityContainer();
          RegisterTypes(container);
          return container;
      });

    public static IUnityContainer Container => container.Value;
    public static PerRequestLifetimeManager PerRequestLifetimeManager;

    public static void RegisterTypes(IUnityContainer container)
    {
        PerRequestLifetimeManager = new PerRequestLifetimeManager();
        container.RegisterType<INinjaRepository, NinjaRepository>(PerRequestLifetimeManager);
    }
}

Lifetime Manager

public class PerRequestLifetimeManager : TransientLifetimeManager, IDisposable
{
    private static List<IBaseRepository> list = new List<IBaseRepository>();

    public override void SetValue(object newValue, ILifetimeContainer container = null)
    {
        base.SetValue(newValue, container);

        IBaseRepository disposable = newValue as IBaseRepository;
        if (disposable != null)
            list.Add(disposable);
    }

    public void Dispose()
    {
        foreach (IBaseRepository item in list.FindAll(item => item.CanBeDisposed))
        {
            if (item != null)
            {
                try
                {
                    item.Dispose();
                }
                catch (Exception)
                {
                    // log exception and continue
                }
            }
        }

        list.RemoveAll(item => item.CanBeDisposed);
    }
}

Repository

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
    internal DbContext _context;
    internal DbSet<TEntity> _dbSet;
    public bool CanBeDisposed { get; set; }

    public GenericRepository(DbContext context)
    {
        _context = context;
        _dbSet = context.Set<TEntity>();
    }

    protected void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_context != null)
            {
                _context.Dispose();
                _context = null;
            }
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
One Developer
  • 99
  • 5
  • 43
  • 103
  • If configured correctly, the DI container would handle the disposal for you based on the lifetime rule. Unity will inject the dependency (your repository) through the controller's constructor -- there's no need to invoke it directly in your action. You need to register DbContext with Unity so that it can manage it with the specified lifetime. – Jasen Dec 29 '17 at 17:55
  • I'd - public NinjasController(INinjaRepository repository) and registered both the repository and DBcontext - container.RegisterType(); & container.RegisterType(); @Jasen, Dispose method was never called if respective of the LifetimeManager used. Can you please help me with a sample if you could. – One Developer Dec 29 '17 at 20:25

1 Answers1

7

First you might want to add one more Unity bootstrapper to your project Unity.AspNet.Mvc

https://msdn.microsoft.com/en-us/library/dn507440(v=pandp.30).aspx

To use the PerRequestLifetimeManager class in an ASP.NET Web API application, you must also add the the Unity bootstrapper for ASP.NET MVC NuGet package to your project.

Unity.Mvc and Unity.AspNet.WebApi will register your controllers for DI.

UnityConfig.cs

public static void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<INinjaContext, NinjaContext>(new PerRequestLifetimeManager());
    container.RegisterType<INinjaRepository, NinjaRepository>(new PerRequestLifetimeManager());
}

UnityWebApiActivator.cs Uncomment the line...

public static void Start()
{
    // Use UnityHierarchicalDependencyResolver if you want to use
    // a new child container for each IHttpController resolution.
    var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.Container);

    ...
}

UnityMvcActivator.cs Uncomment the line...

public static void Start()
{
    ...

    // TODO: Uncomment if you want to use PerRequestLifetimeManager
    Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}

Your controller is simply

public class NinjasController : ApiController
{
    private readonly INinjaRepository repository;

    public NinjasController(INinjaRepository repository)
    {
        this.repository = repository;
    }

    public Ninja Get(int id)
    {
        var ninja = repository.GetNinjaById(id);
        return ninja;
    }
}

With PerRequestLifetimeManager Unity will take care of disposal after the request is complete.

I have an example here https://github.com/jasenhk/MovieStar

If you are using OWIN see Unity IoC does not inject dependency into Web API Controller

Jasen
  • 14,030
  • 3
  • 51
  • 68