1

I have an existing large ASP.NET (ASP.NET Web Forms + MVC support) Application and trying to implement async programming on project.

For that I created a completely new POC by selecting ASP.NET Application (again ASP.NET Web Forms + MVC support). My POC works great and correctly does async execution.

Now when I copy exact same code in existing large project, this behaves like synchronous. I already have latest .NET Framework updates in large application. Here is my Controller implementation which is supposed to upload file async:

[HttpPost]
[ValidateInput(false)]
public async Task<JsonResult> VideoUpload(string Id)
{
    for (int i = 0; i < Request.Files.Count; i++)
    {
        // :::::
        await Run(fileStream);
    }

    return Json(new { error = false, message = "File uploaded." });
}

public async Task Run(Stream fileStream)
{
    // :::::

    using (fileStream)
    {
        // A long running method call
        await fileUploadRequest.UploadAsync();
    }
}

[HttpGet]
public JsonResult GetUploadingStatus()
{
    // :::::
    return Json(new { statusMessage = statusMessage, totalSent = totalSent, totalSize = totalSize }, JsonRequestBehavior.AllowGet);
}

In above code GetUploadingStatus() is a GET method does quick job. This methods receives random (3-4 seconds interval) Ajax calls and returns uploading status.

When I debug this implementation in large project, I noticed GetUploadingStatus() returns every results (10-15 Json response) at a time just after fileUploadRequest.UploadAsync() ends. So I feel this behaves like synchronous in large project. Then why this works great in a clean project but not in large project?

Abhimanyu
  • 2,173
  • 2
  • 28
  • 44
  • 1
    Your actual project & POC configuration is identical? including environment configuration, web config, session etc? – Nandip Makwana Oct 21 '15 at 05:57
  • 1
    I think that you are mistakenly mixing "async progrming" with "parallel programming". The point of async is to release awaiting thread to the threadpool while asynchronous I/O operation awaits for the results. Async will not improve application performance for single request but it could allow to process more requests at the same time – Alex Art. Oct 21 '15 at 06:00
  • Thanks Nandip. My implementations is very clean even in actual project. I just want to enable async behaviour and I don't think environment config or web.config or session will play any role. Even I can't see any bug. – Abhimanyu Oct 21 '15 at 06:01
  • Alex Art: async is to release awaiting thread to the thread-pool while asynchronous I/O operation awaits for the results?? Whats difference between async and asynchronous ? – Abhimanyu Oct 21 '15 at 06:04
  • take a look at this: http://stackoverflow.com/questions/9898441/do-the-new-c-sharp-5-0-async-and-await-keywords-use-multiple-cores – Alex Art. Oct 21 '15 at 06:10
  • Just used Debug.WriteLine("Ajax call received...") in GetUploadingStatus() method. Also tried breakpoint, noticed this hit only after upload ends. – Abhimanyu Oct 21 '15 at 06:10
  • 1
    Your logic makes no sense. The Ajax calls are separate http requests. They have no relationship to any other call before or after. Therefore async or sync means nothing in this regard since they are literally different requests. I'd look at how you are locking whatever you are using to communicate/store progress between requests. – rism Oct 21 '15 at 06:14
  • rism: How do you think said logic make no sense? If method/controller is doing some sort of long running task (forget async for the time being) how this will respond to these separate http requests raised by ajax? I think session state behavior is involve here. My POC works great but not original project means somewhere some session config is not allowing hence issue. – Abhimanyu Oct 21 '15 at 06:37

3 Answers3

1

What I understand is that you are making parallel request: 1 request is uploading files at the same time you are making requests to GetUploadingStatus for upload progress.

In this scenario, the way ASP.NET Session State works, it could lead to behavior you mentioned. As mentioned in this answers Why would multiple simultaneous AJAX calls to the same ASP.NET MVC action cause the browser to block? 2nd request execute only after first is executed. And it is the same you are experiencing as you mentioned "..GetUploadingStatus() returns every results (10-15 Json response) at a time just after fileUploadRequest.UploadAsync() ends.."

Other than that as Alex mentioned, you are mistakenly mixing "async progrming" with "parallel programming" i.e. parallel requests in this case..

Community
  • 1
  • 1
Nandip Makwana
  • 356
  • 4
  • 16
  • Hmm, make sense. I think disabling session behavior will work, like decorating controller with [SessionState(SessionStateBehavior.Disabled)]. – Abhimanyu Oct 21 '15 at 06:31
  • Seems [SessionState(SessionStateBehavior.Disabled)] is working, will update answer sooner after tests. – Abhimanyu Oct 21 '15 at 06:38
  • 1
    great to know it helped to resolve... over all idea is that ASP.NET Session State can cause problem in such scenario be it web forms, MVC and we need to overcome it accordingly.. plz update answer with detailed solutions it may helps others as my answer was intended to pin point towards ASP.NET Session State behavior – Nandip Makwana Oct 21 '15 at 06:45
1

Then why this works great in a clean project but not in large project?

async/await only works correctly when running on .NET 4.5.

To upgrade an older ASP.NET project, you must do two steps:

  1. Change the target framework to .NET 4.5 (or newer).
  2. Change the httpRuntime.targetFramework setting in your web.config to "4.5" (or newer).

When you upgrade an existing ASP.NET project to the latest version of .NET, Visual Studio will only do the first step above, and you have to do the second step manually. However, if you create a new ASP.NET project on the latest version of .NET, Visual Studio will do both steps.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Make sense Stephen. I resolved this issue by using [SessionState(SessionStateBehavior.Disabled)] controller annotation. I already verified from security point of view. In large project web.config I do not find any httpRuntime word. However I can see also, I see system.webServer has handler entry still pointing 4.0 framework. Let me check, if this change helps. – Abhimanyu Oct 22 '15 at 12:21
  • No, i still see have behavior. – Abhimanyu Oct 22 '15 at 12:28
  • 1
    @AbhimanyuKumarVatsa: `async` doesn't change how session state works, so you should disable session state if possible, just the same as synchronous methods. However, the other info in my answer is quite important: the behavior of `async`/`await` is completely undefined unless you set `httpRuntime.targetFramework`. – Stephen Cleary Oct 22 '15 at 12:30
0

To resolve this issue I just added [SessionState(SessionStateBehavior.Disabled)] with the controller which you can see below:

[SessionState(SessionStateBehavior.Disabled)]
public class UploadController : Controller
{
    [HttpPost]
    [ValidateInput(false)]
    public async Task<JsonResult> VideoUpload(string Id)
    {
        for (int i = 0; i < Request.Files.Count; i++)
        {
            // :::::
            await Run(fileStream);
        }

        return Json(new { error = false, message = "File uploaded." });
    }

    public async Task Run(Stream fileStream)
    {
        // :::::

        using (fileStream)
        {
            // A long running method call
            await fileUploadRequest.UploadAsync();
        }
    }

    [HttpGet]
    public JsonResult GetUploadingStatus()
    {
        // :::::
        return Json(new { statusMessage = statusMessage, totalSent = totalSent, totalSize = totalSize }, JsonRequestBehavior.AllowGet);
    }
}

Using this annotation may open some security breaches so verify it yourself before you annotate your controller.

Hope you find this useful.

Abhimanyu
  • 2,173
  • 2
  • 28
  • 44