0

I am using web api 2, and entity framework 6. I have created an async web api, which updates all the records at once. I am also using Autofac for dependency injection.

My service interface is as follows :

Task<Approval> TakeAction(int id, bool isApprove)
void TakeAction(bool isApprove)

These are my service methods :

  public async void TakeAction(bool isApprove)
    {
//GetAllDataToApprove is the same function in the service.
        var approvalList= GetAllDataToApprove().Approvals.ToList();
        foreach (var approval in Approvals)
        {
//This is an async method as well
            await TakeAction(approval.ApprovalId, isApprove);
        }
    }

TakeAction method is as follows :

  public async Task<Approval> TakeAction(int id, bool isApprove)
    {
        Approval approval= approvalrepository.Query(o => o.ApprovalId == id).FirstOrDefault();
        try
        {
//updating the approval status
           approval.StatusId=5
                    UpdateDashboard(approval);                   

                approvalrepository.Update(approval);
                await unitOfWork.SaveChangesAsync();
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return approval;
    }

My web-API method is as follows :

     [HttpPut]
    public IHttpActionResult Put(bool isApprove)
    {
        try
        {
            approvalservice.TakeAction(isApprove);

            return Ok();
        }
        catch (Exception ex)
        {
            throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message));
        }
    }

I want to make a non-blocking API call, such that if this API is triggered, it should approve all the pending data. The reason I made this async is because there are lot of data in the pending list, so it takes a long time.

I am getting the following error: The operation cannot be completed because the DbContext has been disposed.

3
  • How to you manage lifetime of DbContext Commented Jun 18, 2015 at 9:34
  • 2
    this doesn't have anything to do with async operations. it looks like it has to do with you making changes inside a repository (which, presumably, has a DbContext inside it) and then trying to save changes on a unitOfWork (which probably has a different DbContext). Commented Jun 18, 2015 at 9:42
  • 3
    for what it's worth, Entity Framework is already a repository/unitOfWork. adding these "wrappers" around EF not only make the code harder to work with, they also tend to lead you into places where you lose some of the power that EF offers. Commented Jun 18, 2015 at 9:45

1 Answer 1

1

If I understand your question correctly, it boils down to this:

How do I start a long running task from an API call but respond before it is finished.

Short Answer:

You don't in the API. You delegate to a Service.

Long Answer:

The error you are getting is most likely thanks to Autofac. With a Web Api Request you initialize everything you need at the start of the request and get rid of it at the end. In your code, you are trying to do stuff with DbContext after your request ended and it got thrown away. To fix this, simply add await like this await approvalservice.TakeAction(isApprove);.

Doing the above means you are now waiting for the process to complete. Which is not what you wanted. But this is the only way, because Web Api was made to work this way.

What you need to do instead is delegate the work to a service. Something that was made to run long running tasks. A few options are:

  1. HangFire
  2. Azure WebJobs / Cloud Services
  3. Windows Services

This is a really nice read on the exact issue you are having. HowToRunBackgroundTasksInASPNET

Sign up to request clarification or add additional context in comments.

7 Comments

I completely agree with you, I was able to resolve this. As you said Autofac was actually the culprit. I had overriden the dbcontext Dispose method. I had to comment the code. It works fine now, but my concern is just like azure portal, how do I manage the long running tasks on the UI side. Should I use Signal-R to do this ? or do I need to call the API every few seconds to understand how many of the records have been processed ?
Both will work. You can poll, or use something like SignalR for real time updates.
Heads Up: Although you have gotten it to 'work', it is not guaranteed. If your task is long running there is no guarantee Web Api will not just simply throw it away half way through. Furthermore, if there is some error you won't be able to do anything about it.
oh so Hangfire, Azurewebjobs and windows services are the only options I could use ?
I think polling would be good as the client calls the API every few seconds while on the page, whereas SignalR would require the server to broadcast the response to all its client. Please correct me if I am wrong
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.