How to Easily Manage Different Languages ​​on a Website: a Complete Tutorial With ASP.NET MVC

As information technology becomes an ever-larger part of our lives, it is becoming ever easier to access Internet content from all over the world, and developers are increasingly creating multilingual sites to reach a wide audience.

The following is a tutorial to easily and efficiently manage ASP.NET MVC web sites in multiple languages.

I use XML files as source files in order to avoid being beholden to a database. Then, I create a service that implements an interface to be able to easily change the implementation at need.

With this service, I am able to:

– Retrieve resources for building dynamic HTML controls (code behind side).
– Create HtmlHelpers providing access to these resources.
– Create attributes on models to translate label form fields.

Finally, I create an action filter to access the desired resource.

Step 1: Define XML source file(s)

I recommend creating a specific directory in “App_GlobalResources”, for example “XmlResources”.

For the purposes of translating the homepage of our website, let’s create the Home.xml file to differentiate the resources on this page from others. Let’s say it contains two resources:

<?xml version="1.0" encoding="utf-8" ?>
 <Resources>
  <Resource key="HelloWordKey">
   <Language key="EN">Hello World!</Language>
   <Language key="FR">Bonjour le monde!</Language>
  </Resource>
  <Resource key="MyNameKey">
   <Language key="EN">My name is Anthony</Language>
   <Language key="FR">Mon prénom est Anthony</Language>
  </Resource>
  <Resource key="EnterYourNationalityKey">
   <Language key="EN">What's your nationality</Language>
   <Language key="FR">De quelle nationalité êtes-vous?</Language>
  </Resource>
</Resources>

Step 2 : Create a Specific Reader for This(ese) File(s)

using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Xml.Linq; 
using MyApp.Tools; 

namespace MyApp.Services 
{ 
   public static class ResourceXmlReader 
   { 
       //static property, public readable only 
       public static readonly Dictionary>> Resources = new Dictionary>>(); 

       //static constructor 
       static ResourceXmlReader() 
       { 
           try { 
           string path = System.Web.Hosting.HostingEnvironment.MapPath("~/App_GlobalResources/XmlResources/"); 
           FolderContentBrowser content = new FolderContentBrowser(path); 
           LoopOnResources(content.FileNameList); 
           } 
           catch { } 
       } 

       //Browse each xml resource file on the current directory 
       private static void LoopOnResources(List fileList) 
       { 
          fileList.Where(o => o.EndsWith(".xml")).ToList().ForEach(o => OpenAndStoreResource(o)); 
       } 

       //Open, read and store into the static property xml file 
       private static void OpenAndStoreResource(string resourcePath) 
       { 
          try { 
          string fileName = Path.GetFileName(resourcePath).Split('.')[0]; 
          XDocument doc = XDocument.Load(resourcePath); 
          if (null != doc) { 
             Dictionary> currentResource = new Dictionary>(); 
             var resources = doc.Descendants("Resource").ToList(); 
             resources.ForEach(o => currentResource.Add(o.Attribute("key").Value, getEachLanguage(o.Elements("Language")))); 

             //attachement des resources à une ressource nommée 
             Resources.Add(fileName, currentResource); 
          } 
          } 
          catch { } 
        } 

        //Loop on each language into the file 
        private static Dictionary getEachLanguage(IEnumerable elements) 
        { 
           Dictionary langList = new Dictionary(); 
           elements.ToList().ForEach(o => langList.Add(o.Attribute("key").Value, o.Value)); 
           return langList; 
        } 
     } 
}

I use a static constructor because it will be executed just one time. I read xml files just onceand store them in my static property. This is the secret of performance management system languages. I do not read the xml files for each page load.

Note that the reader developed a string of dictionaries. The data is arranged as follows: Name of dictionary xml file (one for each page), containing a dictionary, in turn containing language, itself a resource dictionary (key resources, textual value of the resource).

Step 3: Create a Service That Implements an Interface For Managing Access to Resources

using System;
using System.Collections.Generic;
namespace MyApp.Globalization
{
   public interface IResourceService
   {
      string GetResource(string resourceName, string resourceKey);
      Dictionary> GetRessourcesByName(string resourceName);
   }
}
using MyApp.Services;
using System.Collections.Generic;
using System.Globalization;

