jstuardo
jstuardo

Reputation: 4383

System.Web.HttpContext.Current get lost

I developed an MVC 5 app.

Inside a controller, I have this action:

    // POST: Usuario/Edit
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<JsonResult> Edit(UsuarioViewModel model)
    {
        //
        // some tasks
        //
        //
        return Json("Some text", JsonRequestBehavior.AllowGet);
    }

When that action is called after a html form submit, System.Web.HttpContext.Current is not null. I am using that object somewhere in the code.

Now, I need to call this same action method from other action method in the same controller. In that case, System.Web.HttpContext.Current is null, causing obviously, the application to throw a null object exception.

The action method and the call are:

    // POST: Usuario/CreateFromStaff
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<JsonResult> CreateFromStaff(int[] trabajadores)
    {
        //
        // some tasks
        //
        //
        UsuarioViewModel model = new UsuarioViewModel();
        //
        // model properties assignments
        //
        //
        JsonResult json = Task.Run(async () => await Edit(model)).Result;  // When this call is made, the Http context get lost.
    }

What can I do so that the http context is kept? or, how can I do that call?

Question Edit:

Just to be clearer. The Edit action method is the standard way to store a record, in this case a user record. At some point in this action method I have:

await db.SaveChangesAsync();

On the other hand, the JsonResult json = Task.Run(async () => await Edit(model)).Result; is inside a ForEach method. After that loop, I need to save other data, so that I am using another await db.SaveChangesAsync(); after it.

If I configure the ForEach method as async I have always problems with the second await db.SaveChangesAsync();. An error is thrown telling that some database operations are incomplete. That is why I used .Result and the ForEach method not to be async.

Thanks Jaime

Upvotes: 0

Views: 922

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456477

What can I do so that the http context is kept? or, how can I do that call?

Remove the Task.Run call. You should strongly avoid ever using Task.Run on ASP.NET.

the JsonResult json = Task.Run(async () => await Edit(model)).Result; is inside a ForEach method... If I configure the ForEach method as async... An error is thrown telling that some database operations are incomplete. That is why I used .Result and the ForEach method not to be async.

Indeed, the ForEach method does not properly understand async lambdas, and if you make its lambda async, then you will end up with async void lambdas, which should be avoided. That would cause the "asynchronous operation incomplete" errors.

I assume the fix went something like this:

  1. ForEach doesn't work with async, so I need to make it synchronous.
  2. Blocking didn't work, so I need to use Task.Run to avoid the deadlock.
  3. Well, now I don't get HttpContext.Current. How can I get HttpContext.Current?

But a better fix is this:

  1. ForEach doesn't work with async, so I need to use something other than ForEach.

Changing ForEach to foreach will solve your problem in a much nicer way.

Upvotes: 3

Related Questions