mvc中使用一个action对多个不同名字段做remote验证

MVC中可以在model的属性上使用Remote这个attribute来生成客户端的远程验证

[Remote("ForbiddenWord", "RemoteValidation")]
public string Title { get; set; }

比如这样,当客户端触发验证事件时,会访问Remotevalidation/ForbiddenWord这个controller/action,他传递参数(文本框中填写的值)使用的参数名就是这个文本框的name属性,如果是通过Html.EditorFor生成的,自然就是这个model中的属性名。

默认的参数名是由jquery.validate生成的。

假设我们现在的action是这样的形式

public ActionResult ForbiddenWord(string title)
这样没问题,通过title参数,就可以获取到传来值,然后在action中对此值做具体验证
在model中还有另外一个属性,也需要做同样的验证,如
[Remote("ForbiddenWord", "RemoteValidation")]
public string Body { get; set; }

他生成的验证地址是RemoteValidation/ForbiddenWord?Body=???这样的url形式,action中title参数是获取不到值的。

我不知道有没有什么办法用routes来解决这种问题,我是通过filter来解决的。

 

如果说AdditionalFields能解决同一个model的问题,那对不同model,model中属性不同名的情况AdditionalFields就不行了

既然url的参数与action的参数名对应不上,我们写action的时候就不管他了,随便起个名就OK,如

public ActionResult ForbiddenWord(string word)

 

同样,model中若干字段都需要做同样的验证,如

[Remote("ForbiddenWord", "RemoteValidation")]
public string Title { get; set; }
[Remote("ForbiddenWord", "RemoteValidation")]
public string Body { get; set; }
[Remote("ForbiddenWord", "RemoteValidation")]
public string Intro { get; set; }

 

我们需要把url实际的参数,如title,body,intro的值,赋给action的参数word

在action上加一个filter,OnActionExecuting中做这部分工作

 

[RemoteValidationActionParamFix("word", "body", "title", "intro")]
public ActionResult ForbiddenWord(string word)

filter的参数:第一个为action要fix的参数名,后面为连接可能使用的具体名称

以下是filter的全部代码

  1: public class RemoteValidationActionParamFixAttribute : ActionFilterAttribute
  2: {
  3:     string paramName;
  4:     string[] toFix;
  5:     
  6:     public RemoteValidationActionParamFixAttribute(string paramname, params string[] tofix)
  7:     {
  8:         paramName = paramname;
  9:         toFix = tofix;
 10:     }
 11: 
 12:     public override void OnActionExecuting(ActionExecutingContext filterContext)
 13:     {
 14:         if (toFix == null || toFix.Length < 1)
 15:         {
 16:             return;
 17:         }
 18:         foreach (string str in toFix)
 19:         {
 20:             try
 21:             {
 22:                 filterContext.ActionParameters[paramName] = filterContext.Controller.ValueProvider.GetValue(str).AttemptedValue;
 23:                 break;
 24:             }
 25:             catch
 26:             {
 27:                 continue;
 28:             }
 29:         }
 30:     }
 31: }

image

image

虽然url传递使用了不同的参数名,但都验证成功了。

在若干model中对不同名的属性做同样的验证,也可行。

更进一步,对可能使用到的参数名,不写在attribute构造里,而通过一个配置文件设置,这样可以避免修改代码。

 

如果不使用filter,使用modelbinder也可以实现同样的效果

使用modelbinder还可以在提交时对整个表单做统一验证,而不是ajax对每个字段验证。这样可以减少客户端与服务器端之间的数据传输。不过就是要post之后错误才能显示出来,具体使用什么看情况而定。

posted @ 2011-11-10 17:36  czcz1024  阅读(790)  评论(0编辑  收藏  举报