Unity configured with PerRequestLifetimeManager() creating multiple instances of DbContext per request for WebApi requests, but not MVC requests

Viewed 269

Here's my UnityConfig.cs:

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

    public static IUnityContainer GetConfiguredContainer()
    {
        return container.Value;
    }

    public static void RegisterTypes(IUnityContainer container)
    {
        container.RegisterType<IProjectContext, ProjectContext>(new PerRequestLifetimeManager());
    }
}

Here's my UnityWebApiActivator.cs:

public static class UnityWebApiActivator
{
    public static void Start()
    {
        Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

        var container = UnityConfig.GetConfiguredContainer();
        var resolver = new Microsoft.Practices.Unity.WebApi.UnityDependencyResolver(container);
        GlobalConfiguration.Configuration.DependencyResolver = resolver;
    }

    public static void Shutdown()
    {
        var container = UnityConfig.GetConfiguredContainer();
        container.Dispose();
    }
}

Stepping through the code, I can see my container getting created with the appropriate registrations.

Here is a sample WebAPI controller:

[Authorize]
public class ProjectApiController : BaseApiController
{
    private readonly ProjectService _projectService;

    public ProjectApiController(ProjectService projectService)
    {
        _projectService = projectService;
    }

    [Route("api/project")]
    [AcceptVerbs("POST")]
    public HttpResponseMessage SendProject(ProjectDto projectDto)
    {
        return Request.CreateResponse(HttpStatusCode.OK, _projectService.SendProject(GetUsername(), projectDto));
    }
}

While my ProjectService constructor looks like this:

public class ProjectService : BaseService
{

    public readonly ProjectContext _db;
    public readonly NotificationService _notificationService;

    public ProjectService(ProjectContext db, NotificationService notificationService)
    {
        _db = db;
        _notificationService = notificationService;
    }
    // methods here
 }

Both MVC controllers and API controllers depend on ProjectService, yet WebAPI requests behave differently. When an MVC request is served, I get a single instance of ProjectContext created as desired. When a WebAPI request is served, every injection creates a new instance. This is not desired.

Why is this happening?

Update:

Per the below answer, I have changed

DependencyResolver.SetResolver(new UnityDependencyResolver(container));

to

DependencyResolver.SetResolver(new UnityHierarchicalDependencyResolver(container));

This resulted in:

The type Microsoft.Practices.Unity.WebApi.UnityHierarchicalDependencyResolver does not appear to implement Microsoft.Practices.ServiceLocation.IServiceLocator. Parameter name: commonServiceLocator

Which led me here, where the recommended solution leads to:

enter image description here

I currently have:

  • Unity 4.0.1
  • Unity.AspNet.WebApi 4.0.1
  • Unity.Mvc 4.0.1
  • Unity.MVC5 1.2.3

Upgrading packages is last-resort right now.

1 Answers

We had similar issue with our dbContext (EF Core) in net core 2.2 app along with SimpleInjector library. The dbContext lifetime was not getting set properly irrespective of whatever lifetime value we provided. The worst part was that the failure was intermittent making it even harder to figure it out.

What we discovered was we were registering dbContext twice, once in netcore's DI container and second time with SimpleInjector container which was causing all sorts of issues.

Hence, I would recommend to check if you are also registering it twice. Just fyi, if it is the case, then recommendation would be to get rid of one them as setting same lifetime values did not work for us.

Related