校验

asp.net mvc 的校验也分为服务端校验及客户端校验两种。
asp.net mvc中的内置提供的服务端校验框架中,实现一个校验要处理三个地方:
执行校验;显示校验信息;指明被校验位置:
执行校验,执行校验来自于两个地方:Model binder及手工校验。手工校验的例:
// Validation logic
if (productToCreate.Name.Trim().Length == 0)
    ModelState.AddModelError("Name", "Name is required.");
AddModelError的第一个参数是校验的对象的ID,第二个参数是要在视图中显示的文字信息。
 
显示校验信息,例:
<%= Html.ValidationSummary() %>

在视图中,若有校验不通过,将会在调用 ValidateionSummary的地方显示文字信息。

 

指明被校验位置,:

<p>
    <label for="Name">Name:</label>
    <%= Html.TextBox("Name") %>
    <%= Html.ValidationMessage("Name", "*") %>
</p>

在调用 Validationessage的地方,会显示校验指示信息,第一个参数是要显示出错信息的ID,第二个参数是指示信息。

当一个校验被匹配时,形如以下http://static.asp.net/asp.net/images/mvc/33/CS/image005.png

红色点号开头的四条信息就是调用ValidationSummary()的地方。

每个* 就是校验指示信息。

If you want to customize the appearance of these prebinding error messages then you need to create resource strings for these messages

如何创建资源字符串?

-----

校验不应在Controller中校验,那如何校验呢?在哪里校验吗?

在Model中实现IDataErrorInfo, 让Model binder自动校验:

这个接口,在System.ComponentModel命名空间中,从.net 1.0以来就有了,它的结构非常简单:

public interface IDataErrorInfo
    {
        string this[string columnName] { get; }
 
        string Error { get; }
    }
 

我们只需要实现一个字符串索引器和一个Error只读属性,即可。

举例:

using System.Collections.Generic;
using System.ComponentModel;
 
namespace MvcApplication1.Models
{
 
    public partial class Movie : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();
 
        partial void OnTitleChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Title", "标题必填.");
        }
        
        
        partial void OnDirectorChanging(string value)
        {
            if (value.Trim().Length == 0)
                _errors.Add("Director", "导演必填.");
        }
 
 
        #region IDataErrorInfo Members
 
        public string Error
        {
            get
            {
                return string.Empty;
            }
        }
 
        public string this[string columnName]
        {
            get
            {
                if (_errors.ContainsKey(columnName))
                    return _errors[columnName];
                return string.Empty;
            }
        }
 
        #endregion
    }
}

