更改过帐值的ActionFilter不会影响模型

时间:2019-02-21 21:20:36

标签: c# asp.net asp.net-mvc

我们正在尝试以“全局”方式清理ASP.NET MVC Web应用程序中发布的字符串条目。在当前的尝试下,我编写了一个自定义操作过滤器,并使用类FormPostSanitizer装饰了一个后操作。这样的想法是,我们将装饰所有应该清理的帖子操作。

该方法成功捕获并清理了输入。但是在将模型保存到数据库之前,不会将这些经过清理的值固定在模型上。

这是装饰控制器的方式。

[HttpPost]
[ValidateAntiForgeryToken]
[FormPostSanitizer]
public ActionResult MyAction(MyViewModel model)
{
    // If ModelState.IsValid, save the model ...
}

这是我的动作过滤器。

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    if (filterContext.HttpContext.Request.HttpMethod != "POST") return;

    FormCollection formCollection = new FormCollection(filterContext.Controller.ControllerContext.HttpContext.Request.Form);
    foreach (string key in formCollection.AllKeys)
    {
        string sanitized = formCollection[key].SanitizeString(); // Extension method to alter the string.
        formCollection.Set(key, sanitized);
    }
    filterContext.ActionParameters["form"] = formCollection;
}

我的期望是最后一行会将更改后的值提交给filterContext,并且模型将具有已清理的值。这些值会被清除,但不会应用到模型中。

如果在已编译的代码中有更好的方法可以在将发布的值绑定到模型之前对其进行拦截和更改,那么请指向显示该方法的帖子。感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您可以为此创建自定义模型活页夹

public class SanitizeModelBinder : DefaultModelBinder
{
    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
    {
        bool sanitize = controllerContext.HttpContext.Request.HttpMethod == "POST";

        //get value from default binder
        object value = base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
        if (!sanitize)
        {
            return value;
        }

        //sanitize value if it is a string
        string stringValue = value as string;
        if (stringValue != null)
        {
            return stringValue.SanitizeString();
        }

        return value;
    }
}

Global.asax.cs中设置默认活页夹,以将其用于所有操作

System.Web.Mvc.ModelBinders.Binders.DefaultBinder = new SanitizeModelBinder();

或者如果您想将此绑定器用于某些型号

public ActionResult MyAction([ModelBinder(typeof(SanitizeModelBinder))]MyViewModel model)

答案 1 :(得分:1)

您必须使用自定义模型联编程序,如上文所述的Alexandar,因为在已绑定模型之后将执行动作过滤器属性,并且此时您无法对其进行更改。 如果您在Model Binder中执行此操作,则它将按您期望的那样应用于