Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of Routing routing in .NET / ASP.NET

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces the example analysis of Routing routing in .NET / ASP.NET, which has a certain reference value. Interested friends can refer to it. I hope you will learn a lot after reading this article.

1] introduction at the beginning

The ASP.NET Routing system is the basis for all Uri access applications through ASP.NET (not a direct mapping of physical files). With the advent of Routing, our WEB design has become very different from what it used to be; it is becoming more and more lightweight and simple, all handled in the way of simple Uri resources, and focuses on business design. At present, the mainstream Rest ful api is also based on such a mechanism, but our ASP.NETMVC is also a framework for program access processing through independent Uri, so it is also based on ASP.NET Routing;, that is, the popular ASP.NET technology (ASP.NETWEBAPI). It is all based on the Routing framework, which shows that it is still quite important.

So in this article, let's analyze how Routing works, and why it can provide such good scalability without affecting the existing framework really makes people want to find out. At present, it is very impressive that we all know the existing framework knowledge of ASP.NET, and we probably know where it must have intercepted the ASP.NET pipeline model.

Let's take this important clue to figure out how it supports other frameworks. What puzzles me most is how it makes a good distinction between WebPage and MVC. The most important thing is how it provides only one interface so that subsequent related frameworks can be extended based on this common Routing interface. Its object model must be very clever. We need to understand it in order to have the confidence to continue the follow-up study of our ASP.NET-related framework.

Note: the word Routing is used instead of the word ASP.NETRouting in the full text, which is hereby explained to avoid conceptual confusion.

2] location of the ASP.NETRouting routing object model

What is the most important extension point for ASP.NET? I think we will all say in unison: in the pipeline model, this is also in line with our basic idea of solving this problem; the ASP.NET pipeline model is understood by everyone, as long as we define the relevant events in the pipeline model, we can insert our own logic into the pipeline processing. The last execution interface of the pipeline is the IHttpHander type, so it is possible to change the whole processing flow only by preventing the creation of the default IHttpHander interface.

Figure 2.1:

Then Routing can reverse the opportunity of the entire processing route only if it is executed before blocking the creation of the IHttpHander interface. The Application Event (2) (IHttpHander execution) shown in the figure above means that only the execution of Routing in an Application Event before the execution of IHttpHander can execute other customized IHttpHander in the place where the IHttpHander was originally executed. IHttpHander is the final execution interface of the ASP.NET framework, so if you want to change the Hander that originally executes Page, you need to provide a custom IHttpHander interface object.

In other words, the execution entry of everything is actually in the IHttpHander.ProcessRequest () method, but now the paradox is that ASP.NET Routing is stuck in the middle, which makes the original direct processing flow a little blurred, separating the "ASP.NET basic framework" from the "ASP.NET-based application framework" (such as: ASP.NETMVC\ ASP.NETWEBAPI\ custom framework)

Note: "ASP.NET basic framework" refers to the framework of ASP.NET itself, which can be understood as traditional WEBFROM;, while "ASP.NET-based application framework" refers to upper-level lightweight application frameworks such as MVC\ WEBPAGE\ WEBAPI designed based on ASP.NET basic framework.

Figure 2.2:

In fact, this picture clearly expresses the location of ASP.NETRouting, which is the key link between ASP.NET, ASP.NETMVC and ASP.NETWEBAPI. According to our analysis above, Routing is the object model for the direct interaction of the ASP.NET framework, so from the point of view of ASP.NET, it does not know what is going on behind it. In fact, ASP.NETRouting has transferred the original creation logic to a life event in ASP.NETApplication.

3.] entry to the ASP.NETRouting routing object model

Routing acts as a middleman, transparently wrapping the relevant logic of ASP.NET. Although we can also use related ASP.NET objects on the upper layer of Routing, the concept has changed fundamentally. We can freely introduce custom IHttpHander implementation classes and execute policies according to the Uri passed from the front end, that is to say, you can define a set of Uri rules and processing framework for your own internal use, and it will be easy to build on Routing.

According to the relevant knowledge of IHttpModule and IHttpHander, we can easily know where to find the entry clue of Routing. If we have guessed correctly, there must be an IHttpModule in the Web.config file of the system that specifically deals with Routing, which can be used to implant ASP.NETRouting objects into the ASP.NET framework.

We found the configuration of the .NET Framework environment: C:\ Windows\ Microsoft.NET\ Framework\ v4.0.30319\ Config in this file we can find system-level configuration information

