ASP.NET MVC 入门8、ModelState与数据验证

ViewData有一个ModelState的属性,这是一个类型为ModelStateDictionary的ModelState类型的字典集合。在进行数据验证的时候这个属性是比较有用的。在使用Html.ValidationMessage()的时候,就是从ViewData.ModelState中检测是否有指定的KEY,如果存在,就提示错误信息。例如在前一篇文章ASP.NET MVC 入门7、Hellper与数据的提交与绑定中使用到的UpdateModel方法:

image

我们在View中使用Html.ValidationMessage(string modelName)来对指定的属性进行验证:

image

Html.ValidationMessage()有几个重载:

image

其中ValidationSummary()是用于显示全部的验证信息的。跟ASP.NET里面的ValidationSummary验证控件差不多。

我们测试一下/Admin/Setting页面:

image

在用UpdateModel方法更新BlogSettings.Instance.PostsPerPage的时候,当我们如图所示填写"10d"的时候,由于PostsPerPage为整型的,所以UpdateModel方法就会出错,同时会往ViewData.ModelState添加相应的错误信息,从而Html.ValidationMessage()方法就可以从ViewData.ModelState中检测到错误并提示。同时Html.ValidationMessage()方法会为出错的属性的输入框添加一个名为"input-validation-error"的CSS类,同时后面的提示信息的CSS类名为"field-validation-error":

image

CSS类的样式是可以由我们自己自由定义的。如上图的红色高亮显示。

好,下面我们来实现发表新随笔的功能。我们先写一个提供用户输入随笔内容的表单页面:

复制代码
<p>
    <label for="Title">标题</label>
    <%=Html.TextBox("Title"new { id = "Title", @class = "required" })%>
    <%=Html.ValidationMessage("Title")%>
</p>
<p>
    <label for="Content">内容</label>
    <%=Html.TextArea("Content")%>
    <%=Html.ValidationMessage("Content")%>
</p>
<p>
    <label for="Slug">URL地址别名(如果为空则和标题同名)</label>
    <%=Html.TextBox("Slug"new { id = "Slug", @class = "required" })%>
    <%=Html.ValidationMessage("Slug")%>
</p> 
复制代码

 

然后我们对用户提交过来的数据进行保存:

复制代码
[AcceptVerbs("POST"), ActionName("NewPost")]
public ActionResult SaveNewPost(FormCollection form)
{
    Post post 
= new Post(); 

    
try
    {
        UpdateModel(post, 
new[] { "Title""Content""Slug" });
    }
    
catch
    {
        
return View(post);
    } 

    post.Save();
    
return ShowMsg(new List<string>() { "发表新随笔成功" });
}
复制代码

 

由于这三个值都是字符串类型,所以如果值为空的话,UpdateModel也是不会出错的,而我们的Title和Content是不允许为空的,或者我们想我们的Slug的长度不能超过100,也就是需要有我们自己的业务规则。这时候我们或许会这样写:

复制代码
try
{
    UpdateModel(post, 
new[] { "Title""Content""Slug" });
}

