在ASP.NET Core中,路由是将传入的URL请求映射到正确的控制器和操作的方法。Attribute路由是一种基于属性,用于定义路由规则的方式,通过在控制器类和操作方法上应用特定的属性,来定义URL模板。
基本概念:
重要性:
传统路由和属性路由(Attribute Routing)是ASP.NET Core中的两种主要路由(Routing)方式。下面是它们的比较和选择:
传统路由(Convention-based Routing):
传统路由是一种基于约定的路由方式。在传统路由中,我们定义路由规则时,需要指定路由的URL模板以及相应的控制器和操作方法。传统路由是一种静态路由方式,它的路由规则是在应用程序启动时静态定义的。
优点:
缺点:
属性路由(Attribute Routing):
属性路由是一种基于属性的路由方式。在属性路由中,我们可以在控制器类和操作方法上应用特定的属性来定义路由规则。属性路由是一种动态路由方式,它的路由规则是在运行时动态定义的。
优点:
缺点:
选择:
在选择传统路由和属性路由时,需要根据具体的应用场景和需求来选择。如果应用程序的路由规则比较简单,且性能要求较高,可以选择传统路由;如果应用程序的路由规则比较复杂,且需要更高的可读性和可维护性,可以选择属性路由。同时,在实际开发中,也可以结合使用传统路由和属性路由,以满足不同的路由需求。
在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。
在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”路径访问。
通过这种方式,我们可以更加精细地定义操作方法级别的路由规则,从而更好地满足我们的需求。注意,操作方法级别的路由规则会覆盖控制器级别的路由规则。如果一个操作方法上定义了路由规则,它将优先于控制器级别的路由规则。
在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
方法中注册自定义路由。
在 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 的整数。如果不符合这个条件,路由请求将会失败。
除了上述的路由参数,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 类型。[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 的整数。PageNotFound
方法的结果,这个方法会返回一个 404 页面。Attribute路由是一种强大的路由机制,允许我们在 ASP.NET Core 中灵活地定义路由。通过使用各种属性和约束,我们可以精确控制 URL 的生成和解析。Attribute 路由提供了路由参数、可选参数、默认值、约束类型、自定义约束、嵌套路由、静态和动态路由等高级功能。这使得我们能够构建复杂而强大的 Web 应用程序,同时也提高了代码的可读性和可维护性。通过合理地使用 Attribute 路由,我们可以提升 Web 应用程序的性能和用户体验。