为什么在 ApiController 中获取 ActionName 这么复杂?更简单的方法?

Cul*_*tes 6 c# performance asp.net-web-api

获取操作名称和控制器名称的 MVC 控制器:

public class AuthorizeController : Controller
{

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string actionName = filterContext.ActionDescriptor.ActionName;
        string controllerNamespace = filterContext.ActionDescriptor.ControllerDescriptor.ControllerType.FullName;
        //..more code
        base.OnActionExecuting(filterContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

非常简单。

但是当我有一个 ApiController ( System.Web.Http.ApiController) 时,事情就变得更复杂了:

在此输入图像描述

最终,在一些更清晰的技巧的帮助下,我能够将其减少到“几行”。

private string GetActionName(HttpControllerContext context)
{
    var httpRouteDataCollection = context.RouteData.Values.Values;
    var httpRouteDataCollection2 = httpRouteDataCollection.FirstOrDefault();
    if (!(httpRouteDataCollection2 is IHttpRouteData[] httpRouteData))
    {
        return null;
    }

    IHttpRouteData routeData = httpRouteData.FirstOrDefault();
    var httpActionDescriptorCollection = routeData?.Route.DataTokens["actions"];
    if (!(httpActionDescriptorCollection is HttpActionDescriptor[] httpActionDescriptor))
    {
        return null;
    }
    HttpActionDescriptor reflectedHttpActionDescriptor = httpActionDescriptor.FirstOrDefault();
    return reflectedHttpActionDescriptor?.ActionName;
}
Run Code Online (Sandbox Code Playgroud)

不能更容易完成吗?之所以问这个问题,是因为目前我正在实施一种通用方法来确定谁可以打开哪些操作。有些操作是在 WebApi 中进行的,每次我都需要执行上述“查询”。所以这整个转换过程会消耗一些性能时间。

为什么?

无需赘述,假设您有 40 个 MVC 控制器和 20 个 API 控制器,每个控制器大约有 5-10 个操作。所有这些都存储在数据库中(在启动时循环遍历它们)并且可以链接到身份角色。管理员可以选择特定角色可以执行的操作。收到第一个答案后,我可能不太清楚为什么我想创建一个控制器覆盖,而我只想进行一次编程。

Jle*_*HeP 3

潜在的解决方案之一可能是 ActionFilterAttribute:

public class ValidateAccessAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var actionName = actionContext.ActionDescriptor.ActionName;
        ......
        base.OnActionExecuting(actionContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的控制器上:

    [ValidateAccess]
    public async Task<IHttpActionResult> Stuff()
Run Code Online (Sandbox Code Playgroud)

您甚至可以将参数传递给这些属性并使它们“智能”,例如每个操作都属于某个组,并且访问验证将基于组而不是操作名称。这可能很难维护。

例如

public class ValidateAccessAttribute2 : ActionFilterAttribute
{
    private readonly FunctionalArea _area;

    public ValidateAccessAttribute2(FunctionalArea area)
    {
        _area = area;
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        base.OnActionExecuting(actionContext);
        if (!actionContext.Request.Headers.Contains(AuthorizationHeaders.UserNameHeader))
        {
            actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
            return;
        }
        var userName = actionContext.Request.Headers.GetValues("UserNameHeader").First();
        if (!UserCanAccessArea(userName, _area))
        {
            actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
            return;
        }
    }
}


    [ValidateAccess2(FunctionalArea.AccessToGenericStuff)]
    public async Task<IHttpActionResult> Stuff()
Run Code Online (Sandbox Code Playgroud)