简体   繁体   English

在 ASP.NET Core 2 中创建自定义路由属性

[英]Create custom route attribute in ASP.NET Core 2

We have a bunch of endpoints where we'd like to do the exact same thing for each of them: Register them as a route and verify that the user has access to them.我们有一堆端点,我们希望对它们中的每一个都做完全相同的事情:将它们注册为路由并验证用户是否有权访问它们。 Very condensed our issue can be condensed to us having something like this:非常浓缩我们的问题可以浓缩为我们有这样的事情:

[HttpGet, Route(EntityId.First)]
[HttpGet, Route(EntityId.Second)]
[VerifyAccessFilter(EntityId.First, EntityId.Second)]
public async Task<IActionResult> Endpoint()
{   
    return Ok();
}

But would much rather like something like:但更喜欢类似的东西:

[RouteAndVerify(EntityId.First, EntityId.Second)]
public async Task<IActionResult> Endpoint()
{   
    return Ok();
}

As you can tell this is very simplified, but I hope the intent gets across.如您所知,这非常简化,但我希望意图得到传达。 The hard part seems to be registering the route without using the default Route-attribute.困难的部分似乎是在不使用默认路由属性的情况下注册路由。

You can achieve this with a custom IActionModelConvention implementation.您可以使用自定义IActionModelConvention实现来实现这一点。 The official documentation explains the concept of an action model convention: Work with the application model in ASP.NET Core - Conventions .官方文档解释了操作模型约定的概念: 使用 ASP.NET Core 中的应用程序模型 - 约定 In a nutshell, by implementing IActionModelConvention , you can make changes to the application model and add filters, routes, etc to an action at runtime.简而言之,通过实现IActionModelConvention ,您可以更改应用程序模型并在运行时向操作添加过滤器、路由等。

This is best explained with a sample implementation, which follows below.最好用下面的示例实现来解释这一点。 As you want to combine your existing MVC filter with the ability to configure routes for an action, the implementation below implements both IResourceFilter (this can be whatever filter type you're using) and 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) { ... }
}

In this example, it's all about the Apply method, which simply adds a new SelectorModel for each routeTemplate (as I've named it), each of which is constrained to HTTP GET requests.在这个例子中,都是关于Apply方法的,它只是为每个routeTemplate (正如我所命名的)添加一个新的SelectorModel ,每个routeTemplate都被限制为 HTTP GET请求。

Generally speaking, you cannot "merge" attributes, because attributes do not execute code.一般来说,您不能“合并”属性,因为属性不执行代码。 Attributes are only markers.属性只是标记。 Like "this method is marked red and blue".就像“这个方法被标记为红色和蓝色”。 Then other code will come along, one looking for all red marks and doing something and another looking for all blue marks and doing something else.然后会出现其他代码,一个查找所有红色标记并执行某些操作,另一个查找所有蓝色标记并执行其他操作。 Building a purple mark by merging red and blue is just going to confuse the code looking for the markup, because purple is neither red nor blue.通过合并红色和蓝色来构建紫色标记只会混淆寻找标记的代码,因为紫色既不是红色也不是蓝色。

However, AOP (aspect oriented programming) is available from third parties for C# and means attributes (called aspects because they do more than the normal marker attributes) can execute code.但是,AOP(面向方面​​的编程)可从 C# 的第三方获得,这意味着属性(称为方面,因为它们比普通标记属性做得更多)可以执行代码。

You could write an aspect that decorates the method it's sitting on with the attributes you need, so you can write it once (and test it) and then you can set it on every method without worrying about forgetting an attribute or setting it wrong.您可以编写一个方面,用您需要的属性装饰它所在的方法,因此您可以编写一次(并测试它),然后您可以在每个方法上设置它,而不必担心忘记属性或设置错误。

There are multiple AOP providers for C#, the most popular one seems to be PostSharp. C# 有多个 AOP 提供程序,最流行的一个似乎是 PostSharp。 You can see how write an aspect that adds attributes to a class or method at compile time with PostSharp here .您可以在此处了解如何使用 PostSharp 编写在编译时向类或方法添加属性的方面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM