首页 后端开发 C#.Net教程 ASP.NET Core MVC 配置全局路由前缀

ASP.NET Core MVC 配置全局路由前缀

Feb 07, 2017 am 11:29 AM

ASP.NET Core MVC 配置全局路由前缀

前言

大家好,今天给大家介绍一个 ASP.NET Core MVC 的一个新特性,给全局路由添加统一前缀。严格说其实不算是新特性,不过是Core MVC特有的。

应用背景

不知道大家在做 Web Api 应用程序的时候,有没有遇到过这种场景,就是所有的接口都是以 /api 开头的,也就是我们的api 接口请求地址是像这样的:

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

或者是这样的需求

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

在以前,我们如果要实现这种需求,可以在 Controller 中添加一个 [Route("/api/order")] 这样的特性路由 Attribute,然后MVC 框架就会扫描你的路由表从而可以匹配到 /api/order 这样的请求。

但是第二个带版本号的需求,原本 Controller 的 Route 定义是 [Route("/api/v1/order")],现在要升级到v2,又有上百个接口,这就需要一个一个修改,可能就会懵逼了。

现在,有一种更加简便优雅的方式来做这个事情了,你可以统一的来添加一个全局的前缀路由标记,下面就一起来看看吧。

IApplicationModelConvention 接口

首先,我们需要使用到 IApplicationModelConvention这个接口,位于 Microsoft.AspNetCore.Mvc.ApplicationModels 命名空间下,我们来看一下接口的定义。

public interface IApplicationModelConvention
{
 void Apply(ApplicationModel application);
}
登录后复制

我们知道,MVC 框架有一些约定俗成的东西,那么这个接口就是主要是用来自定义一些 MVC 约定的一些东西的,我们可以通过指定 ApplicationModel 对象来添加或者修改一些约定。可以看到接口提供了一个 Apply的方法,这个方法有一个ApplicationModel对象,我们可以利用这个对象来修改我们需要的东西,MVC 框架本身在启动的时候会注入这个接口到 Services 中,所以我们只需要实现这个接口,然后稍加配置即可。

那再让我们看一下ApplicationModel 这个对象都有哪些东西:

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; }
}
登录后复制

可以看到有 ApiExplorer,Controllers,Filters,Properties 等属性。

ApiExplorerModel:主要是配置默认MVC Api Explorer的一些东西,包括Api的描述信息,组信息,可见性等。

ControllerModel:主要是 Comtroller 默认约定相关的了,这个里面东西就比较多了,就不一一介绍了,我们等下就要配置里面的一个东西。

IFilterMetadata :空接口,主要起到标记的作用。

还有一个地方需要告诉大家的是,可以看到上面的 Controllers 属性它是一个IList,也就是说这个列表中记录了你程序中的所有 Controller 的信息,你可以通过遍历的方式针对某一部分或某个 Controller 进行设置,包括Controller中的Actions的信息都可以通过此种方式来设置,我们可以利用这个特性来非常灵活的对 MVC 框架进行改造,是不是很炫酷。

下面,我们就利用这个特性来实现我们今天的主题。谢谢你点的赞~ :)

添加全局路由统一前缀

没有那么多废话了,直接上代码,要说的话全在代码里:

//定义个类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;
    }
   }
  }
 }
}
登录后复制


然后,我们就可以开始使用我们自己定义的这个类了。

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

最后,在 Startup.cs 文件中,添加上面的扩展方法就可以了。

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();
 }
}
登录后复制

其中,opt.UseCentralRoutePrefix 就是上面定义的那个扩展方法,此处路由参数仍然是可以使用的,所以比如你可以给你的接口指定一个版本号之类的东西。这样之后,你的所有 Controller 的 RoteAttribute 都会添加上了这个前缀,这样就完美解决了最开始的那个版本号的需求。他们看起来大概是这样的:

[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}";
 }
}
登录后复制

   

总结

