一、介绍
在ASP.NET Core中,路由是将传入的URL请求映射到正确的控制器和操作的方法。Attribute路由是一种基于属性,用于定义路由规则的方式,通过在控制器类和操作方法上应用特定的属性,来定义URL模板。
-
基本概念:
-
路由:在ASP.NET Core中,路由是将URL请求映射到正确的控制器和操作的过程。路由中间件会按照定义的路由规则,将传入的HTTP请求匹配到正确的路由路径,进而执行对应的控制器和操作方法。 -
控制器:控制器是处理HTTP请求的类,其中包含处理请求的操作方法。在ASP.NET Core中,控制器类必须继承自Controller或ControllerBase类。 -
操作方法:操作方法是控制器中用于处理HTTP请求的具体实现。通过在控制器类或操作方法上应用特定的属性,可以定义URL模板,从而实现路由匹配。 -
重要性:
-
可读性更强:使用属性路由,可以定义更加清晰和易读的路由路径,使得URL更加友好和易于理解。 -
灵活性更高:属性路由可以更加灵活地定义路由规则,支持多种路由匹配方式,如默认路由、自定义路由、参数路由等。 -
可维护性更高:属性路由的路由规则定义更加集中和清晰,易于维护和管理。同时,由于路由规则定义在控制器类和操作方法上,可以更好地与代码分离,提高代码的可读性和可维护性。 -
性能更优:属性路由在路由匹配时,可以利用编译时静态分析,提前解析路由模板,从而提高路由匹配的性能。
二、传统路由和属性路由的比较和选择
传统路由和属性路由(Attribute Routing)是ASP.NET Core中的两种主要路由(Routing)方式。下面是它们的比较和选择:
-
传统路由(Convention-based Routing):传统路由是一种基于约定的路由方式。在传统路由中,我们定义路由规则时,需要指定路由的URL模板以及相应的控制器和操作方法。传统路由是一种静态路由方式,它的路由规则是在应用程序启动时静态定义的。
-
不够灵活:传统路由的路由规则定义是基于约定的,不够灵活,无法满足一些复杂的路由需求。 -
可读性较差:传统路由的路由规则定义在代码中分散开来,可读性较差。 -
简单易用:传统路由的路由规则定义简单明了,易于理解和使用。 -
性能较高:传统路由的路由规则定义是在应用程序启动时静态定义的,因此在路由匹配时具有较高的性能。 -
优点:
-
缺点:
-
属性路由(Attribute Routing):属性路由是一种基于属性的路由方式。在属性路由中,我们可以在控制器类和操作方法上应用特定的属性来定义路由规则。属性路由是一种动态路由方式,它的路由规则是在运行时动态定义的。
-
相对复杂:属性路由的路由规则定义相对复杂,需要一定的学习成本。 -
性能较低:属性路由的路由规则定义是在运行时动态定义的,因此在路由匹配时性能相对较低。 -
更加灵活:属性路由的路由规则定义更加灵活,可以满足一些复杂的路由需求。 -
可读性更好:属性路由的路由规则定义在代码中集中起来,可读性更好。 -
可维护性更高:属性路由的路由规则定义更加集中和清晰,易于维护和管理。 -
优点:
-
缺点:
-
选择:在选择传统路由和属性路由时,需要根据具体的应用场景和需求来选择。如果应用程序的路由规则比较简单,且性能要求较高,可以选择传统路由;如果应用程序的路由规则比较复杂,且需要更高的可读性和可维护性,可以选择属性路由。同时,在实际开发中,也可以结合使用传统路由和属性路由,以满足不同的路由需求。
三、Attribute路由的基本使用
3.1 在Controller上使用Attribute路由
在ASP.NET Core中,我们可以在控制器类上使用[Route]
属性来定义控制器级别的路由规则。以下是一个示例:
[Route("api/[controller]")]
public class UsersController : Controller
{
[HttpGet]
public IActionResult Get()
{
return Ok();
}
[HttpGet("{id}")]
public IActionResult Get(int id)
{
return Ok();
}
// ...
}
在上面的示例中,我们在UsersController
类上使用了[Route("api/[controller]")]
属性,这表示所有该控制器的操作方法都可以通过“api/users”路径访问。
Tip:这里的
[controller]
是一个占位符,它会被实际的控制器名称替换。例如,如果你访问api/users
路径,[controller]
将被替换为Users
。
此外,我们还分别在Get
和Get(int id)
方法上使用了[HttpGet]
和[HttpGet("{id}")]
属性来定义它们的路由。其中,[HttpGet]
表示该方法可以通过HTTP GET请求访问,而[HttpGet("{id}")]
表示该方法可以通过具有id
参数的HTTP GET请求访问。
通过这种方式,我们可以方便地定义控制器级别的路由规则,从而更好地组织我们的代码和URL。
3.2 在Action上使用Attribute路由
在ASP.NET Core中,我们可以在操作方法上使用[Route]
属性来定义操作方法级别的路由规则。以下是一个示例:
public class UsersController : Controller
{
[HttpGet("{id:int}")]
public IActionResult GetUser(int id)
{
// ...
}
[HttpPost]
[Route("users/create")]
public IActionResult CreateUser(UserViewModel model)
{
// ...
}
// ...
}
在上面的示例中,我们在GetUser
方法上使用了[HttpGet("{id:int}")]
属性,这表示该方法可以通过具有id
参数的HTTP GET请求访问,并且id
必须是整数类型。而在CreateUser
方法上,我们使用了[HttpPost]
和[Route("users/create")]
属性。这表示该方法可以通过HTTP POST请求访问,并且可以通过“users/create”路径访问。 通过这种方式,我们可以更加精细地定义操作方法级别的路由规则,从而更好地满足我们的需求。注意,操作方法级别的路由规则会覆盖控制器级别的路由规则。如果一个操作方法上定义了路由规则,它将优先于控制器级别的路由规则。
3.3 使用自定义路由
在ASP.NET Core中,我们可以使用自定义路由来实现更加灵活的路由规则。以下是一个示例:
public class CustomRouteAttribute : Attribute, IConfigureRoute
{
public string RouteName { get; set; }
public string[] RouteNames { get; set; }
public string Template { get; set; }
public object[] Constraints { get; set; }
public string[] Order { get; set; }
public void Configure(RouteCollection routes, string routeName)
{
var route = new Route(Template, new CustomRouteHandler());
if (Constraints != null)
{
foreach (var constraint in Constraints)
{
route.Constraints.Add(constraint.GetType().Name, constraint);
}
}
if (Order != null)
{
var routeList = new List<Route>();
foreach (var name in RouteNames)
{
var r = routes.GetRouteData(new MvcContext(HttpContext.Current));
while (r != null)
{
if (r.Route.RouteName.Equals(name, StringComparison.OrdinalIgnoreCase))
{
routeList.Add(r.Route);
break;
}
r = r.Route.Parent;
}
}
if (routeList.Count > 0)
{
var index = routeList.IndexOf(route);
if (index >= 0)
{
routeList.RemoveAt(index);
routeList.Insert(index, route);
}
}
else
{
routes.Add(route);
}
}
else
{
routes.Add(route);
}
}
}
[CustomRoute(RouteName = "custom", Template = "custom/{id}")]
public class CustomController : Controller
{
public IActionResult Index()
{
return View();
}
}
在上面的示例中,我们自定义了一个CustomRouteAttribute
属性,并在CustomController
上使用它来定义路由规则。该属性的Template
属性定义了路由模板,RouteName
属性定义了路由名称,还可以定义其他的路由约束和路由顺序等。在Configure
方法中,我们通过RouteCollection
和RouteName
来添加路由规则,并且可以根据需要对路由规则进行排序。 通过这种方式,我们可以更加灵活地定义路由规则,从而更好地满足我们的需求。注意,在使用自定义路由时,需要将UseMvc
替换为UseMvcWithDefaultRoute
,并且需要在Startup.cs
文件的ConfigureServices
方法中注册自定义路由。
四、Attribute路由的高级使用
4.1 路由参数
在 ASP.NET Core 中,我们可以使用 Attribute 路由来定义路由参数。这可以让我们更精确地控制路由的生成。 下面是一个基本的例子:
[Route("api/[controller]")]
public class UsersController : Controller
{
[HttpGet("{id:int}")]
public IActionResult GetUser(int id)
{
// ...
}
}
在这个例子中,[Route("api/[controller]")]
是控制器级别的路由,表示所有 UsersController 的操作都会被路由到 “api/users” 路径。[HttpGet("{id:int}")]
是操作级别的路由,表示 GetUser 方法可以被通过 GET 请求访问,并且需要一个整数参数 “id”。 你可以使用不同的 HTTP 方法来定义路由,例如:
[HttpGet("{id:int}")]
public IActionResult GetUser(int id)
{
// ...
}
[HttpPost]
public IActionResult CreateUser(UserModel model)
{
// ...
}
在上面的例子中,[HttpPost]
表示 CreateUser 方法只能通过 POST 请求访问。 你还可以使用自定义的路由约束来限制路由参数的取值范围,例如:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public class PositiveIntConstraint : Attribute, IHttpRouteConstraint
{
public bool Match(HttpContext context, RouteData data, string parameterName, out RouteValueDictionary values)
{
var value = data.Values[parameterName];
if (value != null && value.ToString().IsInt() && Convert.ToInt32(value) > 0)
{
values = new RouteValueDictionary(new { });
return true;
}
return false;
}
}
public class UsersController : Controller
{
[HttpGet("{id}", Name = "GetUserById")]
[PositiveIntConstraint]
public IActionResult GetUser(int id)
{
// ...
}
}
在上面的例子中,PositiveIntConstraint
是一个自定义的路由约束,它限制了路由参数 “id” 必须是一个大于 0 的整数。如果不符合这个条件,路由请求将会失败。
4.2 其他高级功能
除了上述的路由参数,Attribute 路由还有其他一些高级功能,包括:
-
路由模板:你可以使用和传统路由一样的模板语法来定义 Attribute 路由。比如, [Route("{controller}/{action}/{id}")]
。 -
可选参数:你可以定义可选的路由参数。比如, [Route("products/{id:int?}")]
,这里 id 是可选的。 -
默认值:你可以给路由参数设置默认值。比如, [Route("{controller=Home}/{action=Index}/{id=0}")]
,这里 controller 的默认值是 Home,action 的默认值是 Index,id 的默认值是 0。 -
约束类型:除了整数,你还可以对其他类型的参数进行约束。比如, [HttpGet("{id:guid}")]
可以约束 id 必须是 GUID 类型。 -
自定义约束:你可以定义自己的约束。比如,你可以定义一个约束来检查一个字符串是否是一个有效的 email 地址。 -
嵌套路由:你可以在一个路由中嵌套另一个路由。比如, [Route("{category}/{product}")]
,这里 category 和 product 都是路由参数。 -
静态和动态路由:你可以结合使用静态和动态路由。比如, [Route("/about")]
和[Route("{id}")]
可以同时存在。
五、示例
好的,以下是一个综合了前面所有内容的示例:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public class PositiveIntConstraint : Attribute, IHttpRouteConstraint
{
public bool Match(HttpContext context, RouteData data, string parameterName, out RouteValueDictionary values)
{
var value = data.Values[parameterName];
if (value != null && value.ToString().IsInt() && Convert.ToInt32(value) > 0)
{
values = new RouteValueDictionary(new { });
return true;
}
return false;
}
}
public class UsersController : Controller
{
[HttpGet("{id}", Name = "GetUserById")]
[PositiveIntConstraint]
public IActionResult GetUser(int id)
{
// ...
}
[HttpGet("users/edit/{id:guid}")]
public IActionResult EditUser(Guid id)
{
// ...
}
[HttpPost]
[Route("users/create")]
public IActionResult CreateUser(UserModel model)
{
// ...
}
[Route("users/deleted/{id}")]
public IActionResult DeleteUser(int id)
{
// ...
}
[Route("users/restore/{id}")]
public IActionResult RestoreUser(int id)
{
// ...
}
[Route("{*url}", Name = "PageNotFound")]
public IActionResult PageNotFound()
{
// ...
}
}
在上面的例子中,我们定义了一个 PositiveIntConstraint
约束来限制路由参数必须是一个大于 0 的整数。我们定义了 5 个不同的路由:
-
GetUser
方法可以通过/users/123
这样的 URL 访问,其中 123 是一个大于 0 的整数。 -
EditUser
方法可以通过/users/edit/456
这样的 URL 访问,其中 456 是一个 GUID 类型的参数。 -
CreateUser
方法可以通过/users/create
这样的 URL 访问,不需要任何参数。 -
DeleteUser
方法可以通过/users/deleted/789
这样的 URL 访问,其中 789 是一个大于 0 的整数。 -
RestoreUser
方法可以通过/users/restore/1000
这样的 URL 访问,其中 1000 是一个大于 0 的整数。 -
如果请求的 URL 不符合上面的任何一个路由,那么就会返回 PageNotFound
方法的结果,这个方法会返回一个 404 页面。
六、总结
Attribute路由是一种强大的路由机制,允许我们在 ASP.NET Core 中灵活地定义路由。通过使用各种属性和约束,我们可以精确控制 URL 的生成和解析。Attribute 路由提供了路由参数、可选参数、默认值、约束类型、自定义约束、嵌套路由、静态和动态路由等高级功能。这使得我们能够构建复杂而强大的 Web 应用程序,同时也提高了代码的可读性和可维护性。通过合理地使用 Attribute 路由,我们可以提升 Web 应用程序的性能和用户体验。
原文始发于微信公众号(喵叔写技术):【ASP.NET Core 基础知识】–路由和请求处理–Attribute路由
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/206578.html