我们有一堆端点,我们希望它们对每个端点执行完全相同的操作: 将它们注册为路由,并验证用户是否有权访问它们。非常精打细算,我们的问题可以归结为我们遇到这样的事情:
[HttpGet, Route(EntityId.First)]
[HttpGet, Route(EntityId.Second)]
[VerifyAccessFilter(EntityId.First, EntityId.Second)]
public async Task<IActionResult> Endpoint()
{
return Ok();
}
但更希望是这样的:
[RouteAndVerify(EntityId.First, EntityId.Second)]
public async Task<IActionResult> Endpoint()
{
return Ok();
}
您可以说这很简单,但是我希望这个意图能够传播。 困难的部分似乎是在不使用默认Route-attribute的情况下注册路由。
答案 0 :(得分:1)
您可以通过自定义IActionModelConvention
实现来实现。官方文档解释了动作模型约定的概念:Work with the application model in ASP.NET Core - Conventions。简而言之,通过实现IActionModelConvention
,您可以更改应用程序模型,并在运行时为操作添加过滤器,路由等。
最好通过一个示例实现来对此进行解释,如下所示。当您想将现有的MVC过滤器与配置动作路由的功能结合在一起时,下面的实现同时实现IResourceFilter
(可以是您使用的任何过滤器类型)和IActionModelConvention
:>
public class VerifyAccessFilterAttribute : Attribute, IActionModelConvention, IResourceFilter
{
public VerifyAccessFilterAttribute(params string[] routeTemplates)
{
RouteTemplates = routeTemplates;
}
public string[] RouteTemplates { get; set; }
public void Apply(ActionModel actionModel)
{
actionModel.Selectors.Clear();
foreach (var routeTemplate in RouteTemplates)
{
actionModel.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel { Template = routeTemplate },
ActionConstraints = { new HttpMethodActionConstraint(new[] { "GET" }) }
});
}
}
public void OnResourceExecuting(ResourceExecutingContext ctx) { ... }
public void OnResourceExecuted(ResourceExecutedContext ctx) { ... }
}
在此示例中,所有内容都与Apply
方法有关,该方法只是为每个routeTemplate
(如我所命名的)添加一个新的SelectorModel
,每个方法都被限制为HTTP GET
请求。
答案 1 :(得分:0)
通常来说,您不能“合并”属性,因为属性不会执行代码。属性只是标记。就像“此方法标记为红色和蓝色”。然后将出现其他代码,一个代码寻找所有红色标记并执行某项操作,另一个代码寻找所有蓝色标记并执行其他操作。通过合并红色和蓝色来构建紫色标记只会混淆寻找标记的代码,因为紫色既不是红色也不是蓝色。
但是,第三方可以使用C#的AOP(面向方面的编程),并且意味着属性(称为方面,因为它们比常规标记属性做得更多)可以执行代码。
您可以编写一个方面,用所需的属性来装饰它所位于的方法,因此您可以编写一次(并对其进行测试),然后可以在每个方法上对其进行设置,而不必担心忘记属性或对其进行设置错误的。
C#有多个AOP提供程序,其中最受欢迎的似乎是PostSharp。您可以看到如何编写在PostSharp here编译时将属性添加到类或方法的方面。