Introduction

In WebAPI (part of mvc 4), controllers are view-agnostic. They do not return data to a view – rather they return pure, formatted data (either JSON or XML – see Appendix A). The client can be a javascript enabled browser that can populate its UI from the JSON or any other client that can parse XML.

Synchronous Controller ( Action ) Methods

This is what an action method in a webapi controller (ValuesController) looks like:

/// <summary>

        /// This action does not render any view - APIController just returns data (as XML or JSON). 

        /// Here we return only JSON (see WebApiConfig for configuration that forces JSON formatting)

        /// <returns>JSON formatted Product object</returns>

        public Product Get()

        {

            Thread.Sleep(5000); // simulate long wait 

            return new Product

            {

                Name = "Soda",

                Price = 2.00M,

                ProductCode = 1

            };

        }

 

        public class Product

        {

            public string Name { get; set; }

            public decimal Price { get; set; }

            [JsonIgnore]

            public int ProductCode { get; set; } // omitted

        }

If you GET the Product (localhost/api/values), you should see the browser tied up – waiting for the 5 seconds that we have delayed the Get call.

waiting

Async Await Controller

To avoid tying up the browser, you can make your GET method async. This is a simple exercise – as shown in the example below.

public Product Get()

        {

            var t = LongRunningTaskAsync();

            if(t.IsCompleted) 

              return t.Result;

 

            return null;

        }

 

        // now call the same longrunningtask using async await

        private async Task<Product> LongRunningTaskAsync()

        {

            var func = Task<Product>.Factory.StartNew(GetProductLongRunningTask);

            return await func;

        }

 

        // simulate long wait with thread.sleep

        private Product GetProductLongRunningTask()

        {

            Thread.Sleep(5000); // simulate long wait 

            return new Product

            {

                Name = "Soda",

                Price = 2.00M,

                ProductCode = 1

            };

        }

The steps are:

  1. Mark your long running method as async (the GET action method would call this async method )
  2. Use a Task<Product> to return a Product object
  3. Use a factory method (Task<Product>.Factory.StartNew() ) to start the Task
  4. await the result from the async task
  5. Use the .Result property (of the awaited task) to get your Product object.

Another Example – Mvc.Controller Action Method

Using the same steps as above, we can write an async version of a regular (non webapi) controller method.

public class AccountController : Controller

    {

        [HttpRoute("accounts")]

        public async Task<GetAccountsResponse> GetAccountsAsync([FromUri]GetAccountsRequest acctRequest)

        {

            var requestDispatcher = IoC.Container.Resolve<IRequestDispatcher>();

    

            return await Task<GetAccountsResponse>.Factory.StartNew( () => 

            {

               var response = requestDispatcher.Get<GetAccountsResponse>(acctRequest);

               return response;

            });

        }

 

        [HttpRoute("accounts")]

        public GetAccountsResponse GetAccountsSynchronous([FromUri]GetAccountsRequest acctRequest)

        {

            var requestDispatcher = IoC.Container.Resolve<IRequestDispatcher>();

 

            var response = requestDispatcher.Get<GetAccountsResponse>(acctRequest);

 

            return response;

        }

    }

Summary

Using async and await, one can turn a regular controller action into an async action – thereby avoiding a ‘waiting’ UI. Another task can be launched while you are awaiting the results from the long running task.

Appendix A – Ensure that only JSON is returned by the WebApi controller action.

In MVC 4, here are two different route config files:

  1. RouteConfig.cs which has the regular MVC 4.0 application controller routes.
  2. WebApiConfig.cs which contains routes for the WebAPI controllers.

Modify WebApiConfig.cs as follows (so that it does not default to XML formatting for return data)

public static class WebApiConfig

   {

 

       public static void Register(HttpConfiguration config)

       {

           config.Routes.MapHttpRoute(

               name: "DefaultApi",

               routeTemplate: "api/{controller}/{id}",

               defaults: new { id = RouteParameter.Optional }

           );

           // to default to JSON, remove the XML formatter

           var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");

           config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);

       }

       

   }

Anuj holds professional certifications in Google Cloud, AWS as well as certifications in Docker and App Performance Tools such as New Relic. He specializes in Cloud Security, Data Encryption and Container Technologies.

Initial Consultation

Anuj Varma – who has written posts on Anuj Varma, Hands-On Technology Architect, Clean Air Activist.