Web API FAQs:
1. What are the return types of Action methods in Web API?
a. Void:
If the return type is void, Web API simply returns an empty HTTP response with status code 204 (No Content).
b. HttpResponseMessage
Web API converts the return value into HttpResponseMessage.
This option also provides the control over response message.
Like you can use server side caching using CacheControlHeaderValue.
response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromMinutes(20)
};
Also you can use Request.CreateResponse() method to pass a domain model that will serialized using media formmatter based on Content Negotiation.
public HttpResponseMessage Get()
{
// Get a list of products from a database.
IEnumerable<Product> products = GetProductsFromDB();
// Write the list to the response body.
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, products);
return response;
}
c. IHttpActionResult
Introduce in Web API2.
It has one method called ExecuteAsync().
public interface IHttpActionResult
{
Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken);
}
It is used to create a factory of HttpResponseMessage . Basically you can put your logic for HttpResponse in separate classes.
public class TextResult : IHttpActionResult
{
string _value;
HttpRequestMessage _request;
public TextResult(string value, HttpRequestMessage request)
{
_value = value;
_request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage()
{
Content = new StringContent(_value),
RequestMessage = _request
};
return Task.FromResult(response);
}
}
Example controller
public class ValuesController : ApiController
{
public IHttpActionResult Get()
{
return new TextResult("hello", Request);
}
}
Response:
HTTP/1.1 200 OK
Content-Length: 5
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/8.0
Date: Mon, 27 Jan 2014 08:53:35 GMT
hello
public IHttpActionResult Get (int id)
{
Product product = _repository.Get (id);
if (product == null)
{
return NotFound(); // Returns a NotFoundResult
}
return Ok(product); // Returns an OkNegotiatedContentResult
}
d. Some other type
For other types Web API uses Media formatter and serialize the response return with 200 OK.
A disadvantage of this approach is that you cannot directly return an error code, such as 404.
2. What is content negotiation?
Content Negotiation is the process of selecting content representation based request headers. As there are multiple representations/formatter available.
Accept: Which media types are acceptable for the response, such as "application/json," "application/xml," or a custom media type such as "application/vnd.example+xml"
Accept-Charset: Which character sets are acceptable, such as UTF-8 or ISO 8859-1.
Accept-Encoding: Which content encodings are acceptable, such as gzip.
Accept-Language: The preferred natural language, such as "en-us".
The object that serializes the resource is called a media formatter. Media formatters derive from the MediaTypeFormatter class. Web API provides media formatters for XML and JSON, and you can create custom formatters to support other media types.
3. How to create custom media type formatter?
First you have to create your custom formatter class that should be implement/inherit BufferedMediaTypeFormater class of System.Net.Http.Formatting namespace.
Then use CanReadType and ReadFromStream methods to deserialize data and CanWritetype and WriteToStream methods to serialize data.
4. What is the difference between ASP.Net MVC routing and Web API routing?
In ASP.Net MVC, action methods selected based on URI, but in Web API action methods are selected based on HTTP Methods. However it is also possible to do MVC based routing in Web API. Each entry in the routing table contains a route template. The default route template for Web API is "api/{controller}/{id}".
When the Web API framework receives an HTTP request, it tries to match the URI against one of the route templates in the routing table. If no route matches, the client receives a 404 error. For example, the following URIs match the default route:
/api/contacts
/api/contacts/1
/api/products/gizmo1
However, the following URI does not match, because it lacks the "api" segment:
/contacts/1
Once a matching route is found, Web API selects the controller and the action:
· To find the controller, Web API adds "Controller" to the value of the {controller} variable.
· To find the action, Web API looks at the HTTP method, and then looks for an action whose name begins with that HTTP method name. For example, with a GET request, Web API looks for an action that starts with "Get...", such as "GetContact" or "GetAllContacts". This convention applies only to GET, POST, PUT, and DELETES methods. You can enable other HTTP methods by using attributes on your controller.
· Other placeholder variables in the route template, such as {id}, are mapped to action parameters.
1.You can specify the HTTP method with an attribute: AcceptVerbs, HttpDelete, HttpGet, HttpHead, HttpOptions, HttpPatch, HttpPost, or HttpPut.
2. Otherwise, if the name of the controller method starts with "Get", "Post", "Put", "Delete", "Head", "Options", or "Patch", then by convention the action supports that HTTP method.
3. If none of the above, the method supports POST.
5. What is attribute routing?
Attribute routing uses attributes to define route, it has more control over URI then conventional based routing, however you can use both routing in same project. If you will not provide attribute on actions then it will use conventional based routing.
6. What is the advantage of conventional routing?
In this, routing templates are defined at single place and the routing rules are applies consistently across all controllers. But conventional routing does not support certain type of URI. Like
Suppose you want orders details of customers whose id is 1.
Then URL looks like /customers/1/orders
7. Why Attribute routing?
You can handle above type of situation easily with attribute routing.
[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }
Other Benefits are
· API versioning
You can have multiple versions of your APIs.
/api/v1/products
/api/v2/products
· Overloaded URI segments
In this example, "1" is an order number, but "pending" maps to a collection.
/orders/1
/orders/pending
· Multiple Parameters types
In this example, "1" is an order number, but "2013/06/16" specifies a date.
/orders/1
/orders/2013/06/16
[Route ("orders/{orderId}/Customer/{customerId}")]
8. How to enable Attribute routing?
Use config.MapHttpAttributeRoutes(); in WebApiConfig.cs.
9. How to migrate Web API 1 to 2.
Replace WebApiConfig.Register(GlobalConfiguration.Configuration); by
GlobalConfiguration.Configure(WebApiConfig.Register); in Application_Start method of Global.asax.
10. How to apply constraints in routing?
Web API 1:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional},
constraints: new {id = @"\d+"}
);
Web API 2:
[Route("users/{id:int}"]
public User GetUserById(int id) { ... }
Some other examples:
{x:regex(^\d{3}-\d{3}-\d{4}$)}
{x:range(10,50)}
{x:long}
11. How to create custom route constraints?
By implementing IsMatch method of IHttpRouteConstraint in your custom class.
Then you have to register in WebApiConfig.cs like
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint));
config.MapHttpAttributeRoutes(constraintResolver);
}
}
You can use like
[Route("{id:nonzero}")]
public HttpResponseMessage GetNonZero(int id) { ... }
12. How to make route parameter optional?
Assign some value to that parameter.
public class BooksController : ApiController
{
[Route("api/books/locale/{lcid:int=1033}")]
public IEnumerable<Book> GetBooksByLocale(int lcid) { ... }
}
13. What is the use of Route Name?
Route name are helpful to generate links.
public class BooksController : ApiController
{
[Route("api/books/{id}", Name="GetBookById")]
public BookDto GetBook(int id)
{
// Implementation not shown...
}
[Route("api/books")]
public HttpResponseMessage Post(Book book)
{
// Validate and add book to database (not shown)
var response = Request.CreateResponse(HttpStatusCode.Created);
// Generate a link to the new book and set the Location header in the response.
string uri = Url.Link("GetBookById", new { id = book.BookId });
response.Headers.Location = new Uri(uri);
return response;
}
}
14. What is the route order?
When request comes, It searches for action in the route order.
Look at each URI segment in the route template. For each segment, order as follows:
· Literal segments. [Route("details")]
· Route parameters with constraints. [Route("{id:int}")]
· Route parameters without constraints. [Route("{customerName}")]
· Wildcard parameter segments with constraints. [Route("{*date:datetime}")]
· Wildcard parameter segments without constraints.
[Route ("pending", RouteOrder = 1)] due to route order 1 is after details.
· In the case of a tie, routes are ordered by a case-insensitive ordinal string comparison (OrdinalIgnoreCase) of the route template.
15. What are the Message Handlers in web API?
Message handles are classes that can manipulate the incoming requests. There are various inbuilt message handlers.
- HttpServer : It is used to retrieve the request message from Host (IIS/ Self-Host).
- HttpRoutingDispatcher : used to dispatch the request based on route configured.
- HttpControllerDispatcher : used to send the request to respective controller.
16. What is DelegatingHandler in web API?
It is a class that is used to create custom message handlers in web API. It has the SendAsyc() method that pass the request to inner handler. You can return response without calling any controller on some condition or manipulate the request and pass to another handler. You can better understand by below example.
public class CustomeHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//1. If request does not meet your criteria like authorization/authentication or any other information that you want to compare.
return request.CreateResponse(HttpStatusCode.Unauthorized, “Error message”);
//2. You can modify headers of request
//3. You can logs the incoming request
//4. Then pass the request to next inner handler using base.SendAsync()
return await base.SendAsync(request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}
}
You also have to add this handler in your WebApiConfig.cs as
GlobalConfiguration.Configuration.MessageHandlers.Add(new CustomeHandler());
17. Explain Web API 2 life cycle.
You can see complete life cycle here.
I have made a short diagram for this to easily memorize the steps.
18. How to use Model validation in Web API 2?
Web API support Data annotation same as in MVC. You can
apply these data annotations attributes to your models and use ModelState.IsValid
property to validate the Model.
using
System.ComponentModel.DataAnnotations;
namespace MyApi.Models
{
public class Product
{
public int Id { get; set; }
[Required]
public string Name
{ get; set; }
public decimal Price
{ get; set; }
[Range(0, 999)]
public double
Weight { get; set; }
}
}
And create
controllers like
public class ProductsController : ApiController
{
public HttpResponseMessage Post(Product product)
{
if (ModelState.IsValid)
{
return new
HttpResponseMessage(HttpStatusCode.OK);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest,
ModelState);
}
}
}
19. How to use Authentication in Web API 2?
You
can use Authentication in Web API2 in many ways.
By default it assumes authentication happens in the host means on domain
level. It uses HttpModule.
When the host authenticates the user, it creates a
principal,
which is an
IPrincipal object
that represents the security context under which code is running. The host
attaches the principal to the current thread by setting Thread.CurrentPrincipal. The principal
contains an associated Identity object that contains information about the
user. If the user is authenticated, the Identity.IsAuthenticated property returns true. For
anonymous requests, IsAuthenticated returns false.
As you see an HttpModule take care of all requests that go through the
ASP.net pipeline. But if you only want the security when requests are routed to
your Web API then there is another approach called authentication using HttpMessageHandler.
HttpMessageHandlers are more useful for Self-host Web API scenarios.
You
also can use Authentication filters that are introduced in Web API 2. Authentication
filter also can applied at controller level or action level of globally like
other filters.
[IdentityBasicAuthentication] // Enable Basic
authentication for this controller.
[Authorize]
//
Require authenticated requests.
public class HomeController : ApiController
{
public IHttpActionResult Get() { . . . }
public IHttpActionResult Post() { . . . }
}
To
create custom authentication filter, you can implement IAuthenticationFilter in your class.
20. How to use Authorization in Web API 2?
Authorization
happens after authentication.
HttpModule=>
HttpMessageHandler=>AuthorizationFilter=>Controller
You can use Authorize attribute to provide authorization at controller
level or action level.
// only allowed users can
access this controller:
[Authorize(Users="Alice,Bob")]
public class ValuesController : ApiController
{
}
// only users with role
Administrators can access this controller:
[Authorize(Roles="Administrators")]
public class ValuesController : ApiController
{
}
You can also create custom authentication
filter by inheriting any of AuthorizeAttribute, AuthorizationFilterAttribute, or IAuthorizationFilter.
To disable host-level authentication inside the Web API pipeline, call config.SuppressHostPrincipal() in your configuration. This causes Web API to
remove the IPrincipal from any request that
enters the Web API pipeline. Effectively, it "un-authenticates" the
request.
21. How can you restrict to the consumer/client of Web API 2 to use SSL?
You
can write your own MessageHandler or
Authorization filter.
Using
MessageHandler:
this will be applicable at global level.
public class HttpsSchemeAuthenticationHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if
(request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
return request.CreateResponse(HttpStatusCode.Unauthorized, "Required Https");
}
}
Using Authorization: This can be applied on
controller or action level.
public class RequireHttpsAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext
actionContext)
{
if
(actionContext.Request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
actionContext.Response = new
HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
{
ReasonPhrase = " Required Https "
};
}
else
{
base.OnAuthorization(actionContext);
}
}
}