namespace MyApp.Globalization
{
   public class ResourceService : IResourceService
   {
      public string GetResource(string resourceName, string resourceKey)
      {
         try {
            string language = CultureInfo.CurrentCulture.TwoLetterISOLanguageName.ToUpper();
            if (ResourceXmlReader.Resources.ContainsKey(resourceName)) {
               if (ResourceXmlReader.Resources[resourceName].ContainsKey(resourceKey)) {
                  if (ResourceXmlReader.Resources[resourceName][resourceKey].ContainsKey(language))
                     return ResourceXmlReader.Resources[resourceName][resourceKey][language];
                  else
                     return ResourceXmlReader.Resources[resourceName][resourceKey]["EN"];
               }
               else
                  return string.Empty;
            }
            else return string.Empty;
            }
        catch { return string.Empty; }
      } 

      public Dictionary> GetRessourcesByName(string resourceName)
      {
         try {
            return ResourceXmlReader.Resources[resourceName];
         }
         catch { return null; }
      }
   }
}

We access to the right resource by using the “TwoLetterISOLanguageName” Property, but we need to define it! so here step 4 !

Step 4: Create an action filter attribute which defines the language in the current context

using System.Globalization; 
using System.Linq; 
using System.Threading; 
using System.Web; 
using System.Web.Mvc; 

namespace MVC.Globalization 
{ 
   public class GlobalizeFilterAttribute : ActionFilterAttribute 
   { 
      // Define language in current context 
      public override void OnActionExecuting(ActionExecutingContext filterContext) 
      { 
         //Get current Http HttpContextBase context = filterContext.HttpContext; 
         //if sent by Url 
         string cultureName = context.Request.QueryString["lang"]; 
         //Cookie test 
         if (string.IsNullOrEmpty(cultureName)) 
         { 
            cultureName = (null != context.Request.Cookies["lang"]) ? context.Request.Cookies["lang"].Value : string.Empty; 
            if (string.IsNullOrEmpty(cultureName)) 
            { 
               try { 
                  //sinon langue du navigateur 
                  cultureName = context.Request.UserLanguages.FirstOrDefault(); 
                  if (string.IsNullOrEmpty(cultureName)) cultureName = "EN"; 
               } 
               catch { cultureName = "EN"; } 
            } 
         } 
         else 
         { 
            var langCookie = new HttpCookie("lang"); 
            langCookie.Value = cultureName; 
            context.Response.Cookies.Add(langCookie); 
         } 

         // Change culture on current thread 
         CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName); 
         Thread.CurrentThread.CurrentCulture = culture; 
         Thread.CurrentThread.CurrentUICulture = culture; 

         //action continuation 
         base.OnActionExecuting(filterContext); 
      } 
   } 
}

This attribute allows you to intercept a language set from a form (by Url in this example) and memorize it into a cookie.

If no language is set by a form or by a cookie, the first language set in your browser will be used. If no language is set in your browser, English will be the default language.

This attribute works both if you set the language yourself and if you use the browser language by default.

To use this attribute for each page of your website, define it as a global filter in your FilterConfig class, as follows:

using MVC.Globalization; 
using System.Web; 
using System.Web.Mvc; 

namespace MVC 
{ 
   public class FilterConfig 
   { 
      public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
      { 
         filters.Add(new GlobalizeFilterAttribute()); 
         filters.Add(new HandleErrorAttribute()); 
      } 
   } 
}

Now it’s time to implement each use case translation functionality from service resources (IResourceService).

Step 5 : Implement usage, translation functionality cases

  • HtmlHelper :
using MyApp.Globalization; 
using System.Collections.Generic; 
using System.Globalization; 
using System.Linq; 
using System.Text; 
using System.Web.Mvc;
 
namespace MVC.Helpers 
{ 
   public static class ResourceHelper 
   { 
      private static IResourceService _resources; 
      public static string GetResource(this HtmlHelper helper, string resourceName, string resourceKey) 
      { 
         CheckProvider();
         return _resources.GetResource(resourceName, resourceKey); 
      } 