In fact, all the options are configured at the system level, and the Web.config file used in our program is only used to configure options related to the application. The advantage is that we can easily change the default configuration of the system at the application level.

We find the httpModules configuration section, and on the penultimate line, we find an IHttpModule configuration whose name is UrlRoutingModule-4.0. This should be it. The most important thing is that its type message is System.Web.Routing.UrlRoutingModule.

It is much easier now, we just need to find out how UrlRoutingModule works, but we can't rush it first, and some ideas are not clear, so we continue to analyze it slowly; according to such an idea, we can basically conclude that UrlRoutingModule is the link to coordinate the ASP.NETRouting framework.

Figure 3.1:

This figure summarizes one of our basic ideas so far. The underlying ASP.NET framework deals with the objectification of HTTP, then creates an IHttpHandler interface object through ASP.NETRouting Module, and then executes the IHttpHander interface, a total of three steps.

As the application framework, that is, the top-level code, how can we decide that the ASP.NETRouting framework can use its own IHttpHander interface object when handling ASP.NET calls? this problem requires us to take an in-depth look at the internal object model of the ASP.NETRouting routing object.

4.] Internal structure of ASP.NETRouting routing object model

Here I will use ASP.NETMVC as the application framework to explain this example (I don't know ASP.NETWEBAPI at the moment). So how does ASP.NETMVC, as an application layer framework, get ASP.NETRouting to help transform the IHttpHander interface? so we have to analyze the composition and interaction of some columns of Routing objects.

According to section 3.], we have learned that ASP.NETRouting uses the UrlRoutingModuel object as the listener of the ASP.NET pipeline, and then obtains the final IHttpHander interface object based on a series of internal processing; so if we want to understand how UrlRoutingModule coordinates all this, we have to analyze the source code in depth, even though we only need to know 80%.

Note: friends who need the source code can go directly to the site to get it. Microsoft's official open source website: http://www.codeplex.com/, open source China: http://www.oschina.net/ can all find the source code.

4. 1] UrlRoutingModule object internal structure

The first thing we need to figure out is the UrlRoutingModule object. According to the source code, we can basically determine several basic principles. First, UrlRoutingModule inherits from the IHttpModule interface and subscribes to the Application.PostResolveRequstCache event. In this event, it is mainly through the global routing object table RouteTable object to obtain the dependency injection interface IRouteHander interface provided for the upper layer.

[dependency injection interface]

Here we need to explain what the dependency injection interface is, which can be simply understood as providing the outside world with an opportunity for concrete implementation; in fact, it is the "dependency inversion principle" in the design principle, which is not directly dependent on the specific object within the RouteData; the interface is a contract, and providing an interface is to agree on the contract between the two parties. It is agreed that the Routing framework will use the IRouteHander interface to get the final processing IHttpHander interface

Next, we will analyze the UrlRoutingModule object, because we analyze the source code to figure out the operation flow and relationship between the object models, so it is impossible to analyze all the code, our focus is to figure out their execution order and principle; because the UrlRoutingModule object is the fuse, its appearance will implicate other objects one after another, we will analyze it in sub-sections and pass through the junction.

According to our previous analysis, we first need to find the place where UrlRoutingModule binds the Application event

Protected virtual void Init (HttpApplication application) {application.PostResolveRequestCache + = PostResolveRequestCache;}

In the PostResolverRequestCache method, we will see that the method calls a local internal method with the same name:

Void PostResolveRequestCache (object o, EventArgs e) {var app = (HttpApplication) o; PostResolveRequestCache (new HttpContextWrapper (app.Context));}

Then instantiate a HttpContextWrapper wrapper object, passing in the method of the same name

Public virtual void PostResolveRequestCache (HttpContextBase context) {var rd = RouteCollection.GetRouteData (context); / / (1) matches the RouteData object, which is analyzed later; var rc = new RequestContext (context, rd); / / (2) encapsulates the calculated RouteData object and the current HttpRequest object IHttpHandler http = rd.RouteHandler.GetHttpHandler (rc); / / (3) use the RouteHander attribute in the current RouteData object calculated in step (1) to get the route handler IHttpHander interface context.Request.RequestContext = rc; context.RemapHandler (http);}

Of course, I have omitted some unrelated code, after all, it is obviously not enough to explain all the code clearly; in the above code, I marked the important parts in red.

First of all, the first important point (1) is to match the RouteData object; in fact, it is the Url template data that we configure in the program. When the request comes, we need to go to the routing table according to the Url of the current request to match whether there are any routing objects that match the current Url.

Routes.MapRoute (name: "Default", url: "{controller} / {action} / {id}", defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional}

