What is WebApi?
This question carries a lot of weight. Web API is a small word but it has lots of extensive features.
Here is an excerpt about Web API:
ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. It is an ideal platform for building RESTful applications on the .NET Framework. This poster shows how an HTTP request flows through the Web API pipeline, and how the HTTP response flows back. The diagram also shows extensibility points, where you can add custom code or even replace the default behavior entirely.
This article is about WebApi and its Pipeline. Pipeline in simple words is HttpRequest as pipeline and HttpResponse as an output. Kindly refer to the image below:
This will be an agenda for this article as shown below:
- WebApi Definition.
- WebApi Pipeline architecture
- WebApi Hosting
- WebApi HttpRequest & HttpResponse Message format
- WebApi Delegate Handler
- Routing Dispatcher and per-route message handler
- HttpControllerDispatcher
- Authentication & Authorization Filters
- Model Binders, Value Providers and Action Filters
- IHttpActionInvoker & Exception Filters
- Result Conversation
Web API Definition
ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. It is an ideal platform for building RESTful applications on the .NET Framework. This poster shows how an HTTP request flows through the Web API pipeline, and how the HTTP response flows back. The diagram also shows extensibility points, where you can add custom code or even replace the default behavior entirely.
Web API Architecture
Here is typical pipeline architecture for Web API as in the following screenshot:
Web API Hosting
You can host Web API inside IIS or inside your own process (self-hosting).
ASP.NET Hosting
You can host Web API on ASP.NET server and IIS server. For more details kindly go through the following details how to host Web API in IIS: WebApi Hosting in Internet Information Server (IIS 7.5).
Self-Hosting using OWIN
In Self Hosting you can use OWIN to Self-Host ASP.NET Web API, The HttpServer pipeline starts at the HttpSelfHostServer which is an implementation of HttpServer and directly listens to HTTP requests.
WebApi HttpRequest & HttpResponse Message format
The HTTP request message is first converted to an HttpRequestMessage object, which provides strongly typed access to the HTTP message. There are two types of Http messages HttpRequest and HttpResponse. Each of this has their own format before sending it to respective server and received response from server.
The structure of HttpRequestMessage format is as follows with a pictorial representation.
- <request-line>
- <general-headers>
- <request-headers>
- <entity-headers>
- <empty-line>
- [<message-body>]
- [<message-trailers>]
The structure of HttpResponseMessage format is as follows with a pictorial representation.
- <Status-line>
- <general-headers>
- <response-headers>
- <entity-headers>
- <empty-line>
- [<message-body>]
- [<message-trailers>]
This is the way to understand the HttpRequest and HttpResponse messages.
Web API Delegate Handler
HTTP message handlers are the first stage in the processing pipeline after the request leaves the service host. Further it travels in pipeline as HttpRequestMessage in Pipeline. They process HTTP request messages on the way in, and HTTP response messages on the way out. To create a custom message handler, derive from the DelegatingHandler class. You can add multiple message handlers. Message handlers can be global or assigned to a specific route and called as per-route message handler. Per-route message handler is invoked only when the request matches that route. Per-route message handlers are configured in the routing table. A message handler can create the response directly, skipping the rest of the pipeline.
Delegate handlers are extensibility points which you can customize as per your need. One of the reasons may be to verify the request authenticity and to verify some potential information in the http request .You may also customize the Http response as well and customize messages. A message handler can create the response directly, skipping the rest of the pipeline. Kindly refer to the below image for reference to register global handler in pipeline. There is an example, how a message handler might help you,
- Read or modify request headers.
- Add a response header to responses.
- Validate requests before they reach the controller.
config.MessageHandlers.Add(new CustomHandler_One());
Routing Dispatcher and per-route message handler
After registering global handler and its execution request reaches HttpRouteDispatcher and sends it further in pipeline. HttpRoutingDispatcher dispatches the request based on the route. As per the WebApi Pipeline diagram above HttpRouteDispatcher verifies whether Route handler is null or contains any handler and takes an anticipated action on the basis of that. Delegate handlers give you the privilege to customize the pipeline and allow you to skip the pipeline. You can add a message handler to a specific route when you define the route there i s a typical image which describes multiple handlers globally and per route handler in pipeline.
Reference
Image Source: asp.net
If you notice in above image that MessageHandler2 doesn’t go to the default HttpControllerDispatcher. Here, MessageHandler2 creates the response, on basis of requests that match "PerRoute" never go to a controller further and skips the pipeline. Kindly refer to the code shown below to register the Per-Route handler in WebApiConfig.cs file as shown below in screen shot and code segment as well.
- public static class WebApiConfig
- {
- public static void Register(System.Web.Http.HttpConfiguration config)
- {
- config.MapHttpAttributeRoutes();
- config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new
- {
- id = RouteParameter.Optional
- });
- config.MessageHandlers.Add(new CustomHandler_One());
- config.Routes.MapHttpRoute(name: "PerRoute", routeTemplate: "api2/{controller}/{action}/{id}", defaults: new
- {
- id = RouteParameter.Optional
- }, constraints: null, handler: new CustomHandler_Two()
-
-
-
- );
- }
- }
If you want “PerRoute” handler to execute complete WebApi pipeline as well as further reach to HttpControllerDispatcher then you just require registering PerRoute handler in WebApiConfig as given below in code segment.
- public static class WebApiConfig
- {
- public static void Register(System.Web.Http.HttpConfiguration config)
- {
- config.MapHttpAttributeRoutes();
- config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new
- {
- id = RouteParameter.Optional
- });
- config.MessageHandlers.Add(new CustomHandler_One());
- config.Routes.MapHttpRoute(name: "PerRoute", routeTemplate: "api2/{controller}/{action}/{id}", defaults: new
- {
- id = RouteParameter.Optional
- }, constraints: null,
-
- handler: HttpClientFactory.CreatePipeline(new HttpControllerDispatcher(config), new DelegatingHandler[]
- {
- new CustomHandler_Two()
- }));
- }
- }
HttpControllerDispatcher
HttpControllerDispatcher sends the request to a Web API controller.
HttpControllerDispatcher is related to Delegate handler somewhere because whenever you create any custom handler it calls SendAsync(request, cancellationToken) method which redirects call to inner Handler and generally this inner handler is HttpControllerDispatcher which handles the controller action request. Kindly refer one of the following screen:
This is one of the execution flow of HttpRequest starts from HttpMessageHandler till controller descriptor and Action selector as per my understanding as shown below,
Authentication & Authorization Filters
If I think deeply about an above picture than security is an always a major concern in Web-based applications. You should have proper set of implementation in form of Authenticaiton and authorization technique to secure that data. As you know that ASP.Net Web API is a lightweight framework used for building stateless RESTful services that run on HTTP. There is authentication filter introduced in WebApi2. Authentication filters allows you to create an authentication scheme for individual controllers or actions. Both of these works in a pattern like given below:
- Authentication proves the identity of the client.
- Authorization determines whether the client can access a particular resource. To implement Authentication filters class should implement System.Web.Http.Filters.IAuthenticationFilter interface.
The IAuthenticationFilter interface has two methods
- AuthenticateAsync authenticates the request by validating credentials in the request, if present.
- ChallengeAsync adds an authentication challenge to the HTTP response, if needed.
Here is the flow in the Web API 2 pipeline using Authentication and Authorization filter
- Web API creates an authentication filters before invoking an action. Authentication filter can be apply at action scope, controller scope, and global scope.
- Web API calls AuthenticateAsync on every filter. Each filter validates credentials in the request. If any filter successfully validates credentials, the filter creates an IPrincipal and attaches it to the request. If an error occurs at filter level than it skips the rest of the WebApi pipeline.
- Suppose if there is no error, the HttpRequest goes and execute through the rest of the pipeline.
- Finally, Web API calls every authentication filter’s ChallengeAsync method. Filters use this method to add a challenge to the response, if needed. Sometime it happens in response to a 401 error.
- The diagram showed below states a possibility and its execution flow. The authentication filter successfully authenticates the HttpRequest, an authorization filter authorizes the request, and the controller action returns 200 (OK). Reference http://asp.net
Authentication filter has two methods AuthenticateAsync and ChallengeAsync as shown below in code snippet. The primary purpose of the ChallengeAsync is to manage and add challenge in response. There is a class named as ResultWithChallenge below in code segment which is responsible to call ExecuteAsync and further calls InnerResult. ExecuteAsync to create the HTTP response, and then adds the challenge if needed.
- public class CustomAuthenticationFilterAttribute: Attribute, IAuthenticationFilter
- {
- #region IAuthenticationFilter Members
- public System.Threading.Tasks.Task AuthenticateAsync(HttpAuthenticationContext context, System.Threading.CancellationToken cancellationToken) {
- return Task.FromResult(0);
- }
- public System.Threading.Tasks.Task ChallengeAsync(HttpAuthenticationChallengeContext context, System.Threading.CancellationToken cancellationToken) {
- context.Result = new CustomResultChallenge(context.Result, "Authentication Failed!!!");
- return Task.FromResult(0);
- }
- #endregion# region IFilter Members
- public bool AllowMultiple
- {
- get
- {
- return false;
- }
- }#endregion
- }
Let’s verify that how does WebApi respond from ChallengeAsync with Unauthorized status. Press F5 and see WebApi is running after getting below screen shot:
Send the Get request in order to verify the execution cycle as given below. Copy and paste the following Url (http://localhost:57888/api/employees/GetEmp/5) in PostMan tool as depicted below in screen shot.
As soon as you click on the send button it reaches to Custom value provider’s method to execute set of statement and gives you following output in an image shown below:
Model Binders, Value Providers
Model binding uses the request to create values for the parameters of the action .These values are passed to the action when the action is invoked or binding is a mechanism used by the WebApi to mapping request to an object defined in the controller. Model binding is the process of creating .NET objects using the data sent by the browser in an HTTP request. We have been relying on the model binding process each time defines an action method that takes a parameter. the parameter objects are created by model binding. Model binding is ASP.NET mechanism for mapping HTTP request data directly into action method parameters and custom .Net objects.
- For example, when we receive a request for a URL such as "/Home/ Employees/23", the framework must map the details of the request in such a way that it can pass appropriate values or objects as parameters to our action method. A model binder gets raw input values from a value provider and later value provider takes the HTTP request and populates a dictionary of key-value pairs. Further the model binder uses this dictionary to populate the model.
The action invoker, the component that invokes action methods, is responsible for obtaining values for parameters before it can invoke the action method.
Value Providers
Value Providers are the components that feed data to model binders. Feeding the data means installing the data to the Model binder for further use at the action level. Value provider takes the HTTP request and populates a dictionary of key-value pairs which is later used by model binder to populate the model.
The framework contains a few built-in value providers named FormValueProvider, RouteDataValueProvider, QueryStringValueProvider and HttpFileCollectionValueProvider that fetch data from Request.Form, Request.QueryString, Request.Files and RouteData.Values.
The code shown below for CustomValueProvider used at this application level as well as way to use it at action level in an image shown below:
- public class CustomHeaderValueProvider: IValueProvider
- {
- #region IValueProvider Members
- public Dictionary < string, string > objCollection;
- public CustomHeaderValueProvider(HttpActionContext context)
- {
- objCollection = new Dictionary < string, string > ();
- foreach(var item in context.Request.Headers)
- {
- objCollection.Add(item.Key, string.Join(string.Empty, item.Value));
- }
- }
- public bool ContainsPrefix(string prefix)
- {
- return objCollection.Keys.Contains(prefix);
- }
- public ValueProviderResult GetValue(string key)
- {
- string resultValue;
- if (key == null) throw new Exception("NullReferenceException");
- if (objCollection.TryGetValue(key, out resultValue))
- {
- return new ValueProviderResult(resultValue, resultValue, System.Globalization.CultureInfo.InvariantCulture);
- }
- return null;
- }#endregion
- }
- public class CustomValueProviderFactory: ValueProviderFactory
- {
- public override IValueProvider GetValueProvider(HttpActionContext actionContext)
- {
- return new CustomHeaderValueProvider(actionContext);
- }
- }
At the time of the model binding the DefaultModelBinder checks with the value providers to determine if they can return a value for the parameter (example empId) by calling the ContainsPrefix method. If none of the value providers registered can return then it checks through CustomtvalueProvider whether such a parameter is stored and if yes it returns the value.
This is one of the best pictorial representations taken from http://asp.net site is shown below which is again self-explanatory.
Image taken from http://asp.net
Kindly refer this link for more understanding on Model Binder
Invoke Action with Model Binders and
Fetch Header Information Using CustomValueProvider in ASP.NET Web API
IHttpActionInvoker & Action Filters
Once ApiControllerActionInvoker selects an action to handle an HTTP request, and is responsible for producing HttpResponse of your action. The action invoker, the component that invokes action methods, is responsible for obtaining values for parameters before it can invoke the action method. In other words, the invoker gets an instance of HttpActionContext and is expected to produce an HttpResponseMessage out of it. For this purpose it has to invoke an ExecuteAsync method on the
HttpActionDescriptor present on the HttpActionContext
Action Invoker can be a point to manage your exception at global level and returns a response on basis of the result returned by action method of controller. There is an interface shown given below to implement custom action invoker which has method to implement as shown below:
- public interface IHttpActionInvoker{
- Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken);
- }
There can be three possible scenarios which can be maintained at ActionInvoker level,
- You action returns an object than it has to convert into HttpResponseMessgae by IActionResultConverter and run content negotiation with the help of request.createResponse().
- If action returns IHttpActionResult than it can be convert into HttpResponseMessage at action invoker level. Which gives privilege to mold your response at this level?
- It can return HttpResponseMessage directly from action method.
I’ve created Custom action invoker at my application level to achieve Exception Handling after returning result by the action and later apply code at action invoker level to change it into HttpResponseMessege.
- public class Custom_ControllerActionInvoker: ApiControllerActionInvoker, IHttpActionInvoker
- {
- public override System.Threading.Tasks.Task < System.Net.Http.HttpResponseMessage > InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) {
- var objResult = base.InvokeActionAsync(actionContext, cancellationToken);
- actionContext.Request.Properties["RuntimeReturnType"] = objResult.GetType();
- if (objResult.Exception != null)
- {
- Debug.WriteLine("Exception thrwon by controller {0} :", actionContext.ControllerContext.Controller);
- return Task.Run < HttpResponseMessage > (() => new HttpResponseMessage(HttpStatusCode.InternalServerError));
- } else if (objResult.Result.StatusCode == HttpStatusCode.Forbidden)
- {
-
- Debug.WriteLine("Exception thrwon by controller {0} :", actionContext.ControllerContext.Controller);
- return Task.Run < HttpResponseMessage > (() => new HttpResponseMessage(objResult.Result.StatusCode));
- }
- return objResult;
- }
- }
Kindly find a screen shot and code segment to register CustomActionInvoker in an application as shown below:
- GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionInvoker), new Custom_ControllerActionInvoker());
Action Filters
Custom filters and attributes are an excellent way to inject extra processing logic into the MVC request response pipeline. At some level programmer would be happy to inject some pre-processing or post-processing logic for actions and controllers. In that case we use filters.
This filter will be called before and after the action starts executing and after the action has executed. It comes under namespace using System.Web.Http.Filters;
OnActionExecuting occurs just before the action method is called.
OnActionExecuted occurs after the action method is called, but before the result is executed (before the view is rendered).
- public class CustomActionWebApiFilters: ActionFilterAttribute
- {
- public override void OnActionExecuting(HttpActionContext actionContext)
- {
-
- Debug.WriteLine("Action just added pre-processing logging/information...");
- }
- public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
- {
-
- }
- }
I’ve also added Exception filter to manage exception at code level an the respective code shown below:
- public class CustomExceptionFilterAttribute: ExceptionFilterAttribute
- {
- public override void OnException(HttpActionExecutedContext actionExecutedContext)
- {
- if (actionExecutedContext.Exception is ArgumentException)
- {
- actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
- }
- }
- }
Kindly find a way to register an Exception filter in global.asax file as given below as well as uses at controller’s action level.
- GlobalConfiguration.Configuration.Filters.Add(new CustomExceptionFilterAttribute());
IHttpActionInvoker can be applying to manage Exception at action level.
IHttpActionInvoker can be used to read runtime context sent by action and made further amendment to send it further as HttpResponseMessage.You may learn more about Action filters in WebApi from this
link.
Result Conversation
As name implies Result conversation is about to convert return value from action in form of HttpResponseMessege.The result returned by the an action can be in multiple form and those forms are given below with pictorial representation taken from
Image taken from http://asp.net
- HttpResponseMessege: If return type is HttpResponseMessage sent it directly.
- Void : If return type is void, create response with status 204 (No Content)
- IHttpActionResult: Call ExecuteAsync to create an HttpResponseMessage, and then convert to an HTTP response message.
- Other Types: For return types, Web API uses a media formatter to serialize the return value. Web API writes the serialized value into the response body. The response status code is 200 (OK).
IHttpActionResult plays a vital role in HttpResponseMessege category ,because it allows you return your own return set after introducing in WebAPI2 .There are few advantages of IHttpActionResult are listed below:
- Moves common logic for creating HTTP responses into separate classes. Which makes code readability easier.
- Makes the controller action clear and concise, by hiding the low-level details of constructing the response.
IHttpActionResult contains a single method, ExecuteAsync, which asynchronously creates an HttpResponseMessege.
- public async System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> ExecuteAsync(System.Threading.CancellationToken cancellationToken)
- {
- }
There is an example of IHttpActionResult which have been used at Authentication Filter level and states that ExecuteAsync just add Header value in response and returns. Please have a quick look at the code shown below.
- public class CustomResultChallenge: IHttpActionResult
- {
- #region IHttpActionResult Members
- private readonly IHttpActionResult result;
- private readonly string realm;
- public CustomResultChallenge(IHttpActionResult result, string realm)
- {
- this.result = result;
- this.realm = realm;
- }
- public async System.Threading.Tasks.Task < System.Net.Http.HttpResponseMessage > ExecuteAsync(System.Threading.CancellationToken cancellationToken)
- {
- var res = await result.ExecuteAsync(cancellationToken);
- if (res.StatusCode == HttpStatusCode.Unauthorized)
- {
- res.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Basic", this.realm));
- }
- return res;
- }#endregion
- }
Kindly see vital point marked yellow in the below screen shot;
Press F5 and run you WebApi as depicted below in an image,
Send the Get request in order to verify the execution cycle as given below. Copy and paste the following Url (http://localhost:57888/api/employees/GetEmp/5) in Postman tool as depicted below in screen shot.
As soon as you click on the send button it reaches to Custom handler one and goes on to next level. Kindly execute the complete HttpMessegePipeline one by one and add your points.
So far we’ve get into each area of WebApi HttpRequest Pipeline and tried to understand few facts happen during its cycle.
- Bullet Points. HttpRequest first converts into HttpRequestMessege.
- HttpHandler are type of delegate handler and inject to verify the authenticity and to add some preprocessing logic before it goes further in pipeline. Delegate Handler can be creating on per-route basis. If come error/issue occurs at this level can skip the rest of pipeline.
- Authentication filters have been introduced in WebApi2.If come error/issue occurs at this level can skip the rest of pipeline.
- Mostly classes are derived from using System.Web.Http.
- Model Binders and Value Provides plays an important role in parameter binding as well as the added benefit of FormatterParameterBinding.
- WebApi2 gives privilege to return IHttpActionResult from action method of controller. Also supports HttpResponseMessege.
- You can manage exception at IHttpAcitonInvoker and at ExceptionFilters also.
- This is the final structure of an application given below in screen shot.
Hope you would read all contexts and liked it.
Disclaimer
This is all my understanding about WebApi; I’d be happy if you run this sample application and get a chance to share your opinion.