获取操作名称和控制器名称的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);
}
}
挺直的。
但是当我有一个ApiController(System.Web.Http.ApiController
)时,情况就更复杂了:
最终在一些rsharper技巧的帮助下,我能够将它减少到几行。
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;
}
难道不能更轻松吗?问这个的原因是因为目前我正在实施一种确定谁可以开启什么行动的通用方法。有些操作属于WebApi,每次我需要执行上面的“查询”。因此,整个转换过程会耗费一些性能时间。
为什么?
在不详细介绍的情况下,假设您有40个MVC控制器和20个API控制器,每个控制器大约有5-10个动作。所有这些都存储在数据库中(在启动时循环遍历它们),并且可以链接到Identity角色。管理员可以选择某个角色可以执行的操作。收到第一个答案后,我可能不太清楚为什么我想创建一个控制器覆盖,我只想编程一次。
其中一个潜在的解决方案可能是ActionFilterAttribute:
public class ValidateAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var actionName = actionContext.ActionDescriptor.ActionName;
......
base.OnActionExecuting(actionContext);
}
}
然后在你的控制器上:
[ValidateAccess]
public async Task<IHttpActionResult> Stuff()
您甚至可以将参数传递给这些属性并让它们“智能”,例如每个操作都属于某个组,访问验证将基于组而非操作名称。这可能很难维护。
例如
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()
为什么不使用ActionContext和ControllerContext?
public class ValuesController : ApiController
{
[HttpGet]
[AllowAnonymous]
public IHttpActionResult Get()
{
var actionName = this.ActionContext.ActionDescriptor.ActionName;
var controlerName = this.ControllerContext.ControllerDescriptor.ControllerName;
return this.Ok();
}
}