Dave
Dave

Reputation: 1775

How to convert controller action to be non-blocking/asynchronous

I have a controller action that accepts a file, parses the file and imports data from it, and returns a file:

    public FileResult ImportDevices()
    {
        HttpPostedFileBase csvFile = Request.Files[0] as HttpPostedFileBase;

        if (csvFile != null || csvFile.ContentLength != 0)
        {
            SaveDevicesResult result = CADC.SaveCSVDeviceData(csvFile.InputStream);

            string csvString = result.ToString();

            UTF8Encoding encoding = new UTF8Encoding();
            byte[] bytes = encoding.GetBytes(csvString);

            return File(bytes, "text/txt", "ImportResults.txt");
        }
        return null; // Not sure how to handle this case, that's another question though!
    }

And I'd like this to be non blocking, since the import can take awhile. I'd like the user to be able to browse the page, and return the file as a download when it's ready.

Do I follow this: http://msdn.microsoft.com/en-us/library/ee728598%28v=vs.100%29.aspx

Or do I using async and await?

Or are they the same thing and I'm confused?

Upvotes: 0

Views: 488

Answers (2)

Dan
Dan

Reputation: 10548

You would need to write an asynchronous controller method to handle this, and you would also have to rewrite your SaveCSVDeviceData method to return a Task<SaveDevicesResult>. What you are trying to do here is done via the async/await pattern, which can be achieved by the following

public async Task<ActionResult> ImportDevicesAsync()
{
    var csvFile = Request.Files[0] as HttpPostedFileBase;
    if(csvFile != null && csvFile.ContentLength != 0)
    {
        // Note: I would recommend you do not do this here but in a helper class
        // for this to work, SaveCSVDeviceDataAsync *must* return a Task<object>()
        var result = await CADC.SaveCSVDeviceDataAsync(csvFile.InputStream);
        var csvString = result.ToString();
        var encoding = new UTF8Encoding();
        var bytes = encoding.GetBytes(csvString);
        // if you are returning a csv, return MIME type text/csv
        return File(bytes, "text/txt", "ImportResults.txt");
    }

    // If the file is null / empty, then you should return
    // a validation error
    return Error(500, ...);
}

As I mentioned though, in order for this to work your CADC.SaveCsvDeviceData must return a Task<SaveDevicesResult>. Given that you are passing that method an InputStream I will remind you that all methods on the InputStream have an awaitable alternative to them in .NET 4.5 +.

Upvotes: 1

NeddySpaghetti
NeddySpaghetti

Reputation: 13495

They are not the same thing, the link that you posted is pertains to MVC 1.0 and it's an old way of doing it. For MVC 4 see Using Asynchronous Methods in ASP.NET MVC 4.

Upvotes: 0

Related Questions