4

I want to be able to run an asynchronous call as follows:

[Route("doit"),ResponseType(typeof(MyModel))]
public IHttpResponse PostAsyncCall(MyModel model){
    //Code removed for simplicity

    Task.Factory.StartNew(() => asyncStuff(model.id);

    return OK(model);
}

private void asyncStuff(int id) {
    MyModel model = db.MyModels.find(id);
    //Do things here. Long call to other webservices/processing of data. Time intensive normally.
    User user = db.Users.find(model.userId);
    //Do more things. Time intensive normally.
}

However, when the async method hits the db. methods an error occurs:

An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code

Additional information: The operation cannot be completed because the DbContext has been disposed.

The context used is here:

public class MyContext : DbContext, MyContextInterface
{
        // You can add custom code to this file. Changes will not be overwritten.
        // 
        // If you want Entity Framework to drop and regenerate your database
        // automatically whenever you change your model schema, please use data migrations.
        // For more information refer to the documentation:
        // http://msdn.microsoft.com/en-us/data/jj591621.aspx

        public MyContext() : base("name=MyContext")
        {
        }

        public System.Data.Entity.DbSet<MyAPI.Models.User> Users { get; set; }

        public System.Data.Entity.DbSet<MyAPI.Models.Request> Requests { get; set; }

        public void MarkAsModified(Object item)
        {
            Entry(item).State = EntityState.Modified;
        }

    }

The context is created in the controller as a class variable via:

private MyContextInterface db = new MyContext();

I can see that the db context is being disposed of as the method ends; however, I need to retain this context for the duration of the asynchronous method to access the information needed. How can I do this?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
steventnorris
  • 5,656
  • 23
  • 93
  • 174

1 Answers1

6

You start a task but you don't await it, so effectively you immediately call OK. By the time the long running task is finished, indeed your db context is disposed. Just add an await and your problem will be solved.

Philip Stuyck
  • 7,344
  • 3
  • 28
  • 39
  • I don't want the method to wait until the tasks finishes. I want it to return immediately while the asynchronous task runs in the background, so as to eliminate the user waiting on this long running task. – steventnorris Mar 10 '15 at 20:28
  • 1
    Then you need to reconsider your design. An alternative is that you really make sure that you context is created when you need it or released when you are really done with it and not earlier. I cannot tell exactly where to do it based on what i have seen in your code so far. – Philip Stuyck Mar 10 '15 at 20:31
  • I'm unsure of what direction to take. What further information would be helpful to further clarify the problem? – steventnorris Mar 10 '15 at 20:34
  • 1
    if you don't need the dbcontext before the find, new it when you do need it and use the using clause. I googled around a bit but cannot find a similar as your problem immediately. – Philip Stuyck Mar 10 '15 at 20:41
  • 2
    I did find this link : http://stackoverflow.com/questions/17577016/long-running-task-in-webapi – Philip Stuyck Mar 10 '15 at 20:43
  • So, essentially, I would need to create a new DBContext for the async method, as I can't rely on the one created with the controller correct? So manual create then dispose of the context in the async method? – steventnorris Mar 10 '15 at 20:43
  • If you don't need it beforehand. – Philip Stuyck Mar 10 '15 at 20:44