然后在Controller中这样:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Movie movieToCreate)
{
    // Validate
    if (!ModelState.IsValid)
        return View();
 
    // Add to database
    try
    {
        _db.AddToMovieSet(movieToCreate);
        _db.SaveChanges();
 
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

在IsValid时,Controller就会察看 IDataErrorInfo,确定校验能不能通过。

这样就把具体判断逻辑脱离Controller了.

但是这里,还有一个问题,我们的这个方案是依赖于ASP.NET MVC的验证机制的,我没办法把业务层移植到别的应用场景中(如WPF)中去,怎么办呢?

一种办法是创建一个Service层,Service层后面隐藏了我们所有的验证逻辑及业务逻辑,让Service层和Controller打交道,Service层再和业务层。

如何和ASP.NET MVC的验证机制沟通呢?反过来想,我可以为我们的业务层创建接口层,也可以为我们的验证机制创建接口层,把验证接口暴露出来。我们通过前面的代码可以知道,ASP.NET MVC的验证机制是放在ModelState中的,那么可以反客为主,利用Facade模式,创建一个包装类,把ModelState包起來,藏在后面,形成一个我们适合于我们的验证接口用的新外观即可。

用这种方式,如有新的变化出现的话,我们只要更改包装类即可。

具体如下:

业务层

   1: using System.Collections.Generic;
   2:  
   3: namespace MvcApplication1.Models
   4: {
   5:     public class ProductService : IProductService
   6:     {
   7:         private IValidationDictionary _validatonDictionary;
   8:         private IProductRepository _repository;
   9:  
  10:         public ProductService(IValidationDictionary validationDictionary, IProductRepository repository)
  11:         {
  12:             _validatonDictionary = validationDictionary;
  13:             _repository = repository;
  14:         }
  15:  
  16:         protected bool ValidateProduct(Product productToValidate)
  17:         {
  18:             if (productToValidate.Name.Trim().Length == 0)
  19:                 _validatonDictionary.AddError("Name", "Name is required.");
  20:             if (productToValidate.Description.Trim().Length == 0)
  21:                 _validatonDictionary.AddError("Description", "Description is required.");
  22:             if (productToValidate.UnitsInStock < 0)
  23:                 _validatonDictionary.AddError("UnitsInStock", "Units in stock cannot be less than zero.");
  24:             return _validatonDictionary.IsValid;
  25:         }
  26:  
  27:         public IEnumerable<Product> ListProducts()
  28:         {
  29:             return _repository.ListProducts();
  30:         }
  31:  
  32:         public bool CreateProduct(Product productToCreate)
  33:         {
  34:             // Validation logic
  35:             if (!ValidateProduct(productToCreate))
  36:                 return false;
  37:  
  38:             // Database logic
  39:             try
  40:             {
  41:                 _repository.CreateProduct(productToCreate);
  42:             }
  43:             catch
  44:             {
  45:                 return false;
  46:             }
  47:             return true;
  48:         }
  49:     }
  50:  
  51:     public interface IProductService
  52:     {
  53:         bool CreateProduct(Product productToCreate);
  54:         System.Collections.Generic.IEnumerable<Product> ListProducts();
  55:     }
  56: }

验证接口

   1: namespace MvcApplication1.Models
   2: {
   3:     public interface IValidationDictionary
   4:     {
   5:         void AddError(string key, string errorMessage);
   6:         bool IsValid { get; }
   7:     }
   8: }

验证机制的包装器

   1: using System.Web.Mvc;
   2:  
   3: namespace MvcApplication1.Models
   4: {
   5:     public class ModelStateWrapper : IValidationDictionary
   6:     {
   7:         private ModelStateDictionary _modelState;
   8:  
   9:         public ModelStateWrapper(ModelStateDictionary modelState)
  10:         {
  11:             _modelState = modelState;
  12:         }
  13:  
  14:  
  15:         #region IValidationDictionary Members
  16:  
  17:         public void AddError(string key, string errorMessage)
  18:         {
  19:             _modelState.AddModelError(key, errorMessage);
  20:         }
  21:  
  22:         public bool IsValid
  23:         {
  24:             get { return _modelState.IsValid; }
  25:         }
  26:         #endregion
  27:     }
  28: }

最终的Controller

   1: using System.Web.Mvc;
   2: using MvcApplication1.Models;
   3:  
   4: namespace MvcApplication1.Controllers
   5: {
   6:     public class ProductController : Controller
   7:     {
   8:         private IProductService _service;
   9:  
  10:         public ProductController() 
  11:         {
  12:             _service = new ProductService(new ModelStateWrapper(this.ModelState), new ProductRepository());
  13:         }
  14:  
  15:         public ProductController(IProductService service)
  16:         {
  17:             _service = service;
  18:         }
  19:  
  20:  
  21:         public ActionResult Index()
  22:         {
  23:             return View(_service.ListProducts());
  24:         }
  25:  
  26:  
  27:         //
  28:         // GET: /Product/Create
  29:  
  30:         public ActionResult Create()
  31:         {
  32:             return View();
  33:         }
  34:  
  35:         //
  36:         // POST: /Product/Create
  37:  
  38:         [AcceptVerbs(HttpVerbs.Post)]
  39:         public ActionResult Create([Bind(Exclude = "Id")] Product productToCreate)
  40:         {
  41:             if (!_service.CreateProduct(productToCreate))
  42:                 return View();
  43:             return RedirectToAction("Index");
  44:         }
  45:     }
  46: }

就这样,我们通过一层层解耦,把业务层和验证机制独立出来,使之可以广泛应用于其它各种场合。

还有一些其它的方法,有些验证方法是使用标签来验证的,甚至ASP.NET MVC团队就创建了一个验证框架,用标签来验证的,只是不提供官方的技术支持.地址在http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24471

介绍使用方法的教程:
http://www.asp.net/learn/mvc/tutorial-39-cs.aspx

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值