You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#动态调用方法时,如何触发其关联的AppAuthorize特性?

如何在反射调用Action时触发自定义授权特性逻辑

嘿,我完全懂你的困扰——直接用反射调用StolenCar方法时,AppAuthorize特性里的授权逻辑根本不会自动执行对吧?这是因为ASP.NET MVC的过滤器(比如授权特性)是由框架的请求处理管道触发的,单纯的反射调用只会执行方法本身,不会触发附加的特性逻辑。不过咱们有两种靠谱的方法来解决这个问题:

方案一:手动获取并执行特性的授权逻辑

这种方法直接提取方法上的AppAuthorize特性,手动构造所需的上下文,然后触发它的授权逻辑,判断通过后再调用目标方法。

步骤代码示例:

Type magicType = Type.GetType(controllerFullName);
MethodInfo magicMethod = magicType.GetMethod(actionName);
ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
object magicClassObject = magicConstructor.Invoke(new object[] { });

// 1. 获取方法上的所有AppAuthorize特性
var authorizeAttributes = magicMethod.GetCustomAttributes<AppAuthorize>(inherit: true);

// 2. 模拟ControllerContext(根据你的场景调整,比如在Web环境下可以用当前HttpContext)
Controller controller = magicClassObject as Controller;
HttpContextBase httpContext = new HttpContextWrapper(HttpContext.Current); // 非Web环境需模拟
RouteData routeData = new RouteData();
routeData.Values["controller"] = magicType.Name.Replace("Controller", string.Empty);
routeData.Values["action"] = actionName;
ControllerContext controllerContext = new ControllerContext(httpContext, routeData, controller);

// 3. 构造授权上下文并执行特性逻辑
AuthorizationContext authorizationContext = new AuthorizationContext(controllerContext);
bool isAuthorized = true;

foreach (var authAttr in authorizeAttributes)
{
    authAttr.HandleUnauthorizedRequest(authorizationContext);
    // 如果特性已经设置了Result(比如重定向到登录页),说明未授权
    if (authorizationContext.Result != null)
    {
        isAuthorized = false;
        break;
    }
}

// 4. 根据授权结果决定是否调用目标方法
if (isAuthorized)
{
    var result = magicMethod.Invoke(magicClassObject, new object[] { parameters }) as ActionResult;
    return result;
}
else
{
    // 返回特性处理后的未授权结果
    return authorizationContext.Result;
}

方案二:利用MVC的ControllerActionInvoker执行Action

这种方法更贴近真实的MVC请求流程,ControllerActionInvoker会自动触发所有注册的过滤器(包括你的AppAuthorize特性),不需要手动处理特性调用。

步骤代码示例:

Type magicType = Type.GetType(controllerFullName);
ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
Controller controller = magicConstructor.Invoke(new object[] { }) as Controller;

if (controller == null)
{
    throw new InvalidOperationException("目标类型不是MVC Controller");
}

// 1. 构造ControllerContext
HttpContextBase httpContext = new HttpContextWrapper(HttpContext.Current); // 非Web环境需模拟
RouteData routeData = new RouteData();
routeData.Values["controller"] = magicType.Name.Replace("Controller", string.Empty);
routeData.Values["action"] = actionName;
controller.ControllerContext = new ControllerContext(httpContext, routeData, controller);

// 2. 创建ActionInvoker并执行Action
ControllerActionInvoker actionInvoker = new ControllerActionInvoker();
// 映射参数到Action的参数名(如果有多个参数需要逐个映射)
var parametersDict = new Dictionary<string, object>();
var paramInfo = magicType.GetMethod(actionName).GetParameters()[0];
parametersDict[paramInfo.Name] = parameters;

// 执行Action,自动触发所有过滤器逻辑
bool actionExecuted = actionInvoker.InvokeAction(controller.ControllerContext, actionName, parametersDict);

// 返回执行结果
return controller.ControllerContext.Result as ActionResult;

注意事项

  • 如果是在非Web环境(比如控制台程序、单元测试)调用,你需要用Moq等工具模拟HttpContextBase、HttpRequestBase等对象,确保SecurityContext.Current和配置项能正常获取。
  • 如果你有多个AppAuthorize特性(因为你的特性设置了AllowMultiple = true),要确保所有特性的逻辑都被执行。
  • 方案二的优势是能自动触发所有类型的过滤器(比如ActionFilter、ResultFilter),如果你的Controller还有其他特性,这种方法会更全面。

内容的提问来源于stack exchange,提问作者Anik Saha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:21:14