catch
{
    
return View(post);


if (string.IsNullOrEmpty(post.Title))
{
    ViewData.ModelState.AddModelError(
"Title", post.Title, "标题不能为空");
}

if (string.IsNullOrEmpty(post.Content))
{
    ViewData.ModelState.AddModelError(
"Content", post.Content, "内容不能为空");


if (!ViewData.ModelState.IsValid)
{
    
return View(post);
}
复制代码

 

ViewData.ModelState提供了一个AddModelError的方法,方便我们添加验证失败的信息。我们可以如上代码这样进行对象的业务规则验证,但是一旦业务规则多了,这样的代码是非常壮观的,而且不好控制。那么我们该怎么更好的进行业务规则的验证呢?得意于BlogEngine.Net的良好架构,我们可以很轻松的完成这一点。

首先,让我们修改一下BlogEngine.Core里面BusinessBase的代码。我们前面说过,BusinessBase实现了IDataErrorInfo接口,该接口有个索引器,导致ViewData.Eval()方法调用时搜索索引器的值时返回String.Empty而使ViewData.Eval()认为是找到值了,从而失效。

image

我们可以将return string.Empty修改为return null。但我们这里并不需要用到这个接口,所以我们把该接口去掉,并把相应的代码注释了。然后我们再暴露一个BrokenRules的属性,用于返回当前的所有破坏性业务规则(红框部分代码为我们添加的):

image

BusinessBase提供了一个抽象的ValidationRules方法,用于在业务类重写这个方法往里面添加验证规则(具体请看BusinessBase的Validation节)。


#region Validation 

private StringDictionary _BrokenRules = new StringDictionary();
/// <summary>
/// 获取所有的破坏性规则。
/// 在获取前请用IsValid进行判断。
/// </summary>
public StringDictionary BrokenRules
{
    
get
    {
        
return _BrokenRules;
    }

} 

/// <summary>
/// Add or remove a broken rule.
/// </summary>
/// <param name="propertyName">The name of the property.</param>
/// <param name="errorMessage">The description of the error</param>
/// <param name="isBroken">True if the validation rule is broken.</param>
protected virtual void AddRule(string propertyName, string errorMessage, bool isBroken)
{
    
if (isBroken)
    
{
        _BrokenRules[propertyName] 
= errorMessage;
    }

    else
    {
        
if (_BrokenRules.ContainsKey(propertyName))
        
{
            _BrokenRules.Remove(propertyName);
        }

    }
} 

/// <summary>
/// Reinforces the business rules by adding additional rules to the 
/// broken rules collection.
/// </summary>
protected abstract void ValidationRules(); 

/// <summary>
/// Gets whether the object is valid or not.
/// </summary>
public bool IsValid
{
    
get
    {
        ValidationRules();
        
return this._BrokenRules.Count == 0;
    }

} 

/// /// <summary>
/// If the object has broken business rules, use this property to get access
/// to the different validation messages.
/// </summary>
public virtual string ValidationMessage
{
    
get
    {
        
if (!IsValid)
        
{
            StringBuilder sb 
= new StringBuilder();
            
foreach (string messages in this._BrokenRules.Values)
            
{
                sb.AppendLine(messages);
            }
 

            
return sb.ToString();
        }
 

        
return string.Empty;
    }

} 

#endregion 

 

我们在Post类中重写这个方法来添加验证规则:

image

然后我们可以在Controller的Action中很优雅的书写我们的代码来进行业务规则的验证:

复制代码
[AcceptVerbs("POST"), ActionName("NewPost")]
public ActionResult SaveNewPost(FormCollection form)
{
    Post post 
= new Post(); 

    
try
    {
        UpdateModel(post, 
new[] { "Title""Content""Slug" });
    }
    
catch
    {
        
return View(post);
    } 

    
if (!post.IsValid)
    {
        
foreach (string key in post.BrokenRules.Keys)
        {
            ViewData.ModelState.AddModelError(key, form[key], post.BrokenRules[key]);
        }
        
return View(post);
    } 

    post.Save();
    
return ShowMsg(new List<string>() { "发表新随笔成功" });
}
复制代码

 

我们注意到上面的Action中用到了一个FormCollection 的参数,这个参数系统会自动将Form提交过来的全部表单值(Request.Form)赋给它的。客户端验证可以用jQuery的验证插件来,这里就不罗嗦了。

暂时就写这么多吧,想到什么再补充。Enjoy!Post by Q.Lee.lulu。

本文的Blog程序示例代码: 4mvcBlog_8.rar

---------------------------------------------------------------------

更多内容,请关注http://blog.51mvc.com/ 和 http://bbs.51mvc.com/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438203.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET MVC 入门9、Action Filter 与 内置的Filter实现(介绍)

本系列文章基于ASP.NET MVC Preview5. 有时候你想在调用action方法之前或者action方法之后处理一些逻辑&#xff0c;为了支持这个&#xff0c;ASP.NET MVC允许你创建action过滤器。Action过滤器是自定义的Attributes&#xff0c;用来标记添加Action方法之前或者Action方法之后…

ASP.NET MVC 入门10、Action Filter 与 内置的Filter实现(实例-防盗链)

本系列文章基于ASP.NET MVC Preview5. 前一篇中我们已经了解了Action Filter 与 内置的Filter实现&#xff0c;现在我们就来写一个实例。就写一个防盗链的Filter吧。 首先继承自FilterAttribute类同时实现IActionFilter接口&#xff0c;代码如下&#xff1a; /// <summary…

base64原理及其编解码的python实现

base64原理及其编解码的python实现base64base64简介base64编码表base64编码原理base64编解码的python实现其他base编码base16base32base36、base58、 base62、 base85、base91、 base92base64 base64简介 base64是一种基于64个可打印字符来表示二进制数据的表示方法。2664&am…

REVERSE-PRACTICE-JarvisOJ-1

REVERSE-PRACTICE-JarvisOJ-1[61dctf]androideasy[61dctf]stheasyDD - Android NormalDD - Android Easy[61dctf]androideasy apk文件&#xff0c;用jadx-gui打开 主要的逻辑为&#xff0c;获取输入&#xff0c;检验输入的长度&#xff0c;输入异或23后与已知数组比较&#xf…

NuGet学习笔记(1) 初识NuGet及快速安装使用

关于NuGet园子里已经有不少介绍及使用经验&#xff0c;本文仅作为自己研究学习NuGet一个记录。 初次认识NuGet是在去年把项目升级为MVC3的时候&#xff0c;当时看到工具菜单多一项Library Package Manager&#xff0c;右键项目文件多了一项Manage Nuget Packages...&#xff0c…

NuGet学习笔记(2) 使用图形化界面打包自己的类库

上文NuGet学习笔记(1) 初识NuGet及快速安装使用说到NuGet相对于我们最重要的功能是能够搭建自己的NuGet服务器&#xff0c;实现公司内部类库的轻松共享更新。在安装好NuGet扩展后&#xff0c;我们已经能够通过NuGet轻松下载自己需要的类库&#xff0c;下面来说一说如何将自己的…

REVERSE-PRACTICE-JarvisOJ-2

REVERSE-PRACTICE-JarvisOJ-2DD - HelloAPK_500DebugMeFindPassDD - Hello macos文件&#xff0c;无壳&#xff0c;ida分析 start函数和sub_100000C90函数没什么作用 主要的逻辑在sub_100000CE0函数&#xff0c;反调试检测和byte_100001040数组的循环变换&#xff0c;最后打印…

NuGet学习笔记(3) 搭建属于自己的NuGet服务器

文章导读 创建NuGetServer Web站点 发布站点到IIS 添加本地站点到包包数据源 在上一篇NuGet学习笔记(2) 使用图形化界面打包自己的类库 中讲解了如何打包自己的类库&#xff0c;接下来进行最重要的一步&#xff0c;从零开始搭建属于自己的NuGet服务器&#xff0c;诚然园子里…

REVERSE-PRACTICE-JarvisOJ-3

REVERSE-PRACTICE-JarvisOJ-3爬楼梯软件密码破解-1Classical CrackMe2Smali爬楼梯 apk文件&#xff0c;放到模拟器里运行一下 “爬一层楼”按钮可按&#xff0c;每按一下&#xff0c;“已爬的楼层”加1层 “爬到了&#xff0c;看FLAG”按钮不可按&#xff0c;应该是“已爬的楼…

管理全局包、缓存和临时文件夹

每当安装、更新或还原包时&#xff0c;NuGet 将管理项目结构多个文件夹之外的包和包信息&#xff1a; name说明和位置&#xff08;每个用户&#xff09;global‑packagesglobal-packages 文件夹是 NuGet 安装任何下载包的位置。 每个包完全展开到匹配包标识符和版本号的子文件…

REVERSE-PRACTICE-JarvisOJ-4

REVERSE-PRACTICE-JarvisOJ-4Classical CrackmeFindKeyClassical Crackme exe程序&#xff0c;输入注册码&#xff0c;输入错误弹窗 查壳发现是.Net程序&#xff0c;dnSpy打开&#xff08;要不要用de4dot unpack无所谓&#xff0c;这里打开的是解包过的程序&#xff09; 按下“…

在解决方案中所使用 NuGet 管理软件包依赖

使用程序包恢复功能可以在提交源代码时, 不需要将 packages 中的程序集文件提交到源代码管理中&#xff0c;大幅减少项目的尺寸。所有NuGet程序包都存储在解决方案的Packages文件夹中。 要启用程序包恢复功能&#xff0c;可右键单击解决方案&#xff08;注意&#xff0c;不是右…

REVERSE-PRACTICE-BUUCTF-1

REVERSE-PRACTICE-BUUCTF-1easyrereverse1reverse2内涵的软件easyre exe程序&#xff0c;无壳&#xff0c;ida分析 左侧函数窗找到main函数&#xff0c;flag提交即可 reverse1 exe程序&#xff0c;运行后提示输入flag&#xff0c;ida分析 左侧函数窗无明显的main函数&#…

REVERSE-PRACTICE-BUUCTF-2

REVERSE-PRACTICE-BUUCTF-2新年快乐[BJDCTF 2nd]guessgamehellowordxor新年快乐 exe程序&#xff0c;运行后提示输入正确的flag&#xff0c;有upx壳&#xff0c;常规工具脱壳即可 ida分析&#xff0c;左侧函数窗找到main函数&#xff0c;F5反汇编&#xff0c;简单的输入比较逻…

REVERSE-PRACTICE-BUUCTF-3

REVERSE-PRACTICE-BUUCTF-3reverse3不一样的flagSimpleRevJava逆向解密reverse3 exe程序&#xff0c;无壳&#xff0c;用ida分析 左侧函数窗最后找到main函数&#xff0c;F5反汇编 先base64&#xff0c;然后顺序加上对应的下标&#xff0c;最后比较&#xff0c;写逆脚本即可得…

console对象的方法log、info、warn、error的区别及几个实用的方法

先说一下console&#xff0c;JavaScript 原生中默认是没有 Console 对象&#xff0c;这是某些浏览器提供的内置对象。 在不同的浏览器里显示可能不同 下面的运行截图中&#xff0c;图中的灰色是运行的这句&#xff0c;灰色下面是此句运行的结果 log()、info()、warn()、error()…

认识ASP.NET 5项目结构和项目文件xproj

ASP.NET 5 在项目结构上做了很大的改变&#xff0c;我们以前熟悉的目录结构与项目文件内容都不太一样了&#xff0c;本篇文章带大家了解 ASP.NET 5 到底跟以前有哪些不一样的地方。 我们先用 Visual Studio 2015 建立一个全新的 ASP.NET 5 网站项目&#xff0c;打开VS2015&…

REVERSE-PRACTICE-BUUCTF-4

REVERSE-PRACTICE-BUUCTF-4刮开有奖[BJDCTF 2nd]8086[GKCTF2020]Check_1n[GXYCTF2019]luck_guy刮开有奖 exe文件&#xff0c;运行后无任何提示&#xff0c;无壳&#xff0c;用ida分析 WinMain->DialogBoxParamA->DialogFunc DialogBoxParamA函数&#xff1a; DialogFun…

REVERSE-PRACTICE-BUUCTF-5

REVERSE-PRACTICE-BUUCTF-5findit简单注册器[GWCTF 2019]pyre[BJDCTF2020]JustREfindit apk文件&#xff0c;直接上jadx-gui分析 验证输入的逻辑比较简单&#xff0c;写脚本即可 安装这个apk&#xff0c;将字符串输入即可得到flag&#xff0c;当然也可以直接写输出flag的脚本…

REVERSE-PRACTICE-BUUCTF-6

REVERSE-PRACTICE-BUUCTF-6rsaCrackRTF[2019红帽杯]easyRE[ACTF新生赛2020]easyrersa 解压出来是.enc和.key两个文件&#xff0c;.enc是密文&#xff0c;.key存放着公钥信息 使用在线网站或者openssl解析.key文件中存放着的公钥信息 可获知rsa需要的模数n和公钥e 使用在线网站…