📜 ⬆️ ⬇️

The evolution of Microsoft web frameworks. ASP.NET vNext



Prerequisites for change


The news about the release of ASP.NET vNext on the network spread quite quickly along with the announcement of the most interesting innovations proposed in the update. ASP.NET MVC 6 has received a new name and is positioned as something really new in the environment of Microsoft web frameworks (MS). In order to most fully understand the importance of the stated changes in vNext, recall the features of the current implementation of web applications on the .NET platform.

A typical ASP.NET MVC application consists of a Global.asax file in which we extend the HttpApplication class (System.Web) and thus add the desired behavior for handling Http requests by configuring the individual components of MVC. In the classic ASP.NET MVC, the Router class (System.Web.Routing) is an integral part of processing Http requests by redirecting them to the desired HttpHandler in standard behavior (MvcRouteHandler) which creates a factory of controllers and starts a further request processing pipe. These components are obviously closely tied to a web server from MS - Internet Information Services (IIS), which uses HttpHandlers and HttpContext (access to http request / response parameters) to process requests. The widespread use of these components in MVC inherited from ASP.NET Web Forms assumed close integration with IIS, which made it impossible to use an alternative web server for hosting applications. Over time, these circumstances caused more and more criticism from the developer community and were not really a very favorable factor for the development of ASP.NET MVC, which, being an Open Source project, is developing much faster than Microsoft is developing updates for the System.Web components.
')


An attempt to rectify the situation was undertaken as part of the development of the Web Api project. During the migration from the MS WCF framework, developers abandoned the approach to building RESTful services based on the concept of "binding contracts", in favor of a more convenient MVC, which predetermined a lot in common and consonant name - ASP.NET Web Api. In fact, the developers of the new framework were able to do it with an eye to the ASP.NET MVC shortcomings described above. Web Api did not use these very System.Web components directly due to adapters for HttpContext.Request, HttpContext.Response - abstractions with the updated structure HttpRequestMessage, HttpResponseMessage, into which HttpControllerHandler (entry point to the Web Api application) produced The IIS HttpHandler dependency was also eliminated by processing requests through a chain of HttpMessageHandlers (System.Net.Http) nested into each other, based on which the updated stack was implemented (filters, dispatchers, delegating handlers, controllers).



All these changes allowed to make the Web Api application independent of the host and to develop the OWIN (Open Web Interface) specifications. The key concept was the middleware - web application components (in IIS - HttpModules) and application delegate, which instead of HttpContext, interacts with a much more abstract set of request / response parameters in the hash map of the form IDictionary <string, object>.



Despite all the advantages, flexibility, improved extensibility and a number of fixes for architectural flaws, Web Api still could not become a full-fledged replacement for MVC while being focused on Single Page Applications (SPA). At the same time, one framework did not interfere with another. Moreover, they got along perfectly well in the same web application if IIS was used for hosting and even could use common Http modules, for example, for authentication. Nevertheless, the considered approach required a clear division of responsibility in the application and taking into account the peculiarities that, nevertheless, Web Api and Mvc use a completely different pipeline for processing requests. The latter added another kind of complexity to the developers and suggested the subsequent refactoring in the new version of the framework, which was called vNext.

ASP.NET vNext project template


The first thing that catches the eye in a new web application is the lack of web.config, packages.config, and even AssemblyInfo.cs files.



We have only two files in the solution structure:

Now looking at the properties of the VS project, we will not see the abundance of options with which ASP.NET projects were previously provided. There are two tabs available: General - configuration of the namespace and type of application during the construction; on the Debugging tab - the port number on which our application will be available.
Further more interesting is the actual project.json configuration file. It looks approximately as follows.



The primary set provides only two keys.

Such drastic changes in the project structure are due to the use of the new Roslyn compiler, which allows compiling source code into IL at runtime and executing it. The capabilities of Roslyn formed the basis of the new K Language Runtime (KLR) runtime. At the moment, there are two options for launching the project in .NET Desktop mode, or Core CLR (in the alpha version, the mode is available only in KLR from under Win 8). You can also build a project using K Versions Manager (KVM) / K Packages Manager (KPM) - console utilities supplied with K, which allow you to independently manage installed versions of KRE (K Runtime Engine), unpack applications based on project.json and run them. For more information, check out github.com/aspnet/home .

The structure of an ASP.NET vNext web application


The only source code file in the project is Startup.cs, which contains a reference to the Microsoft.AspNet.Builder namespace and a class with a structure similar to OWIN based applications. It has one method - Configure with an input parameter of type IBuilder. The project compiles and runs, but returns nothing as an answer (or rather, returns “403rd”, because IIS, not finding the request handler, is trying to access the file system), which is logical, since we did not add any middleware.



On www.asp.net/vnext we are offered to call a static extension method (UseWelcomePage) to add the simplest Request Handler, but it is of little interest to us, since it hides all the specifics of the operation of the IBuilder interface. Let's try to "dig" deeper looking at his definition:

using System; namespace Microsoft.AspNet.Builder { public interface IBuilder { IServiceProvider ApplicationServices { get; set; } IServerInformation Server { get; set; } RequestDelegate Build(); IBuilder New(); IBuilder Use(Func<RequestDelegate, RequestDelegate> middleware); } } 


In order to navigate the code, you need to remember that the concept of middleware in OWIN directly refers to the Application Delegate, which receives the list of parameters for the Http request and performs some kind of conversion on it, returning Task.

 Func<IDictionary<string, object>, Task> 


For OWIN, we also had a static Extensions method at the IAppBuilder interface level, which allowed adding middleware using a more convenient structured version of the context - IOwinContext. In vNext, it has changed a bit, because it involves working with HttpContext directly. The latter is now in the Microsoft.AspNet.Http namespace, and has nothing to do with the HttpContext from System.Web, as was the case with the HttpContextBase wrapper in ASP.NET MVC:

 public delegate Task RequestDelegate(HttpContext context); 


Thus, everything gradually falls into place - RequestDelegate in vNext and is thus the OWIN Application Delegate.
To add a new middleware in the original implementation of the Use method, we pass a generic delegate that contains a nested delegate of the type RequestDelegate as a parameter. The external Generic delegate refers to the entire further pipeline processing the http request, RequestDelegate - performs the work of Http Handler.
Let's take a look at the example with the addition of modules - this should clarify the situation a little.

 public void Configure(IBuilder app) { app.Use(next => httpContext => httpContext.Response.WriteAsync("Executed before all followers." + Environment.NewLine) .ContinueWith(task => next(httpContext))); app.Use(next => httpContext => next(httpContext) .ContinueWith(task => httpContext.Response.WriteAsync("Executed after all followers." + Environment.NewLine))); app.Use((httpContext, next) => httpContext.Response.WriteAsync("Hello world middleware." + Environment.NewLine)); } 


As you can see, when configuring middleware, we have behavior in many ways similar to Delegating Handlers Web Api, where we can flexibly control the sequence of execution from the current module of the entire further pipeline (parameter next). Simply add the processing of the Http request within the lambda expressions passed to Use.



As for OWIN itself, vNext is fully compatible with this interface. The Microsoft.AspNet.Builder namespace contains a class of static extension methods for IBuilder, which create transition adapters from Owin Application Delegate to vNext RequestDelegate.

 using AddMiddleware = Action<Func<Func<IDictionary<string, object>, Task>, Func<IDictionary<string, object>, Task>>>; public static AddMiddleware UseOwin(this IBuilder builder) { .... } 


In our application, we can use the AddMiddleware to interact between the OWIN Environment dictionary and vNext HttpContext, relying on the internal implementation of the platform. The extension will make it quite easy to use OWIN components in the new version of the framework.

Among the important features, it is worth noting that, unlike OWIN AppBuilder, the vNext IBuilder interface also contains the application service locator built-in, which is initialized by the application by the web server. This property provides access to Web Host Application Level Services.

vNext HttpContext


With the structure of the application a little figured out what exactly is the updated vNext HttpContext. As expected, the context class itself, Request and Response, is declared abstract. The HttpContext in the implementation of the Microsoft.AspNet.Hosting host delivered from the “crumbs” is instantiated by the DefaultHttpContext object before each call to the middleware chain. The context has an Abort method, implements the IDisposable interface, and provides two ApplicationServices and RequestServices locator services with a corresponding container life cycle, which clearly supports the more convenient formation of a Structure Map at the application level compared to previous versions of ASP.NET MVC.

A new context extensibility mechanism has been added to vNext by using HttpFeatures. At the level of the context interface, it provides two sets of methods for obtaining and adding extensions (via packing in the object and generic wrapper):

  public abstract object GetFeature(Type type); public abstract void SetFeature(Type type, object instance); public virtual T GetFeature<T>() { return (T)GetFeature(typeof(T)); } public virtual void SetFeature<T>(T instance) { SetFeature(typeof(T), instance); } 