上面的黑体字,希望大家能够理解并运用,这个例子只是实际需求中的很小的一个场景,在具体的项目中会有各种各样正常或者非正常的需求,我们在做一个功能的时候要多多思考,其实 MVC 框架还有很多东西可以去学习,包括它的设计思想,扩展性等东西,都是需要慢慢领悟的。如果大家对 ASP.NET Core 感兴趣,可以关注我一下,我会定期在博客中分享我的一些学习成果吧。

通过此文希望能帮助大家,谢谢大家对本站的支持!

更多ASP.NET Core MVC 配置全局路由前缀相关文章请关注PHP中文网!


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

char在C语言中如何处理特殊字符 char在C语言中如何处理特殊字符 Apr 03, 2025 pm 03:18 PM

C语言中通过转义序列处理特殊字符,如:\n表示换行符。\t表示制表符。使用转义序列或字符常量表示特殊字符,如char c = '\n'。注意,反斜杠需要转义两次。不同平台和编译器可能有不同的转义序列,请查阅文档。

char在C语言字符串中的作用是什么 char在C语言字符串中的作用是什么 Apr 03, 2025 pm 03:15 PM

在 C 语言中,char 类型在字符串中用于:1. 存储单个字符;2. 使用数组表示字符串并以 null 终止符结束;3. 通过字符串操作函数进行操作;4. 从键盘读取或输出字符串。

char与wchar_t在C语言中的区别 char与wchar_t在C语言中的区别 Apr 03, 2025 pm 03:09 PM

在 C 语言中,char 和 wchar_t 的主要区别在于字符编码:char 使用 ASCII 或扩展 ASCII,wchar_t 使用 Unicode;char 占用 1-2 个字节,wchar_t 占用 2-4 个字节;char 适用于英语文本,wchar_t 适用于多语言文本;char 广泛支持,wchar_t 依赖于编译器和操作系统是否支持 Unicode;char 的字符范围受限,wchar_t 的字符范围更大,并使用专门的函数进行算术运算。

C语言各种符号的使用方法 C语言各种符号的使用方法 Apr 03, 2025 pm 04:48 PM

C 语言中符号的使用方法涵盖算术、赋值、条件、逻辑、位运算符等。算术运算符用于基本数学运算,赋值运算符用于赋值和加减乘除赋值,条件运算符用于根据条件执行不同操作,逻辑运算符用于逻辑操作,位运算符用于位级操作,特殊常量用于表示空指针、文件结束标记和非数字值。

c#多线程和异步的区别 c#多线程和异步的区别 Apr 03, 2025 pm 02:57 PM

多线程和异步的区别在于,多线程同时执行多个线程,而异步在不阻塞当前线程的情况下执行操作。多线程用于计算密集型任务,而异步用于用户交互操作。多线程的优势是提高计算性能,异步的优势是不阻塞 UI 线程。选择多线程还是异步取决于任务性质:计算密集型任务使用多线程,与外部资源交互且需要保持 UI 响应的任务使用异步。

char在C语言中如何进行类型转换 char在C语言中如何进行类型转换 Apr 03, 2025 pm 03:21 PM

在 C 语言中,char 类型转换可以通过:强制类型转换:使用强制类型转换符将一种类型的数据直接转换为另一种类型。自动类型转换:当一种类型的数据可以容纳另一种类型的值时,编译器自动进行转换。

C语言 sum 的作用是什么? C语言 sum 的作用是什么? Apr 03, 2025 pm 02:21 PM

C语言中没有内置求和函数,需自行编写。可通过遍历数组并累加元素实现求和:循环版本:使用for循环和数组长度计算求和。指针版本:使用指针指向数组元素,通过自增指针遍历高效求和。动态分配数组版本:动态分配数组并自行管理内存,确保释放已分配内存以防止内存泄漏。

char数组在C语言中如何使用 char数组在C语言中如何使用 Apr 03, 2025 pm 03:24 PM

char 数组在 C 语言中存储字符序列,声明为 char array_name[size]。访问元素通过下标运算符,元素以空终止符 '\0' 结尾,用于表示字符串终点。C 语言提供多种字符串操作函数,如 strlen()、strcpy()、strcat() 和 strcmp()。

See all articles