ASP. NET Core 2.2

  • 2021-11-02 00:31:17
  • OfStack

Endpoint routing

In ASP. NET Core 2.2, a new route is added, called Endpoint (endpoint) route. In this paper, the previous routing system is called traditional routing.

This paper introduces some core functions and implementation methods of traditional routing and Endpoint routing through source code. See official documents for specific functional differences.

Endpoint routing is automatically enabled after upgrading to ASP. NET Core 2.2. If you want to restore the previous implementation logic, you need to add the following code:


services.AddMvc(options => options.EnableEndpointRouting = false)
  .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

The source code analyzed in this article is based on ASP. NET Core version 2.2. 3.

Endpoint action

The difference between Endpoint routing and traditional routing is that the corresponding relationship between Url and Action in traditional routing is handled in UseMvc. We can't get the corresponding Action according to Url and then process it.

Endpoint is to separate the mapping relationship between Url and Action from Mvc and use it as an independent middleware.

The benefit is that we can use some information on Controller and Action in other middleware, such as Attruibute.

The framework also provides the LinkGenerator class to generate links directly from Endpoint, eliminating the need for HttpContext information.

In addition, some RPS (Requests per Second) have been upgraded.

However, at present, Endpoint is still called in UseMvc, and more open usage will be implemented in ASP. NET Core 3.0.

Enable Endpoint routing

See Github for source code. You can also get the source code to see locally.

We can see the following code in the UseMvc method at line 72 of the MvcApplicationBuilderExtensions. cs file:


var options = app.ApplicationServices.GetRequiredService<IOptions<MvcOptions>>();

if (options.Value.EnableEndpointRouting)
{
  ...
}
else
{
  ...
}

In if is the logic of Endpoint routing, and else is the logic of traditional routing.

While MvcOptions is constructed as follows, EnableEndpointRouting controls the default value through CompatibilitySwitch, which is why CompatibilityVersion. Version_2_2 enables Endpoint routing.


public MvcOptions()
{
  // ...
  _enableEndpointRouting = new CompatibilitySwitch<bool>(nameof(EnableEndpointRouting));
  // ...
}

Implementation Principle of Endpoint Routing

The code in lines 92-123 of the MvcApplicationBuilderExtensions. cs file is to convert Action into Endpoint in all Controller.

In line 129 of UseEndpointRouting, a middleware of EndpointRoutingMiddleware is added. This middleware is to find the Endpoint corresponding to the current route from all Endpoint, and then put it into the Feature collection.

In line 132 of UseEndpoint, an EndpointMiddleware middleware is added. This middleware takes out the Endpoint found in EndpointRoutingMiddleware, finds the corresponding Controller and Action according to the MetaData information, and calls.

In the UseMvc method, UseEndpointRouting and UseEndpoint are two consecutive middleware, and UseEndpoint is the end of the request, which means that our custom middleware cannot obtain Endpoint information.

However, by manually calling UseEndpoint, we can still get the routing information of Endpoint.

Use sample

A usage example is shown below.

Defines an LogAttribute class and contains an Message attribute, which is declared and used on Action.

Defines an EndpointTestMiddleware middleware that outputs the Message attribute of LogAttribute.

Call UseEndpointRouting manually, and then call the EndpointTestMiddleware middleware we defined.


// Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseEndpointRouting();

  app.UseMiddleware<EndpointTestMiddleware>();

  app.UseMvc(routes =>
  {
    routes.MapRoute(
      name: "default",
      template: "{controller=Home}/{action=Index}/{id?}");
  });
}
// EndpointTestMiddleware.cs
public class EndpointTestMiddleware
{
  private RequestDelegate _next;

  public EndpointTestMiddleware(RequestDelegate next)
  {
    _next = next;
  }

  public async Task Invoke(HttpContext httpContext)
  {
    var endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;
    if (endpoint == null)
    {
      await _next(httpContext);
      return;
    }
    var attruibutes = endpoint.Metadata.OfType<LogAttribute>();
    foreach (var attribute in attruibutes)
    {
      Debug.WriteLine("------------------------------------------------------------------------");
      Debug.WriteLine(attribute.Message);
      Debug.WriteLine("------------------------------------------------------------------------");
    }
    await _next(httpContext);
  }
}
// LogAttribute.cs
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public sealed class LogAttribute : Attribute
{
  public LogAttribute(string message)
  {
    Message = message;
  }

  public string Message { get; set; }
}
// HomeController.cs
public class HomeController : Controller
{
  [Log("Index")]
  public IActionResult Index()
  {
    return View();
  }

  [Log("Privacy")]
  public IActionResult Privacy()
  {
    return View();
  }
}

In this way, we can get the Endpoint information in our own middleware, then find LogAttribute on Controller, and then output Message.

Summarize

Endpoint is a new routing mechanism in ASP. NET Core 2.2. It solves the problem that traditional routing is difficult to expand, and the problem that traditional routing is too coupled with MVC is solved, and it improves RPS.

This paper introduces the Endpoint routing, analyzes the implementation principle of Endpoint, and gives an example.

Reference link:

[ https://devblogs.microsoft.com/aspnet/asp-net-core-2-2-0-preview1-endpoint-routing/ ]
[ https://www.stevejgordon.co.uk/asp-net-core-first-look-at-global-routing-dispatcher ]
[ https://rolandguijt.com/endpoint-routing-in-asp-net-core-2-2-explained/ ]


Related articles: