1

I have self-hosted WebAPI inside my ASP.NET MVC application. I want to perform some asynchronous action when one of my API action is executed. The asynchronous action has dependency on DbContext along with some other dependencies.

Following is my Simple Injector configuration.

public class SimpleInjectorIntegrator
{
    private static Container container;

    public static Container Setup()
    {
        container = new Container();
        container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
            defaultLifestyle: new WebRequestLifestyle(),
            fallbackLifestyle: new AsyncScopedLifestyle());

        container.Register<IBaseRepository<User>, BaseRepository<User>>(Lifestyle.Scoped);
        container.Register<ComputationService>(Lifestyle.Scoped);
        container.Register<ILog, Logger>(Lifestyle.Scoped);

        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    }

    public static T Get<T>() where T : class
    {
        if (container == null)
            throw new InvalidOperationException("Container hasn't been initialized.");

        return container.GetInstance<T>();
    }
}

The Global.asax.cs looks like this.

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        var container = SimpleInjectorIntegrator.Setup();
        GlobalConfiguration.Configure(WebApiConfig.Register);

        ...some other code...
        DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    }
}

Below is the API Controller.

public class ExperimentUploadController : ApiController
{
    private ComputationService _service = SimpleInjectorIntegrator.Get<ComputationService>();

    public IHttpActionResult Started(InputModel model)
    {
        ...Do Something...
        var task = Task.Run(() =>
        {
             _service.Do(model.Id);
        });
    }
}

The API depends on ComputationService which performs connects with database using a repository. When I am trying to access the database from ComputationService, it throws that DbContext is disposed.

ComputationService code looks like below:

public class ComputationService 
{
    private IBaseRepository<User> _userRepo = SimpleInjectorIntegrator.Get<User>();

    public void Do(int id) 
    {
        ///throws here
        var user = _userRepo.Get(id);
    }
}

I am not sure why this is happening.

Steven
  • 166,672
  • 24
  • 332
  • 435
Nitesh Saxena
  • 199
  • 15
  • 1
    Do you await `task`? If you don't, the request is probably finishing (and thus disposing the `DbContext`) before the `Do` method completes. – ProgrammingLlama Jan 08 '19 at 04:51
  • I do not want the thread to wait for task to complete. I want my API to return and my service to perform the task and in service I am injecting all the required dependencies. – Nitesh Saxena Jan 08 '19 at 05:06
  • Perhaps [this](https://stackoverflow.com/questions/13617698/the-operation-cannot-be-completed-because-the-dbcontext-has-been-disposed-error) might be helpful? – ProgrammingLlama Jan 08 '19 at 05:35
  • See: https://simpleinjector.readthedocs.io/en/latest/howto.html#multi-threaded-applications – Steven Jan 08 '19 at 07:50

1 Answers1

0

The actual problem that I was facing was that I do not want my API to wait for the asynchronous operation to complete and hence the DbContext was being disposed as mentioned by @John. But I require SimpleInjector to resolve the dependency using AsyncScopedLifestyle as I have configured it in my configuration.

I found the answer using this Github link. What I did is wrapped my Asynchronous method inside the Asynchronous scope and resolved dependencies in that scope and it worked.

Here is the updated code.

public class ComputationService 
{
    private IBaseRepository<User> _userRepo;

    public void Do(int id) 
    {
        using(AsyncScopedLifestyle.BeginScope(SimpleInjectorIntegrator.Container)) 
        {
            _userRepo = = SimpleInjectorIntegrator.Container.GetInstance<User>();
            var user = _userRepo.Get(id); //works fine.
        }
    }
}

One more change I have made is to expose the Container via Property in my SimpleInjectorIntegrator class.

Nitesh Saxena
  • 199
  • 15