Slide 1

Slide 1 text

From requests to responses: a journey into the ASP.NET Web API runtime architecture NDC 2013 Pedro Félix @pmhsfelix [email protected] 1

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Outline • Message Representation • The HttpRequestMessage and HttpResponseMessage classes • The HttpContent and derived classes • Message Processing • Processing layers • Extensibility points • Examples 4

Slide 5

Slide 5 text

Message Representation 5

Slide 6

Slide 6 text

System.Net.Http • Introduced in .NET 4.5 • Backported to .NET 4.0 6

Slide 7

Slide 7 text

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); }

Slide 8

Slide 8 text

Typed headers 8

Slide 9

Slide 9 text

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 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); }

Slide 10

Slide 10 text

HttpContent 10

Slide 11

Slide 11 text

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(); } }

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Message Processing 13

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Message Processing Message Handling Layer 15

Slide 16

Slide 16 text

Message Handlers 16 HttpRequestMessage HttpResponseMessage Message Handler HttpRequestMessage Task DelegatingHandler HttpRequestMessage HttpResponseMessage

Slide 17

Slide 17 text

Message Handlers 17 HttpRequestMessage HttpResponseMessage Message Handler HttpRequestMessage Task DelegatingHandler HttpRequestMessage HttpResponseMessage

Slide 18

Slide 18 text

Basic Authentication 18 async protected override Task 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; }

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

HttpConfiguration • Routing HttpRouteCollection Routes { get; } • Middleware container Collection MessageHandlers { get; } HttpFilterCollection Filters { get; } MediaTypeFormatterCollection Formatters { get; } ParameterBindingRulesCollection ParameterBindingRules { get; } • Service location IDependencyResolver DependencyResolver { get; set; } ServicesContainer Services { get; internal set; } 21

Slide 22

Slide 22 text

Message Processing Host Adaptation Layer 22

Slide 23

Slide 23 text

Hosts • Web Host • ASP.NET Pipeline • Self Host • HttpListener - uses the WCF channel stack • Custom hosts • E.g. Service Bus host • OWIN hosts 23

Slide 24

Slide 24 text

ASP.NET Pipeline 24 HttpApplication IHttpModule IHttpModule UrlRoutingModule IHttpModule RouteTable.Routes IHttpHandler

Slide 25

Slide 25 text

ASP.NET Hosting (Web Hosting) 25 HttpApplication IHttpModule IHttpModule UrlRoutingModule IHttpModule RouteTable.Routes HttpControllerHandler HttpRequestMessage HttpResponseMessage HttpServer GlobalConfiguration .HttpConfiguration

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Self Hosting 27 WCF Channel Stack Transport Channel HttpMessageEncoder HttpRequestMessage HttpResponseMessage HttpServer HttpSelfHost Configuration HttpBinding HttpSelfHostServer

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Message Processing Controller Layer 31

Slide 32

Slide 32 text

Controller Dispatching 32 IHttpController Concrete Controller GetAction PostAction ... HttpControllerDispatcher HttpResponseMessage HttpRequestMessage HttpControllerContext HttpRequestMessage HttpControllerDescriptor HttpResponseMessage ApiController (actions, filters, model binding, formatters) Concrete Controller ExecuteAsync

Slide 33

Slide 33 text

Controller selection, instantiation and invocation 33

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Action pipeline 35 AuthorizationFilter HttpResponseMessage HttpActionContext AuthorizationFilter HttpActionBinding AuthorizationFilter ActionFilter HttpResponseMessage action arguments Action method IActionResultConverter object HttpResponseMessage HttpRequestMessage ExceptionFilter ExceptionFilter parameters

Slide 36

Slide 36 text

Filters and attributes 36

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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(null); } } config.ParameterBindingRules.Add(prm => prm.ParameterType == typeof(IPAddress) ? new IPAddressParameterBinding(prm) : null);

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

MediaTypeFormatter Media Type Formatters 40 HttpRequestMessage Request URI Headers Body Content-Type: media-type stream MediaTypeFormatter CLR Object

Slide 41

Slide 41 text

MediaTypeFormatter • MediaTypeFormatter is selected based on • The content media type • The parameter CLR type • Examples • JsonMediaTypeFormatter • XmlMediaTypeFormatter • FormUrlEncodedMediaTypeFormatter 41

Slide 42

Slide 42 text

Result conversion • Convert the action returned object into a HttpResponseMessage • IActionResultConverter interface • HttpResponseMessage Convert( HttpControllerContext controllerContext, object actionResult); • Implementations • ResponseMessageResultConverter • VoidResultConverter • ValueResultConverter 42

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

MediaTypeFormatter (again) • Collection SupportedMediaTypes { get;} • Collection SupportedEncodings { get; private set; } • Collection MediaTypeMappings { get; } • abstract bool CanReadType(Type type); • abstract bool CanWriteType(Type type); • Task ReadFromStreamAsync(Type type, Stream readStream, …) • Task WriteToStreamAsync(Type type, object value, Stream writeStream, …) 44

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Thanks! 47