Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From requests to responses: a journey into the ASP.NET Web API runtime architecture

From requests to responses: a journey into the ASP.NET Web API runtime architecture

Slides for my NDC 2013 session on the ASP.NET Web API internal runtime architecture
Video is available here: https://vimeo.com/68215605

Pedro Felix

June 15, 2013
Tweet

More Decks by Pedro Felix

Other Decks in Programming

Transcript

  1. From requests to responses: a journey into the ASP.NET Web

    API runtime architecture NDC 2013 Pedro Félix @pmhsfelix [email protected] 1
  2. whoami • Professor at the Lisbon Polytechnic Institute • Independent

    Consultant • Currently with the Service Delivery Broker team (SAPO - Portugal Telecom) • Co-author of Designing Evolvable Web APIs with ASP.NET (to be published in 2013 by O’Reilly) 2
  3. Concrete Controller HTTP is a stateless request/response protocol that operates

    by exchanging messages An HTTP "server" is a program that accepts connections in order to service HTTP requests by sending HTTP responses. In Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing 3 Request Message Response Message ? ASP.NET Web API
  4. Outline • Message Representation • The HttpRequestMessage and HttpResponseMessage classes

    • The HttpContent and derived classes • Message Processing • Processing layers • Extensibility points • Examples 4
  5. Instantiability and testability 7 [Fact] public void HttpRequestMessage_is_easy_to_instantiate() { var

    request = new HttpRequestMessage( HttpMethod.Get, new Uri("http://www.ietf.org/rfc/rfc2616.txt")); Assert.Equal(HttpMethod.Get, request.Method); Assert.Equal("http://www.ietf.org/rfc/rfc2616.txt", request.RequestUri.ToString()); Assert.Equal(new Version(1,1), request.Version); } [Fact] public void HttpResponseMessage_is_easy_to_instantiate() { var response = new HttpResponseMessage(HttpStatusCode.OK); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(new Version(1,1), response.Version); }
  6. Typed headers 9 [Fact] public void Header_classes_expose_headers_in_a_strongly_typed_way() { var request

    = new HttpRequestMessage(); request.Headers.Add( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); HttpHeaderValueCollection<MediaTypeWithQualityHeaderValue> accept = request.Headers.Accept; Assert.Equal(4, accept.Count); MediaTypeWithQualityHeaderValue third = accept.Skip(2).First(); Assert.Equal("application/xml", third.MediaType); Assert.Equal(0.9, third.Quality); Assert.Null(third.CharSet); Assert.Equal(1, third.Parameters.Count); Assert.Equal("q", third.Parameters.First().Name); Assert.Equal("0.9", third.Parameters.First().Value); }
  7. Custom content 11 public class FileContent : HttpContent { private

    readonly Stream _fstream; public FileContent(string path, string mediaType = "application/octet-stream") { _fstream = new FileStream(path, FileMode.Open, FileAccess.Read); base.Headers.ContentType = new MediaTypeHeaderValue(mediaType); } protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { return _fstream.CopyToAsync(stream); } protected override bool TryComputeLength(out long length) { if (!_fstream.CanSeek){ length = 0; return false; } else{ length = _fstream.Length; return true; } } protected override void Dispose(bool disposing) { _fstream.Dispose(); } }
  8. System.Net.Http • Faithful to RFC 2616 • Easier to instantiate

    and test • Both typed and untyped access to message members (e.g. headers) • Extensible HTTP content class hierarchy • Based on the Task Asynchronous Pattern • Usable on both the client and server sides 12
  9. Runtime Architecture Web Host | Self Host | Custom Hosts

    Message Handler ApiController Concrete Controller GetAction PostAction ... 14 HttpRequestMessage HttpResponseMessage HttpRequestMessage HttpResponseMessage HttpRequestMessage HttpResponseMessage Message Handler Message Handler • Controller Layer • Controllers, actions, parameters • Model binding, validation and formatters • Filters • Message Handling Layer • Message transformation • Response message generation • Host adaptation Layer • Request message generation • Response message consuption
  10. Basic Authentication 18 async protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request,

    CancellationToken cancellationToken) { if (HasAuthorizationHeaderWithBasicScheme(request)) { var username = TryExtractAndValidateCredentials( request.Headers.Authorization.Parameter); if (username == null) return UnauthorizedResponseMessage(_realm); SetPrincipal(request, username); } var response = await base.SendAsync(request, cancellationToken); if(response.StatusCode == HttpStatusCode.Unauthorized) response.Headers.WwwAuthenticate.Add( new AuthenticationHeaderValue("Basic", string.Format("realm={0}", _realm))); return response; }
  11. HttpServer • Message Handler pipeline • Common pipeline ended with

    a special route dispatcher handler • Per-route pipeline • Associated configuration • HttpServer is also a DelegatingHandler 19 Message Handler Http Configuration Message Handler Route Dispatcher Controller Dispatcher Per-Route Handler
  12. 20 Web Host | Self Host | Custom Hosts ApiController

    Concrete Controller GetAction PostAction ... HttpRequestMessage HttpResponseMessage HttpRequestMessage HttpResponseMessage Message Handler Http Configuration Message Handler Route Dispatcher Controller Dispatcher Per-Route Handler
  13. HttpConfiguration • Routing HttpRouteCollection Routes { get; } • Middleware

    container Collection<DelegatingHandler> MessageHandlers { get; } HttpFilterCollection Filters { get; } MediaTypeFormatterCollection Formatters { get; } ParameterBindingRulesCollection ParameterBindingRules { get; } • Service location IDependencyResolver DependencyResolver { get; set; } ServicesContainer Services { get; internal set; } 21
  14. Hosts • Web Host • ASP.NET Pipeline • Self Host

    • HttpListener - uses the WCF channel stack • Custom hosts • E.g. Service Bus host • OWIN hosts 23
  15. ASP.NET Hosting (Web Hosting) 25 HttpApplication IHttpModule IHttpModule UrlRoutingModule IHttpModule

    RouteTable.Routes HttpControllerHandler HttpRequestMessage HttpResponseMessage HttpServer GlobalConfiguration .HttpConfiguration
  16. ASP.NET Hosting (Web Hosting) • Hosting adaptation concerns • Request

    and response buffering – IHostBufferSelector • TLS client certificate • Uses ASP.NET Routing • To select the ASP.NET IHttpHandlers • To obtain the Web API routing data • Sits on top of the classical ASP.NET pipeline • Connection configuration at IIS 26
  17. Self Hosting 27 WCF Channel Stack Transport Channel HttpMessageEncoder HttpRequestMessage

    HttpResponseMessage HttpServer HttpSelfHost Configuration HttpBinding HttpSelfHostServer
  18. Self Hosting • Hosting adaptation concerns • HttpSelfHostConfiguration properties •

    Request and response buffering (.TransferMode) • TLS client certificate (.ClientCredentialType) • Timeouts (.ReceiveTimeout) • Throttling (.MaxConcurrentRequests) • Does not perform any routing • Routing is evaluated by the routing message handler • After the common message handlers • Connection configuration via netsh 28
  19. In-memory hosting • Since a HttpServer is also a delegating

    handler... 29 Message Handler Http Configuration Message Handler Route Dispatcher Controller Dispatcher Per-Route Handler Message Handler HttpClient
  20. Service Bus Hosting 30 Message Handler Http Configuration Message Handler

    Route Dispatcher Controller Dispatcher Per-Route Handler WCF Generic Service Using WebHttpRelayBinding Service Bus Relay HttpRequestMessage HttpResponseMessage
  21. Controller Dispatching 32 IHttpController Concrete Controller GetAction PostAction ... HttpControllerDispatcher

    HttpResponseMessage HttpRequestMessage HttpControllerContext HttpRequestMessage HttpControllerDescriptor HttpResponseMessage ApiController (actions, filters, model binding, formatters) Concrete Controller ExecuteAsync
  22. ApiController.ExecuteAsync • Initialize properties (e.g. Request, User) from controller context

    • Use IHttpActionSelector to get HttpActionDescriptor • Filters • Parameter binding • Result convertion • Create HttpActionContext • Create action pipeline • filters, parameter binding and result conversion • Invoke pipeline 34
  23. Action pipeline 35 AuthorizationFilter HttpResponseMessage HttpActionContext AuthorizationFilter HttpActionBinding AuthorizationFilter ActionFilter

    HttpResponseMessage action arguments Action method IActionResultConverter object HttpResponseMessage HttpRequestMessage ExceptionFilter ExceptionFilter parameters
  24. Parameter binding • Handled by HttpParameterBinding derived classes • ModelBinderParameterBinding

    • Based on model binders and value providers (similar to ASP.NET MVC) • Used to bind from request URI • Related to FromUriAttribute • Multiple parameters • Default for simple types • FormatterParameterBinding • Based on the MediaTypeFormatter concept • Used to bind from request body • Related to FromBodyAttribute • One parameter only • Default for complex types 37
  25. Custom parameter binding 38 public class IPAddressParameterBinding : HttpParameterBinding {

    public IPAddressParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor) { } public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) { var request = actionContext.Request; var ipString = GetClientIpAddressFrom(request); SetValue(actionContext, IPAddress.Parse(ipString)); return Task.FromResult<object>(null); } } config.ParameterBindingRules.Add(prm => prm.ParameterType == typeof(IPAddress) ? new IPAddressParameterBinding(prm) : null);
  26. The "Content-Type" header field indicates the media type of the

    associated representation The indicated media type defines both the data format and how that data is intended to be processed by a recipient In Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content (bolds are mine) • Examples • text/plain, text/html, application/json, application/xml • application/hal+json, application/vnd.collection+json • application/vnd.github+json • See http://www.iana.org/assignments/media-types 39
  27. MediaTypeFormatter Media Type Formatters 40 HttpRequestMessage Request URI Headers Body

    Content-Type: media-type stream MediaTypeFormatter CLR Object
  28. MediaTypeFormatter • MediaTypeFormatter is selected based on • The content

    media type • The parameter CLR type • Examples • JsonMediaTypeFormatter • XmlMediaTypeFormatter • FormUrlEncodedMediaTypeFormatter 41
  29. Result conversion • Convert the action returned object into a

    HttpResponseMessage • IActionResultConverter interface • HttpResponseMessage Convert( HttpControllerContext controllerContext, object actionResult); • Implementations • ResponseMessageResultConverter • VoidResultConverter • ValueResultConverter 42
  30. ValueResultConverter • Uses a MediaTypeFormatter to convert CLR object 

    byte sequence • The MediaTypeFormatter is chosen based on • The CLR object type • The request message, namely • The Accept header • The request URI • Server-driven content negotiation 43
  31. MediaTypeFormatter (again) • Collection<MediaTypeHeaderValue> SupportedMediaTypes { get;} • Collection<Encoding> SupportedEncodings

    { get; private set; } • Collection<MediaTypeMapping> MediaTypeMappings { get; } • abstract bool CanReadType(Type type); • abstract bool CanWriteType(Type type); • Task<object> ReadFromStreamAsync(Type type, Stream readStream, …) • Task WriteToStreamAsync(Type type, object value, Stream writeStream, …) 44
  32. Conclusions and final remarks • Layered runtime architecture • Hosting

    Adaptation • Message Handling Pipeline • Controller Layer • HTTP messages using the new class model • Several extensibility points 45
  33. References • “Use the source, Luke” git clone https://git01.codeplex.com/aspnetwebstack •

    G. Block, P. Cibraro, P. Félix, H. Dierking & D. Miller Designing Evolvable Web APIs with ASP.NET • To be published by O’Reilly in 2013 • Preview available at O’Reilly Atlas - http://chimera.labs.oreilly.com/books/1234000001708 • Samples at https://github.com/pmhsfelix 46