      public static MvcHtmlString GetJSONResources(this HtmlHelper helper, string[] resourcesName) 
      { 
         CheckProvider();
         string lang = CultureInfo.CurrentCulture.TwoLetterISOLanguageName.ToUpper(); 
         TagBuilder builder = new TagBuilder("script"); 
         builder.MergeAttribute("type", "text/javascript"); 
         StringBuilder strBuilder = new StringBuilder(); 
         strBuilder.AppendLine(); 
         strBuilder.AppendLine("var MyApp = MyApp || {};"); 
         strBuilder.AppendLine("MyApp.Resources = MyApp.Resources || {};"); 
         strBuilder.AppendLine("MyApp.Resources ="); 
         strBuilder.AppendLine("{"); 
         resourcesName.ToList().ForEach(resourceName => { 
            var ressourceCollection = _resources.GetRessourcesByName(resourceName); 
            if (null != ressourceCollection && ressourceCollection.Count > 0) 
            { 
               int nbElements = ressourceCollection.Count; 
               int i = 1; 
               foreach (KeyValuePair> item in ressourceCollection) { 
                  string value = string.Empty; 
                  try { 
                     value = item.Value[lang]; 
                  } 
                  catch { 
                     try { 
                        value = item.Value["EN"]; 
                     } 
                     catch { } 
                  } 
                  strBuilder.AppendFormat(@"""{0}"" : ""{1}""", item.Key, value); 
                  strBuilder.Append(","); 
                  strBuilder.AppendLine(); 
                  i++; 
               } 
            } 
         }); 
         strBuilder.Remove(strBuilder.Length - 3, 1); 
         strBuilder.AppendLine("}"); 
         builder.InnerHtml = strBuilder.ToString(); 
         return new MvcHtmlString(builder.ToString()); 
      } 

      public static void RegisterProvider(IResourceService provider) 
      { 
         _resources = provider; 
      }
      
      private void CheckProvider()
      {
         if (null == _resources)
            throw new Exception("Resource provider is not set");
      }
   } 
}

I have created two ways to do this. The first, “GetResource”, allows you to call the resource you want to display in html. The second, “GetJSONResources”,  allows you to serialize the complete resource into a Json object in order to use resources with Javascript. It takes an array of string parameters because you can serialize several resources (defined as “Dictionary” in the resource container described at the beginning of this article).

As this helper requires an IResourceService instance, you must register an instance when the application starts, as follows:

using MVC.Helpers; 
using MyApp.Globalization; 
using System.Web.Mvc; 
using System.Web.Routing; 

namespace MVC 
{ 
   public class MvcApplication : System.Web.HttpApplication 
   { 
      protected void Application_Start() 
      { 
         AreaRegistration.RegisterAllAreas(); 
         RouteConfig.RegisterRoutes(RouteTable.Routes); 
         FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
         
         IResourceService r = new ResourceService(); 
         ResourceHelper.RegisterProvider(r); 
         CustomDisplayNameAttribute.RegisterProvider(r); 
      } 
   } 
}
  •  Attribute on Models (for managing Model labels into a html form) :
using MyApp.Globalization; 
using System.ComponentModel; 
namespace MVC 
{ 
   public class CustomDisplayNameAttribute : DisplayNameAttribute 
   { 
      private static IResourceService _resourceService; 
      private string _resourceName; 
      private string _resourceKey;

      public CustomDisplayNameAttribute(string resourceName, string resourceKey) 
      { 
         _resourceName = resourceName; 
         _resourceKey = resourceKey; 
      } 

      public override string DisplayName 
      { 
         get 
         { 
            CheckProvider();
            return _resourceService.GetResource(_resourceName, _resourceKey); 
         } 
      } 

      public static void RegisterProvider(IResourceService provider)
      {
         _resources = provider;
      }
 
      private void CheckProvider()
      {
         if (null == _resourceService)
            throw new Exception("Resource provider is not set");
      }
}

namespace MVC.Models 
{ 
   public class TestModel 
   { 
      [CustomDisplayName("Home", "EnterYourNationalityKey")] 
      public string Name { get; set; } 
   } 
}

Like the previous HtmlHelper you need to register also an IResourceService instance

