ASP.NET Core MVC configure global routing prefix

高洛峰
Release: 2017-02-07 11:29:40
Original
1613 people have browsed it

ASP.NET Core MVC configures global routing prefix

Preface

Hello everyone, today I will introduce to you a new feature of ASP.NET Core MVC, adding global routing Unified prefix. Strictly speaking, it is not a new feature, but it is unique to Core MVC.

Application background

I don’t know if you have ever encountered this scenario when you are making Web Api applications, that is, all interfaces start with /api, that is, we The api interface request address is like this:

http://www.example.com/api/order/333

or such a requirement

http://www.example.com/api/v2/order/333

In the past, if we wanted to achieve this requirement, we could add a [Route("/api /order")], then the MVC framework will scan your routing table to match requests like /api/order.

But for the second requirement with a version number, the original Controller’s Route definition was [Route("/api/v1/order")]. Now it needs to be upgraded to v2, and there are hundreds more. The interface needs to be modified one by one, which may cause confusion.

Now, there is a simpler and more elegant way to do this. You can add a global prefix routing tag in a unified manner. Let’s take a look below.

IApplicationModelConvention interface

First, we need to use the IApplicationModelConvention interface, located under the Microsoft.AspNetCore.Mvc.ApplicationModels namespace. Let’s take a look at the definition of the interface.

public interface IApplicationModelConvention
{
 void Apply(ApplicationModel application);
}
Copy after login

We know that the MVC framework has some conventions, so this interface is mainly used to customize some of the MVC conventions. We can add or Modify some conventions. You can see that the interface provides an Apply method. This method has an ApplicationModel object. We can use this object to modify what we need. The MVC framework itself will inject this interface into Services when it starts, so we only need to implement This interface can be configured slightly.

Then let us take a look at what the ApplicationModel object has:

public class ApplicationModel : IPropertyModel, IFilterModel, IApiExplorerModel
{
 public ApiExplorerModel ApiExplorer { get; set; }
 public IList<ControllerModel> Controllers { get; }
 public IList<IFilterMetadata> Filters { get; }
 
 public IDictionary<object, object> Properties { get; }
}
Copy after login

You can see that there are ApiExplorer, Controllers, Filters, Properties and other properties.

ApiExplorerModel: Mainly configures some things of the default MVC Api Explorer, including Api description information, group information, visibility, etc.

ControllerModel: Mainly related to the default convention of Comtroller. There are many things in this, so I won’t introduce them one by one. We will configure one of the things in it later.

IFilterMetadata: Empty interface, mainly used as a marker.

One more thing I need to tell you is that you can see that the above Controllers property is an IList, which means that this list records the information of all Controllers in your program. , you can set it for a certain part or a Controller through traversal, including the information of Actions in the Controller. We can use this feature to very flexibly transform the MVC framework, right? Very cool.

Next, we will use this feature to implement our theme today. Thank you for your thumbs up~ :)

Add global route unified prefix

No more nonsense, go directly to the code, everything you want to say is in the code:

//定义个类RouteConvention,来实现 IApplicationModelConvention 接口
public class RouteConvention : IApplicationModelConvention
{
 private readonly AttributeRouteModel _centralPrefix;
 
 public RouteConvention(IRouteTemplateProvider routeTemplateProvider)
 {
  _centralPrefix = new AttributeRouteModel(routeTemplateProvider);
 }
 
 //接口的Apply方法
 public void Apply(ApplicationModel application)
 {
  //遍历所有的 Controller
  foreach (var controller in application.Controllers)
  {
   // 已经标记了 RouteAttribute 的 Controller
   var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList();
   if (matchedSelectors.Any())
   {
    foreach (var selectorModel in matchedSelectors)
    {
     // 在 当前路由上 再 添加一个 路由前缀
     selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_centralPrefix,
      selectorModel.AttributeRouteModel);
    }
   }
 
   // 没有标记 RouteAttribute 的 Controller
   var unmatchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel == null).ToList();
   if (unmatchedSelectors.Any())
   {
    foreach (var selectorModel in unmatchedSelectors)
    {
     // 添加一个 路由前缀
     selectorModel.AttributeRouteModel = _centralPrefix;
    }
   }
  }
 }
}
Copy after login


Then, we can start using the class we defined.

public static class MvcOptionsExtensions
{
 public static void UseCentralRoutePrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute)
 {
  // 添加我们自定义 实现IApplicationModelConvention的RouteConvention
  opts.Conventions.Insert(0, new RouteConvention(routeAttribute));
 }
}
Copy after login

Finally, in the Startup.cs file, just add the above extension method.

public class Startup
{
 public Startup(IHostingEnvironment env)
 {
  //...
 }
 
 public void ConfigureServices(IServiceCollection services)
 {
  //...
   
  services.AddMvc(opt =>
  {
   // 路由参数在此处仍然是有效的,比如添加一个版本号
   opt.UseCentralRoutePrefix(new RouteAttribute("api/v{version}"));
  });
 }
 
 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 {
  //...
   
  app.UseMvc();
 }
}
Copy after login

Among them, opt.UseCentralRoutePrefix is ​​the extension method defined above. The routing parameters here can still be used, so for example, you can give your interface Specify something like a version number. After this, the RoteAttribute of all your Controllers will be added with this prefix, which perfectly solves the original version number requirement. They look like this:

[Route("order")]
public class OrderController : Controller
{
 // 路由地址 : /api/v{version}/order/details/{id}
 [Route("details/{id}")]
 public string GetById(int id, int version)
 {
  //上面是可以接收到版本号的,返回 version 和 id
  return $"other resource: {id}, version: {version}";
 }
}
 
public class ItemController : Controller
{
 // 路由地址: /api/v{version}/item/{id}
 [Route("item/{id}")]
 public string GetById(int id, int version)
 {
  //上面是可以接收到版本号的,返回 version 和 id
  return $"item: {id}, version: {version}";
 }
}
Copy after login

Summary

The bold words above, I hope everyone can understand and use them, this example is just a practical example In a very small scenario of demand, there will be various normal or abnormal demands in specific projects. We need to think more when making a function. In fact, there are many things to learn about the MVC framework, including Its design ideas, scalability and other things need to be understood slowly. If you are interested in ASP.NET Core, you can follow me. I will regularly share some of my learning results in my blog.

I hope this article can help everyone, thank you for your support of this site!

For more articles related to ASP.NET Core MVC configuring global routing prefix, please pay attention to the PHP Chinese website!


source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!