In fact, it corresponds to the configuration of this code. After processing, this code will be an instance of a Route object, and the RouteCollection above is easy to understand. It is a strongly typed collection of Route.

So far, there have been several Route-related objects, and it doesn't matter, their role will be clear when we analyze the whole line to the end.

The second important point (2), encapsulates the RequestContext object, in fact, we can determine its purpose from the name of the type, it is the request context, but also the bounded context; this encapsulates the need to be used as a parameter when getting the IHttpHander interface below

The third point (3), using the RouteData object obtained by the previous matching, in fact, RouteData means routing data, so what is routing data: it is the data related to routing generated after a successful route matching; remember the principle we analyzed in section 3], UrlRoutingModule provides basic routing functions to the upper layer, but the specific processing is at the application level

So this is the final top-level application processor obtained here through the RouteData.RouteHandler.GetHttpHandler (RequestContext requestContext) method.

Figure 4.1:

The above explanation can be expressed simply by using this picture.

The UrlRoutingModule object obtains the IRouteHander interface through the RouteData routing data object, and then obtains the final IHttpHander interface through the IRouteHander interface.

Summary: in fact, the UrlRoutingModule object can be understood as the basic part of the ASP.NETRouting module, and the extension is in the place where our application is configured, that is, the routing data that we usually configure in the Global.asax.cs file; when we configure the Route object, we have already specified the IRouteHander interface, and then this interface will be put into the RouteData property of the same name, rather than directly acquired by UrlRoutingModule as a fragmented object

4.2] RouteBase, Route, RouteCollection, RouteTable routing Core object Model

In Section 4. 1], UrlRoutingModule is the infrastructure part of the routing framework, built into. In the NETFramework system and ASP.NET configuration, when web.config; carries on the version upgrade in ASP.NET, the system has automatically upgraded this part of the work for us. When we use it, we only need to create a version above ASP.NET3.5 SP1 that will automatically have the routing system function, because according to Microsoft's official MSDN, the routing system is introduced in ASP.NET3.5 SP1. In fact, most of the ASP.NET versions we use are already 4.5, and even the previous versions of 2.0 and 3.0 will be upgraded to the latest version one after another, because the new version of the framework provides countless advantages that you cannot refuse.

Well, when we have the basic part, we can do the programming of the application programming interface, in fact, this part is where we come into contact with; and in this section, we will focus on analyzing the programming interface that the routing system provides to us at the application level, that is, the core objects listed in the title above.

Let's first give a basic introduction to the meaning of these objects and their relationship with each other:

RouteBase: obviously the base class of Route, providing a top-level abstraction as a custom routing object, all routing frameworks use abstract RouteBase as dependencies

Route: the routing object implemented by default in the routing system inherits from the RouteBase abstract base class and is used as our default routing configuration object. Of course, you can implement your own Route object.

RouteCollection:Route is the configuration of a single Url, so there must be multiple Url rules in the system, so the RouteCollection object is a strongly typed collection of Route, which inherits from the Collection type; so RouteCollection is used as the collection management of Route; note that RouteBase in the generic Collection here once again reminds us to "dependency inversion"

RouteTable: used to store RouteCollection objects. There are a series of routing objects in the routing table, which are managed by RouteCollection. In RouteTable, the Routes static attribute is used to represent the global route mapping table of the current system.

It is obvious here that there is a layer-by-layer abstraction of routing, from the simple Route representing a route map, to the collection RouteCollection representing Route, to the final RouteTable, which is very abstract.

In order to give you an intuitive understanding of the interpretation of these objects, we use a diagram to explain how they relate and implement the process.

Figure 4.2:

Next, we will go deep into the interior of each object to explore the interaction between them, and we will analyze it according to this reference relationship, starting with the Route object.

[Route 、 RouteBase]

The Route object inherits from the configuration of RouteBase that represents a Url template, including the string of Url template, such as api/order/102304, and some auxiliary content. This is not the focus of this section. We just need to know that it is used to configure Url. The Route object is not instantiated directly by us, but is instantiated through the extension method of the application layer. Why do you do this? in fact, this is the key point of why the route can go to the upper layer.

According to the route set extension class in ASP.NETMVC, that is, the extension method in the System.Web.Mvc.RouteCollectionExtensions static class, these extension methods are used to package the configuration of Route when we apply ASP.NET. Do you remember that at the beginning of section 4] we introduced the principle of a dependency injection interface, which will achieve the purpose of plug-in custom implementation through the dependency injection interface?