  • Using directly the IResourceService into a MVC Controller :
using MyApp.Globalization; 
using System.Web.Mvc; 

namespace MVC.Controllers 
{ 
   public class HomeController : Controller 
   { 
      private IResourceService _resourceService;

      public HomeController() : this(new ResourceService()) { } 

      public HomeController(IResourceService resourceService) 
      { 
         _resourceService = resourceService; 
      } 

      // GET: /Index/ 
      public ActionResult Index() 
      { 
         ViewData["HelloWorld"] = _resourceService.GetResource("Home", "HelloWordKey"); 
         return View(); 
      } 
   } 
}

I recommend you use Injection dependency. I will not describe it in this article, but I have “prepared” this controller in order to use this pattern with this constructor “public HomeController(IResourceService resourceService)”

Step 6: Test Tools in an HTML Page

@using MVC.Helpers 
@model MVC.Models.TestModel 

@{ ViewBag.Title = "Index"; } 
<h2>@Html.Raw(ViewData["HelloWorld"])</h2> 
<h3>@Html.GetResource("Home", "MyNameKey")</h3> 
<br /> @Html.LabelFor(m=> m.Name) 
<br /> @Html.TextBoxFor(m=> m.Name) 
@Html.GetJSONResources(new string[] { "Home" }) 

<script type="text/javascript"> alert(MyApp.Resources.HelloWordKey + "n" + MyApp.Resources.MyNameKey); </script>

 

As you can see, there is a sample of each implemented tool:

  • @Html.GetResource(“Home”, “MyNameKey”) as simple HtmlHelper in order to access to a specific asked resource
  • @Html.Raw(ViewData[“HelloWorld”]) as ViewData setted into the MVC Controller by accessing directly to IResourceService (_resourceService.GetResource(“Home”, “HelloWordKey”);)
  • @Html.GetJSONResources(new string[] { “Home” }) as HtmlHelper wich serialize a resource into a JSON object
  • @Html.LabelFor(m=> m.Name) as a translated Model label

And now for the result:

Sample 1: French language as default language on browser

chix-langue.png

french-default.png

Source code :

<!DOCTYPE html> 
   <html> 
      <head> 
         <meta charset="utf-8" /> 
         <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
         <title>MyApp</title> 
      </head> 
      <body> 
         <h2>Bonjour le monde!</h2> 
         <h3>Mon pr&amp;#233;nom est Anthony</h3> 
         <br /> 
         <label for="Name">De quelle nationalit&amp;#233; &amp;#234;tes-vous?</label> 
         <br /> 
         <input id="Name" name="Name" type="text" value="" /> 
         <script type="text/javascript"> 
            var MyApp = MyApp || {}; 
            MyApp.Resources = MyApp.Resources || {}; 
            MyApp.Resources = { "HelloWordKey" : "Bonjour le monde!", 
                                "MyNameKey" : "Mon prénom est Anthony", 
                                "EnterYourNationalityKey" : "De quelle nationalité êtes-vous?" 
                              } 
         </script> 
         <script type="text/javascript"> 
            alert(MyApp.Resources.HelloWordKey + "n" + MyApp.Resources.MyNameKey); 
         </script> 
          </body> 
	    </html>

 

Sample 2: German language as default language on browser (as German is not managed, it will be managed in English by default)

choix-langue 1

english-default.png

Source code :

<!DOCTYPE html> 
<html> 
      <head> 
         <meta charset="utf-8" /> 
         <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
         <title>MyApp</title> 
      </head> 
      <body> 
         <h2>Hello World!</h2> 
         <h3>My name is Anthony</h3> 
         <br /> 
         <label for="Name">What&amp;#39;s your nationality</label> 
         <br /> 
         <input id="Name" name="Name" type="text" value="" /> 
         <script type="text/javascript"> 
            var MyApp = MyApp || {}; 
            MyApp.Resources = MyApp.Resources || {}; 
            MyApp.Resources = { "HelloWordKey" : "Hello World!", 
                                "MyNameKey" : "My name is Anthony", 
                                "EnterYourNationalityKey" : "What's your nationality" 
                              } 
         </script> 
         <script type="text/javascript"> 
            alert(MyApp.Resources.HelloWordKey + "n" + MyApp.Resources.MyNameKey); 
         </script> 
      </body> 
</html> 

Sample 3 :  French language as default browser language and select into a form english language (stored in cookie after selection)

select-en

Reselect french by form action :

french-default1.png

 

I hope this article has helped you to easily translate your ASP.NET application 😉

Asynchronicity: Understanding the concepts of asynchronous tasks, parallel tasks and background tasks

Asynchronous programming is a set of techniques to implement expensive operations which are performed simultaneously with the rest of the program. Asynchronous programming is often used in the context of programs with a graphical user interface: it is generally unacceptable to freeze a user interface during the course of a time-consuming operation. In addition, asynchronous operations are important for server applications that need to manage multiple client requests simultaneously.

Background tasks

Sometimes when you execute an action, you do not need to wait for the result of this action, so you return the focus to the user for further events, for example, when you send an image to the server, the image resizing operation can be performed in the background. Here’s how to execute a task and to return the focus to the user : You just need to run a task with Task.Run() static method (available from .NET 4.5) If you work with .NET 4.0 Framework you need to use Task.Factory.StartNew() static method

using System;
using System.Threading.Tasks;

namespace MyApp
{
    public class TestClass
    {
        public void DoWork()
        {
            Task.Run(() => { /* do something */});
        }
    }
}

You can read here the difference between there two methods : Task.Run vs Task.Factory.StartNew If you work with .NET 4.5.2 Framework you can do more : background tasks with .NET 4.5.2

Parallel tasks

Sometimes you have several  independents actions of each other to execute, thus when you run the second task after the previous one had been completed, we say they are executed synchronously, to gain speed of execution and return control to the user faster we can execute asynchronously between it, in other words we parallelize these tasks : here’s how: I will use Task.Run() static method (available from .NET 4.5), but as the latest paragraph if you are using .NET 4.0 Framework you can use Task.Factory.StartNew() static method

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public void DoWork()
        {
            /*Build an array of tasks wich return a value*/
            Task[] tasks = new Task[3];

            /*Define each tasks to parallelize*/
            tasks[0] = Task.Run(() => { Thread.Sleep(4000); 
                                                return true; });
            tasks[1] = Task.Run(() => { Thread.Sleep(3000); 
                                                return 1; });
            tasks[2] = Task.Run(() => { Thread.Sleep(5000); 
                                                return "True"; });

            /*Wait for all tasks execution are completed*/
            Task.WaitAll(tasks);

            /*Get an array of values returned by parallelized tasks array*/
            object[] results = tasks.Select(m => m.Result).ToArray();

            /*Get each values*/
            bool result0 = (bool)results[0];
            int result1 = (int)results[1];
            string result2 = (string)results[2];
        }
    }
}

1- I define an array of tasks

2- I add in the array each tasks i want to parallelize

3- I perform all tasks and I expect that all tasks are completed

4- I extract results form each task

5- I get each value with it type from the array of results

Under these conditions , total time of execution will take 5 sec VS 12 sec in synchronously conditions Same same reasoning without results back :

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public void DoWork()
        {
            //Build an array of tasks wich return a value
            Task[] tasks = new Task[3];

            //Define each tasks to parallelize
            tasks[0] = Task.Run(() => { Thread.Sleep(4000); });
            tasks[1] = Task.Run(() => { Thread.Sleep(3000); });
            tasks[2] = Task.Run(() => { Thread.Sleep(5000); });

            //Wait for all tasks execution are completed
            Task.WaitAll(tasks);
        }
    }
}

Asynchronous tasks

