Executing a Task in the Background in ASP.NET MVC

In some cases we want to execute some long running task in the background without affecting the main thread. One classic example is sending mails when we are implementing a sign in module. Mostly people will either go for a scheduled job independent of the application or do it in the main thread itself. 

.NET Framework 4.5.2 has got a new API called QueueBackgroundWorkItem which can execute short-lived resource intense tasks in an effective and reliable manner. As per the documentation

QBWI schedules a task which can run in the background, independent of any request. This differs from a normal ThreadPool work item in that ASP.NET automatically keeps track of how many work items registered through this API are currently running, and the ASP.NET runtime will try to delay AppDomain shutdown until these work items have finished executing.

One of the advantages of using the QBWI(QueueBackgroundWorkItem) is that it can keep track of the items that are registered through this API is currently running and the runtime will be able to delay the shutdown of the App Domain upto 90 seconds so that the running tasks can be completed. 

Let's see an example of file upload in ASP.NET MVC. In this example, I will chose file from the local machine using the file upload control and when you click the Upload button, the file will be saved inside a folder in the server which will be handled by the QBWI. 

View 

@{
    ViewBag.Title = "Index";
}
@model List<string>

<h2>Index</h2>
@using (Html.BeginForm("UploadFile", "Home", FormMethod.Post, new { id = "frmImageGallery", enctype = "multipart/form-data" }))
 { 
   <input type="file" name="file" />
   <input type="submit" value="Upload"  id="btnUpload" />
 }

<h2>Images</h2>
@foreach (var item in Model)
{ 
    <p><img src="@String.Concat("Images/Uploaded/",item)" style="height:200px" /></p><br />
}
<script>
    $(function () {
        $(document).on("click", "#btnUpload", function (event) {
            event.preventDefault();
            var fileOptions = {
                success: res,
                dataType: "json"
            }
            $("#frmImageGallery").ajaxSubmit(fileOptions);
        });

    }); 
</script>

Controller

public ActionResult Index()
{
    List drInfo = Directory.GetFiles(Server.MapPath("~/Images/Uploaded"), "*.*")
        .Where( s => s.ToLower().EndsWith(".png") || s.ToLower().EndsWith(".jpg"))
        .Select(Path.GetFileName).ToList();


    return View(drInfo);
}

[HttpPost]
public ActionResult UploadFile(HttpPostedFileBase file)
{
    if (file != null)
    {
              

        if (file != null && file.ContentLength > 0)
        {
            HostingEnvironment.QueueBackgroundWorkItem(ctx => SaveUploadedFile(file)); 

                    
        }
    }
            

    return RedirectToAction("Index" );
}

private void SaveUploadedFile(HttpPostedFileBase UploadedFile)
{
    Thread.Sleep(5000);
    var fileName = Path.GetFileName(UploadedFile.FileName);
    var path = Path.Combine(Server.MapPath("~/Images/Uploaded"), fileName);
    UploadedFile.SaveAs(path);
}

See here, in this controller I have a private method which saves the uploaded file to the disk. And in the action method I am using the following code to start the background task using QBWI

 HostingEnvironment.QueueBackgroundWorkItem(ctx =>
                SendNotification(message));

In the SaveUploadedFile method I have put a Thread.Sleep to simulate a long running task. Let's run the project and select a file by clicking on the Choose File button and click on the Upload button to save it. 

When the page refreshes after the postback, you won't see the uploaded images under the Images below because the background process han't completed yet because of the sleep statement. If you refresh the page again after sometime you will the uploaded picture under the images list as shown below.

There are some limitations in using this API which is detailed in the following blog.

https://blogs.msdn.microsoft.com/webdev/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-background-processes-in-asp-net/


No Comments

Add a Comment