In the Route source code, we will see that it has an attribute of IRouteHander interface type RouteHander

Public class Route: RouteBase {public IRouteHandler RouteHandler {get; set;}}

The property of this IRouteHandler interface type is an IRouteHandler interface that we ASP.NETMVC will implement; and the definition of this interface:

Public interface IRouteHandler {IHttpHandler GetHttpHandler (RequestContext requestContext);}

Quite simply, to create the IHttpHandler interface that the ASP.NET pipeline engine finally executes; the Route class has a core method that overrides RouteBase:

Public override RouteData GetRouteData (HttpContextBase httpContext)

This method is used to obtain some matching data of the current route. RouteData is described in Section 4.1]. We will take a look at the following detailed analysis, which will not be introduced here.

Summary: in fact, the Route object is quite simple. The two key points are the GetRouteData method and the IRouteHander interface. The former is used to obtain the routing information after the current route is matched successfully, while the latter is used to return the IHttpHandler interface to be executed.

[RouteCollection 、 RouteTable]

RouteCollecton and RouteTable objects are relatively simple. Let's first look at RouteCollection objects. First of all, you may wonder why not use a simple object of type Collection to store Route instances. If you want to implement a RouteCollection; without looking at the source code, you really don't know that a lot of work has been done inside it. First of all, the most important thing is the Look mechanism in the case of thread concurrency. Because our RouteCollection object is a global static object, there are multiple threads reading this object concurrently, so mutex control must be performed when accessing the collection; for example, this code:

Public void Add (string name, RouteBase item) {lock (GetWriteLock ()) {base.Add (item); if (! String.IsNullOrEmpty (name)) d.Add (name, item);}}

When adding a route, the write object is locked first, and then it can be operated safely; we then go to the RouteTable object, which is the simplest, which is a static property Routes used to store the global routing table.

Public class RouteTable {static RouteTable () {Routes = new RouteCollection ();} public static RouteCollection Routes {get; private set;}}

When the Routes property is first obtained, the RouteCollection object is instantiated in the static constructor

4.3] RouteValueDictionary, RouteData, RequestContext routing data object Model

In section 4.2], we analyze several core objects of the routing system, but if the core objects are to run, there must be some data encapsulated objects to eliminate the data transfer problem for them; and the three core objects in this section are really essential data storage and data transfer container core objects for the routing system to work successfully.

Let's first give a basic introduction to the meaning of these objects and their relationship with each other:

RouteValueDictionary: objects used for intermediate values are stored inside routing objects, such as default values of Url templates, namespaces, parameters passed from the address bar, etc.; of course, they can also be used to store any value in the form of any Key-Value.

RouteData: routing data, which is used to encapsulate the routing data after a successful match according to the routing Url. The most important thing is to pass the IRouteHander interface to the UrlRoutingModule.

RequestContext: request context, which wraps HttpRequest and RouteData into the IRouteHander interface to obtain the IHttpHander interface; because the IRouteHandler interface method GetHttpHandler needs to know some information of the current request and the routing data processed by the current Url before calculating the current IHttpHandler interface

In order to give you an intuitive understanding of the interpretation of these objects, we use a diagram to explain how they relate and implement the process.

Figure 4.3:

The following detailed analysis of the internal principles of each object

[RouteValueDictionary]

The RouteValueDirctionary object is used to store data inside the routing object. For example, when we configure routing, we can specify some default values, namespaces, and so on.

Look at the definition of RouteValueDictionary source code:

Public class RouteValueDictionary: IDictionary

This type inherits from the dictionary interface IDictionary, not from the dictionary base class, and is intended to use the behavior of a dictionary rather than its default implementation; a Dictionary type is used as the final container within RouteValueDictionary

Dictionary d = new Dictionary (CaseInsensitiveStringComparer.Instance)

An inner class CaseInsensitiveStringComparer is used in the constructor to compare the equality of Key:

Internal class CaseInsensitiveStringComparer: IEqualityComparer {public static readonly CaseInsensitiveStringComparer Instance = new CaseInsensitiveStringComparer (); public int GetHashCode (string obj) {return obj.ToLower (CultureInfo.InvariantCulture). GetHashCode ();} public bool Equals (string obj1, string obj2) {return String.Equals (obj1, obj2, StringComparison.OrdinalIgnoreCase);}}

The IEqualityComparer interface is still very good, but now it is basically not used like this. Instead, it directly provides a Lambda as a comparison function.

[RouteData]

I think you should know the general meaning of routing data object. It has been mentioned many times above, so I will not introduce it here. Let's take a look at the core code snippet inside RouteData:

Public RouteData (RouteBase route, IRouteHandler routeHandler) {Route = route; RouteHandler = routeHandler; DataTokens = new RouteValueDictionary (); Values = new RouteValueDictionary ();} public RouteValueDictionary DataTokens {get; private set;} public RouteBase Route {get; set;} public IRouteHandler RouteHandler {get; set;} public RouteValueDictionary Values {get; private set;}

Through the constructor, we can see that the reference to the Route object and the reference to the IRouteHander interface are saved. Why IRouteHandler is used as the constructor parameter is because RouteBase has no property definition of the IRouteHander interface at all; the IRouteHandler interface is not important in RouteBase or Route, because Route can be customized, where the mandatory is in RouteData, and its constructor must accept the IRouteHandler type interface.

Let's go on to see that in the next two lines of code of the constructor, the two properties DataTokens and Values are instantiated respectively, and the type is RouteValueDictionary, which coincides with what we analyzed above. RouteValueDictionary is used internally to hold these fragmented key value pairs data containers, which is needed in Route, RouteData and other places. It is because RouteValueDictionary's Value is of Object type, so it can be used to store values of any type, which is more general.

[RequestContext]

RequestContext has also been contacted many times above, indicating the request context, that is, all the data related to the request is encapsulated inside; in later articles, we will come into contact with many Context-like objects, such as ControlContext,ViewContext, which are used to control the boundaries of the context, rather than passing piecemeal parameters directly.

4.4] the relationship between IRouteHandler and IHttpHander interfaces

The IRouteHandler interface is the core of the routing framework, and only by providing the IRouteHandler implementation can we successfully get the IHttpHandler interface behind it; ASP.NETMVC provides the MvcRouteHandler object to implement the IRouteHandler interface, and MvcRouteHandler instantiates the MvcHandler object of the IHttpHandler interface internally; MvcHandler then obtains the RouteData object through the RequestContext object, and then obtains the corresponding Control information for subsequent execution

5.] the internal structure of UrlRoutingHandler object and its extended application

There is a very important IHttpHandler interface object UrlRoutingHanlder in the ASP.NETRouting routing framework. I think you must be wondering why such an object is needed; in fact, it exists to provide us with the opportunity to bypass the UrlRoutingModule module. According to the detailed analysis above, we know that the entry of the route is in UrlRoutingModule, and all the route-related mapping work is done in this class, but sometimes we want to bypass UrlRoutingModule for simple processing or performance optimization considerations, which come in handy. At present, the usage scenario I can think of is that it is convenient to rewrite the project of the first version of ASP.NET. First of all, our project needs to be built on the lower version of ASP.NET, but we need to add the function of Url.ReWriter, so we need to implement this function ourselves.

However, the workload and performance are difficult to control. It is very convenient to use the UrlRoutingHandler provided here for implementation. UrlRoutingHandler gives us the opportunity to use the ASP.NETRouting framework without worrying about whether UrlRoutingModule is configured or not.

Public abstract class UrlRoutingHandler: IHttpHandler

From the code, we can see that it is an abstract class that implements the IHttpHanlder interface directly, but the important thing is the ProcessRequest method

Protected virtual void ProcessRequest (HttpContextBase httpContext) {if (httpContext = = null) throw new ArgumentNullException ("httpContext"); var rd = RouteCollection.GetRouteData (httpContext); if (rd = = null) throw new HttpException ("The incoming request does not match any route"); if (rd.RouteHandler = = null) throw new InvalidOperationException ("No IRouteHandler is assigned to the selected route"); RequestContext rc = new RequestContext (httpContext, rd) Var hh = rd.RouteHandler.GetHttpHandler (rc); VerifyAndProcessRequest (hh, httpContext);} protected abstract void VerifyAndProcessRequest (IHttpHandler httpHandler, HttpContextBase httpContext)

The logic of this method is similar to that of the PostResolveRequestCache method in UrlRoutingModule, and the current RouteData object is matched through the global RouteCollection collection; that is enough to show that the process will no longer go through the UrlRoutingModule module; the last line of the method is to execute a template method: VerifyAndProcessRequest, which is left to the subclass to implement

So here we put routing and execution together, and the base class is responsible for routing subclass is responsible for execution, which is a very good design method.

Thank you for reading this article carefully. I hope the article "sample Analysis of Routing routing in .NET / ASP.NET" shared by the editor will be helpful to you. At the same time, I also hope that you will support and follow the industry information channel. More related knowledge is waiting for you to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report