Nick Goloborodko
Nick Goloborodko

Reputation: 3053

Autofac and HostingEnvironment.QueueBackgroundWorkItem

I'm looking to add some background processing to my ASP.NET MVC 5 application, more specifically executing some long-ish (5-10 seconds) running tasks with HostingEnvironment.QueueBackgroundWorkItem. Now, the problem that I'm having is that code is running "out of band" and is not tied to the request any more - Autofac disposes of some of the injected dependencies.

Here is some of the code:

        [HttpPost, ActionName("Execute")]
    public ActionResult ExecutePost(Guid taskguid, FormCollection values)
    {
        if (taskguid == default(Guid))
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        var model = _taskListService.GetTaskByGuid(taskguid);

        if (TryUpdateModel(model.TaskObject as MissingCrossReferenceTask))
        {
            model.TaskObject.DependencyContainer = _dependencyContainer;
            model.TaskObject.TaskListId = model.Id;

            HostingEnvironment.QueueBackgroundWorkItem(ct => ExecuteTask(ct, model));

            return RedirectToAction("Index", "Dashboard");
        }


        return View(model);

    }

In the code above DependencyContainer is an object that contains a number of dependencies that are injected by Autofac (EF Repositories and Services)

private void ExecuteTask(CancellationToken ct, TaskList model)
    {
        model.TaskObject.Execute();
    }

Inside of that execute method of the MissingCrossReferenceTask (which is in a separate assembly from the ASP.NET MVC project:

        public bool Execute()
    {


        long tableId = DependencyContainer.CrossReferenceService.GetCrossReferenceTable(TableName).Id;

        string currentValue = DependencyContainer.CrossReferenceService.GetValue(FromValue, tableId);

        ...

    }

The first line throws an exception: ObjectDisposedExcetion {"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."}

Now, I don't know the Autofac well enough to figure out the best way around this. Is it somehow possible to re-inject the reference directly in ExecuteTask method? If so - how?

I would extremely appreciate any help of this. It has been driving me insane for a few days now...

Thanks, Nick Goloborodko

Upvotes: 2

Views: 1639

Answers (1)

Nick Goloborodko
Nick Goloborodko

Reputation: 3053

I guess submitting the question has forced me to look at the problem from a slightly different angle.

I think I have found a way around this (in other words - it now works as I'd like it to). I'm still not sure if this approach is the best in my situation or if there are any unseen problems with it - I would much appreciate any comments around this topic!

I have solved the issue in the following way:

 private void ExecuteTask(CancellationToken ct, TaskList model)
    {
        MvcApplication app = this.HttpContext.ApplicationInstance as MvcApplication;

        using (var container = app.ContainerProvider.ApplicationContainer.BeginLifetimeScope(WebLifetime.Application))
        {
            model.TaskObject.DependencyContainer = container.Resolve<DependencyContainer>();
            model.TaskObject.Execute();
        }
    }

(adopted from a solution posted on this page: http://aboutcode.net/2010/11/01/start-background-tasks-from-mvc-actions-using-autofac.html)

Hope this may save a bit of time to someone else in the future!

Upvotes: 1

Related Questions