ASP.NET MVC 3:您是否可以创建一个ActionFilter来访问请求参数,然后修改它们以适合Action Method签名

时间:2012-03-20 16:01:39

标签: asp.net-mvc-3

我正在尝试将一些安全性/验证日志记录添加到我正在处理的ASP.NET MVC 3应用程序中。我想做的是使用类似于此的Action过滤器来装饰我的一些Action方法:

public class RegexValidateAttribute : ActionFilterAttribute
{
    private static readonly ILog logger =
        LogManager.GetLogger( typeof( RegexValidateAttribute ).FullName );

    public string ParameterName { get; set; }
    public string Expression { get; set; }

    public override void OnActionExecuting( ActionExecutingContext filterContext )
    {
        string parameterValue = Convert.ToString(
            filterContext.ActionParameters[ ParameterName ] );
        if ( parameterValue != null )
        {
            if ( !Regex.IsMatch( parameterValue, Expression ) )
            {
                logger.Error( "INPUT_VALIDATION_EXCEPTION [ Parameter "
                              + ParameterName + " did not match the regex: '"
                              + parameterValue + "' :: '" + Expression + "']" );
            }
        }
    }
}

我的控制器的定义与此相似:

public class MyController : Controller
{        
    [RegexValidate( ParameterName = "id", Expression = @"^\d+$" )]
    public PartialViewResult MyMethod( int id = 0 )
    {
        <Action Proccessing>
    }
}

我遇到的“问题”是因为action方法的输入参数定义为int,如果有人传入非数字值,则参数值在此过程中更改为0确定选择哪种动作方法。当然,这是在我的ActionFilter有机会执行之前发生的,因此我没有机会记录原始的无效值。

我知道这可以通过更改要定义为string的参数来解决,但这需要我重新编写大量代码,然后将转换逻辑添加到action方法以进行转换字符串到int。

那么,有没有办法在ActionFilter中获取原始值而不是修改后的值,或者在修改值之前执行ActionFilter?

更新: 根据@ Darin关于使用AuthorizationFilter的建议,我能够使用类似于以下内容的代码实现我的目标:

public class RegexValidateAttribute : AuthorizeAttribute
{
    private static readonly ILog logger =
        LogManager.GetLogger( typeof( RegexValidateAttribute ).FullName );

    public string ParameterName { get; set; }
    public string Expression { get; set; }
    public string ReplacementValue { get; set; }

    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        string parameterValue = Convert.ToString(
            filterContext.RouteData.Values[ ParameterName ] );
        if ( parameterValue != null )
        {
            if ( !Regex.IsMatch( parameterValue, Expression ) )
            {
                logger.Error( "INPUT_VALIDATION_EXCEPTION [ Parameter "
                               + ParameterName + " did not match the regex: '"
                               + parameterValue + "' :: '" + Expression + "']" );
                filterContext.RouteData.Values[ ParameterName ] = ReplacementValue;
            }
        }
    }
}

1 个答案:

答案 0 :(得分:5)

当您从ActionFilterAttribute派生时,模型绑定器会在 OnActionExecuting方法之前运行。当模型绑定器运行时,它会崩溃。如果您希望方法在模型绑定器之前运行,则应实现IAuthorizationFilter 接口或派生自已实现该接口的AuthorizeAttribute

另一种可能性是为路由添加约束,以便在id不是数字时不调用控制器操作:

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { id = @"^\d+$" }
);