Asynchronicity is essential for activities that are potentially blocking, such as when your application accesses the web. Access to a web resource sometimes is slow or delayed. If such an activity is blocked within a synchronous process, the entire application must wait. In an asynchronous process, the application can continue with other work that doesn’t depend on the web resource until the potentially blocking task finishes. Examples how it works with a back result and not :

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public async Task DoSimpleWorkAsync()
        {
            bool value = await Task.Run(() => { Thread.Sleep(4000); 
                                                return true; });
            return value;
        }

        public async Task DoSimpleWork2Async()
        {
            await Task.Run(() => { Thread.Sleep(4000); });
        }
    }
}

Keywords async / await are required – The marked async method can use Await or await to designate suspension points. The await operator tells the compiler that the async method can’t continue past that point until the awaited asynchronous process is complete. In the meantime, control returns to the caller of the async method. – The suspension of an async method at an await expression doesn’t constitute an exit from the method, and finally blocks don’t run. – The marked async method can itself be awaited by methods that call it.

Mix asynchronous tasks and parallelization

It’s possible to parallelize asynchronous tasks, let’s reuse previous examples :

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public async void DoWork()
        {
            //Build an array of tasks wich return a value
            Task[] tasks = new Task[3];

            //Define each tasks to parallelize
            tasks[0] = Task.Run(() => { Thread.Sleep(4000); 
                                                return true; });
            tasks[1] = Task.Run(() => { Thread.Sleep(3000);
                                                return 1; });
            tasks[2] = Task.Run(() => { Thread.Sleep(5000); 
                                                return "True"; });

            //Wait for all tasks execution are completed
            await Task.WhenAll(tasks);

            //Get an array of values returned by parallelized tasks array
            object[] results = tasks.Select(m => m.Result).ToArray();

            //Get each values
            bool result0 = (bool)results[0];
            int result1 = (int)results[1];
            string result2 = (string)results[2];
        }
    }
}

Note that it is very important not to use Task.WaitAll () but Task.WhenAll () when keywords async / await, Task.WaitAll () is intended to be used with synchronous tasks and Task is used . WhenAll () with asynchronous tasks! Synchronous and asynchronous tasks do not mix! 😉

Mix asynchronous tasks and background tasks

Sometimes it could be interesting to launch tasks in background, but these tasks could be asynchronous , in order to launch non blocking tasks in background, for example it could be usefull to use this way when several longs tasks (potentially blocking) are launched on the server when when server activity is already elevated

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public async void DoWork()
        {
            await Task.Run(() => { Thread.Sleep(4000); });
        }
    }
}

Another syntax works but i worse than the first shown previlously, if an exception occurs , with async void, exception will be “observed” unlike the following with async Task:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;

namespace MyApp
{
    public class TestClass
    {
        public async Task DoWork()
        {
            await Task.Run(() => { Thread.Sleep(4000); });
        }
    }
}

I hope this article has helped you understand the world of asynchronicity, the future of computing! 😉

Exploring QueueBackgroundWorkItem in ASP.NET and Framework 4.5.2

Sometimes it’s very useful for long running tasks that don’t need to complete before returning a response to the user in ASP.NET application.

But before  .NET 4.5.2 release , we were not sure that these tasks have been executed safely.

In the release notes, QueueBackgroundWorkItem is summarized as follows:

HostingEnvironment.QueueBackgroundWorkItem lets you schedule small background work items. ASP.NET tracks these items and prevents IIS from abruptly terminating the worker process until all background work items have completed.

The benefit from this is reliably. If you use HostingEnvironment queue in an ASP.NET application, any background tasks are guaranteed to execute safely.

How does QueueBackgroundWorkItem works ?, as follow :

using System.Web.Mvc;
using System.Web.Hosting;

namespace MyApp.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            HostingEnvironment.QueueBackgroundWorkItem(clt =>
            {
                //Background task that needs to be performed safely
            });
            return View();
        }

    }
}

Note that HostingEnvironment.QueueBackgroundWorkItem belongs to System.Web.Hosting NameSpace.

This method defines two overloads:

  • Action
  • Func

Firstly, here are samples with Action overload :

We will define long running actions : a classical Task and an async Task:

using System.Web.Mvc;
using System.Web.Hosting;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace MyApp.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            HostingEnvironment.QueueBackgroundWorkItem(clt=>
            {
                //Background task that needs to be performed safely
            });
            return View();
        }

        //Action overload's target
        private void LongRunningAction(CancellationToken clt)
        {
            Task.Run(() => { Thread.Sleep(5000);
                             Debug.WriteLine("Action executed"); 
                           });
        }

        //Action overload's target
        private async void LongRunningActionAsync(CancellationToken clt)
        {
            await Task.Run(() => { Thread.Sleep(5000); 
                                   Debug.WriteLine("Action async executed"); 
                                 });
        }
    }
}

Now let’s see ways to use it:

using System.Web.Mvc;
using System.Web.Hosting;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System;

namespace MyApp.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            //Sample 1
            //Action overload
            //with lambda expression
            HostingEnvironment.QueueBackgroundWorkItem(
                clt => LongRunningAction(clt)
            );

            //Sample 2
            //Action overload
            //without lambda expression
            HostingEnvironment.QueueBackgroundWorkItem(
                (Action)LongRunningAction
            );

            //Sample 3
            //Action overload
            //with lambda expression
            HostingEnvironment.QueueBackgroundWorkItem(
                clt => LongRunningActionAsync(clt)
            );

            //Sample 4
            //Action overload
            //without lambda expression
            HostingEnvironment.QueueBackgroundWorkItem(
                await (Action)LongRunningAction
            );

            return View();
        }

        //Action overload's target
        private void LongRunningAction(CancellationToken clt)
        {
            Task.Run(() => { Thread.Sleep(5000); 
                             Debug.WriteLine("Action executed"); 
                           });
        }

        //Action overload's target
        private async void LongRunningActionAsync(CancellationToken clt)
        {
            await Task.Run(() => { Thread.Sleep(5000); 
                                   Debug.WriteLine("Action async executed"); 
                                 });
        }
    }
}

As you can see, you can execute Actions, with Lambda expression syntax (sample 1) or not (sample 2)

You can also execute async Actions, with Lambda expression syntax (sample 3) or not (sample 4)

Secondly, here are samples with Func overload :

We will define a function that return a long running Task :

using System.Web.Mvc;
using System.Web.Hosting;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace MyApp.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            HostingEnvironment.QueueBackgroundWorkItem(
                clt => { }
            );

            return View();
        }

        //Func overload's target
        private Task LongRunningFunc(CancellationToken clt)
        {
            return Task.Run(() => { Thread.Sleep(5000); 
                                    Debug.WriteLine("Func executed"); 
                                  });
        }
   
    }
}

Let’s see ways to use it :

using System.Web.Mvc;
using System.Web.Hosting;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System;

namespace MyApp.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            //Sample 5
            //Func overload
            //With lambda expression
            HostingEnvironment.QueueBackgroundWorkItem(
                clt => LongRunningFunc(clt)
            );

            //Sample 6
            //Func overload
            //Without lambda expression
            HostingEnvironment.QueueBackgroundWorkItem(
                (Func)LongRunningFunc
            );

            //Sample 7
            //Func overload
            //With lambda expression
            //Accept async / await
            HostingEnvironment.QueueBackgroundWorkItem(
                async clt => await LongRunningFunc(clt)
            );

            return View();
        }

        //Func overload's target
        private Task LongRunningFunc(CancellationToken clt)
        {
            return Task.Run(() => { Thread.Sleep(5000); 
                                     Debug.WriteLine("Func executed"); 
                                  });
        }
   
    }
}

As you can see, you can execute functions, with Lambda expression syntax (sample 5) or not (sample 6)

You can also use async / await keywords to execute the function (sample 7)

Summary

As you’ve seen, the new QueueBackgroundWorkItem method is very easy to use with different delegate parameters. ASP.NET does the heavy lifting for us by preventing IIS from terminating worker processes when there are any pending background work items. Consequently, HostingEnvironment.QueueBackgroundWorkItem is an ideal candidate for scheduling small background jobs in .NET 4.5.2.

I have chosen an ASP.NET MVC for this article, of course, you can call the QueueBackgroundWorkItem method from another web application type (such as WebForm, and also WCF!), this is not exclusive to MVC.