In the updated version of ASP.NET, this approach is used to dynamically form a context, starting from the first access to HttpContext, where Host Application / Server Specific Features are initialized to the level used by separate middleware components of the request, authentication, caching, and web sockets parameters. In the basic implementation, Request almost completely uses the interfaces defined in Microsoft.AspNet.Builder to get components from HttpFeatures. Forming a context in this way allows you to hide the specific implementation of the web server-specific implementation of the host-level functionality behind a specific interface of a separate component, not limited to the basic structure of HttpContex.

vNext MVC


The most expected innovation from the point of view of building the web application itself is certainly the combination of ASP.NET MVC and Web Api functionality within one framework, which will allow using a common pipeline to process Http requests.

Adding MVC behavior to vNext involves connecting and configuring two middleware modules:


  public void Configure(IBuilder app) { app.UseServices(services => services.AddMvc()); app.UseMvc(router => router.MapRoute("DefaultHome", "{controller}/{action}/{id?}", defaults: new { Controller = "Home", Action = "Index" })); } 


The first of these is a set of services that provides an implementation of standard MVC components and is used throughout the pipeline to process a request at the level of individual abstractions. We are talking about suppliers of Action context, factory of controllers, model bindings, View Engine provision, etc. Description of services with DI mappings is available for reference in the class Microsoft.AspNet.Mvc.MvcServices.cs.

The second is RouterHandler, which is represented in the vNext by the IRouter interface with the asynchronous RouteAsync method:

  public interface IRouter { Task RouteAsync(RouteContext context); string GetVirtualPath(VirtualPathContext context); } 


By default, the interface implements the MvcRouteHandler class. Unlike previous versions of routing based on framework-specific functionality (in MVC - HttpHandler, Web Api - DelegatingHandler), this time it provides only a call for separate interface methods obtained from the service locator with a set of MVC components. It is this class that receives the ActionContext and starts the further pipeline processing the request using the IActionInvoker service in conjunction with the ControllerFactory. The main advantage of using this approach is obvious, it provides the necessary versatility to merge frameworks, which was absent before.

Another positive change in the new edition of MVC was the fully asynchronous mode of executing service methods. In a similar way, pipe was implemented in Web Api and allowed to completely remove from the workflow pool of the web server the operations associated with waiting for resources. MVC until now only provided asynchronous controllers "out of the box".

The Controller from MVC was taken as the main working unit for processing the Http request in vNext. For post-processing and serialization of results of actions, the IActionResult interface is used. The MVC functionality in this respect has remained conceptually the same. As for the main extensions that are well proven in Web Api, they are not currently added to the vNext pipeline. Like for example the formatting mechanism by using Content Negotiation services. If an instance of a class that does not implement an IActionResult is returned from the controller action, a JSON formatter is used.

The configuration mechanism of the application has been heavily modified due to the transition to the updated project template. Now, instead of the previous web.config, config.json is used, which represents the hierarchical structure of key-value pairs.



Directly at the code level, a set of utilities from the Microsoft.Framework.ConfigurationModel namespace is provided, which merges keys from various configuration sources, for example, the launch parameters of the host application passed to console K; The pairs of web applications defined in the project.json, config.json files.

About each of the components, as well as those that were not mentioned, you can write a separate review and for sure it will not be one. Considering that the list of functional components of the new framework has not yet been finally approved, we restrict ourselves to the basic understanding of the work of its main components.

Results


After reading the alpha version of ASP.NET MVC vNext, you can really say that the changes of the developers are expected to be quite dramatic. They are connected not only with a thorough refactoring of ASP.NET, but also with the adaptation of the framework under the updated Runtime.

At the application level, the change in internal concepts is rather limited and will be intuitive for developers who have dealt with OWIN and previous versions of ASP.NET MVC.

From the point of view of the framework itself, the most important is the transition to an open web interface and a clear division of responsibility between the host and the web application. The qualitative update of the composition of abstractions and the addition of flexible extensibility opportunities open up new perspectives in the development of web applications.

Useful resources:

www.asp.net/vnext
github.com/aspnet
blogs.msdn.com/b/webdev/archive/2014/06/03/asp-net-vnext-in-visual-studio-14-ctp.aspx
www.asp.net/aspnet/overview/owin-and-katana
blogs.msdn.com/b/dotnet/archive/2014/05/12/the-next-generation-of-net-asp-net-vnext.aspx

Source: https://habr.com/ru/post/226427/


All Articles