zoukankan      html  css  js  c++  java
  • 稳扎稳打Silverlight(59) 4.0通信之WCF RIA Services: 数据验证

    [索引页]
    [源码下载]


    稳扎稳打Silverlight(59) - 4.0通信之WCF RIA Services: 数据验证



    作者:webabcd


    介绍
    Silverlight 4.0 之 WCF RIA Services:数据验证


    在线DEMO
    http://www.cnblogs.com/webabcd/archive/2010/08/09/1795417.html


    示例
    演示在 WCF RIA Services 框架中实现数据验证的各种方法
    1、服务端
    MyDomainService.cs

    代码
    /*
     * 一个 Domain Service 服务
     
    */

    namespace Silverlight40.Web.Service
    {
        
    using System;
        
    using System.Collections.Generic;
        
    using System.ComponentModel;
        
    using System.ComponentModel.DataAnnotations;
        
    using System.Data;
        
    using System.Linq;
        
    using System.ServiceModel.DomainServices.EntityFramework;
        
    using System.ServiceModel.DomainServices.Hosting;
        
    using System.ServiceModel.DomainServices.Server;
        
    using Silverlight40.Web.Model;

        
    /*
         * 用 LinqToEntities 实现 Domain Service 则继承 LinqToSqlDomainService<NorthwindEntities>;用 LinqToSql 实现 Domain Service 则继承 LinqToSqlDomainService<NorthwindEntities>
         * Domain Service 内所有对客户端可见的方法都应该是 public 的,Domain Service 内的方法不支持重载
         * 对客户端可见的方法要满足命名约定,或为其指定对应的 Attribute。当前支持 6 种数据操作:Query, Update, Insert, Delete, Invoke, Named Update, 详见文档
         * 
         * [EnableClientAccess()] - 该类对客户端可见
         * [EnableClientAccess(RequiresSecureEndpoint = true)] - 使用 HTTPS 协议
         * [Ignore] - 指定的方法不作为服务而公开
         * [Query(IsComposable=true)] - 支持客户端的 linq 查询,而且此查询会被在服务端执行
         * 
         * 在多个 Domain Services 间共享实体:通过 [ExternalReference], [Association()], Context.AddReference() 实现,详见文档
         
    */

        
    // 服务端的类名为:MyDomainService,则其生成的客户端上下文的类名为:MyDomainContext
        [EnableClientAccess()]
        
    public class MyDomainService : LinqToEntitiesDomainService<NorthwindEntities>
        {
            [Query(IsDefault 
    = true)]
            
    public IQueryable<Category> GetCategories()
            {
                
    return this.ObjectContext.Categories;
            }

            
    public void InsertCategory(Category category)
            {
                
    if ((category.EntityState != EntityState.Detached))
                {
                    
    this.ObjectContext.ObjectStateManager.ChangeObjectState(category, EntityState.Added);
                }
                
    else
                {
                    
    this.ObjectContext.Categories.AddObject(category);
                }
            }

            
    public void UpdateCategory(Category currentCategory)
            {
                
    this.ObjectContext.Categories.AttachAsModified(currentCategory, this.ChangeSet.GetOriginal(currentCategory));
            }

            
    public void DeleteCategory(Category category)
            {
                
    if ((category.EntityState == EntityState.Detached))
                {
                    
    this.ObjectContext.Categories.Attach(category);
                }
                
    this.ObjectContext.Categories.DeleteObject(category);
            }



            [Query(IsDefault 
    = true)]
            
    public IQueryable<Product> GetProducts()
            {
                
    return this.ObjectContext.Products;
            }

            
    public IQueryable<Product> GetProductsBySort(string sort)
            {
                
    return ObjectContext.Products.OrderBy(sort);
            }

            
    public void InsertProduct(Product product)
            {
                
    if ((product.EntityState != EntityState.Detached))
                {
                    
    this.ObjectContext.ObjectStateManager.ChangeObjectState(product, EntityState.Added);
                }
                
    else
                {
                    
    this.ObjectContext.Products.AddObject(product);
                }
            }

            
    public void UpdateProduct(Product currentProduct)
            {
                
    this.ObjectContext.Products.AttachAsModified(currentProduct, this.ChangeSet.GetOriginal(currentProduct));
            }

            
    public void DeleteProduct(Product product)
            {
                
    if ((product.EntityState == EntityState.Detached))
                {
                    
    this.ObjectContext.Products.Attach(product);
                }
                
    this.ObjectContext.Products.DeleteObject(product);
            }

            
    public IQueryable<Product> GetProductsByCategoryId(int categoryId)
            {
                
    return this.ObjectContext.Products.Where(p => p.CategoryID == categoryId);
            }
        }
    }



    MyDomainService.metadata.cs

    代码
    /*
     * [MetadataTypeAttribute()] - 指定类的元数据对象
     * [Include] - 生成的客户端上下文包含此字段
     * [Exclude] - 生成的客户端上下文不包含此字段
     * [Composition] - 指定字段为关联数据,即父实体增删改查时,此关联数据也会做相应的变化。指定此 Attribute 后,需显式指定其为 [Include]
     *     注:如果使用 DomainDataSource 则不能将字段设置为 [Composition]
     * [Editable(true)], [Editable(false)] - 指定字段是否可编辑
     * 
     * 支持 Data Annotation 方式的数据验证:DataTypeAttribute(具有很多常用的数据类型的验证), RangeAttribute, RegularExpressionAttribute, RequiredAttribute, StringLengthAttribute 等
     * 注:如果需要将自定义的验证既作用于服务端又作用于客户端,则需要把自定义的验证逻辑代码设置为 shared 模式
     
    */

    namespace Silverlight40.Web.Model
    {
        
    using System;
        
    using System.Collections.Generic;
        
    using System.ComponentModel;
        
    using System.ComponentModel.DataAnnotations;
        
    using System.Data.Objects.DataClasses;
        
    using System.Linq;
        
    using System.ServiceModel.DomainServices.Hosting;
        
    using System.ServiceModel.DomainServices.Server;

        
    using Silverlight40.Web.Service.Validation;

        [MetadataTypeAttribute(
    typeof(Category.CategoryMetadata))]
        [CustomValidation(
    typeof(CategoryValidator), "ValidateCategory")] // 演示通过自定义的实体验证器来实现验证
        public partial class Category
        {
            
    internal sealed class CategoryMetadata
            {
                
    private CategoryMetadata()
                {
                }

                [Key()]
                
    public int CategoryID { getset; }

                [Display(Name 
    = "类别名称")] // 显示用
                [Numeric(ErrorMessage = "字段“{0}”必须是数字")] // 演示通过继承 RegularExpressionAttribute 实现字段的自定义验证
                [StartsWith(ErrorMessage = "{0}")] // 演示通过继承 ValidationAttribute 实现字段的自定义验证
                [CustomValidation(typeof(EndsWidthValidator), "ValidateCategoryName")]  // 演示通过自定义的字段验证器来实现验证
                public string CategoryName { getset; }

                
    public string Description { getset; }

                [Exclude]
                
    public byte[] Picture { getset; }

                [Include]
                [Composition]
                
    public EntityCollection<Product> Products { getset; }
            }
        }

        [MetadataTypeAttribute(
    typeof(Product.ProductMetadata))]
        
    public partial class Product
        {
            
    internal sealed class ProductMetadata
            {
                
    private ProductMetadata()
                {
                }

                
    public Category Category { getset; }

                
    public Nullable<int> CategoryID { getset; }

                
    public bool Discontinued { getset; }

                
    public EntityCollection<Order_Detail> Order_Details { getset; }

                [Display(Order 
    = 0, Name = "产品ID")]
                
    public int ProductID { getset; }

                [Display(Order 
    = 1, Name = "产品名称")]
                
    public string ProductName { getset; }

                
    public string QuantityPerUnit { getset; }

                
    public Nullable<short> ReorderLevel { getset; }

                
    public Supplier Supplier { getset; }

                
    public Nullable<int> SupplierID { getset; }

                
    public Nullable<decimal> UnitPrice { getset; }

                
    public Nullable<short> UnitsInStock { getset; }

                
    public Nullable<short> UnitsOnOrder { getset; }
            }
        }
    }


    StartsWithAttribute.shared.cs

    代码
    /*
     * 验证规则:“必须以 1 开头”
     
    */

    using System;
    using System.Collections.Generic;
    using System.Linq;

    using System.ComponentModel.DataAnnotations;

    namespace Silverlight40.Web.Service.Validation
    {
        [AttributeUsage(AttributeTargets.Property 
    | AttributeTargets.Field)]
        
    public class StartsWithAttribute : ValidationAttribute
        {
            
    private readonly string _param;

            
    /*
            /// <summary>
            /// 构造函数
            /// 如果使用 shared 方式,则对于客户端来说不支持构造函数传参(服务端还是支持的)
            /// </summary>
            /// <param name="param">指定的开头字符串</param>
            public StartsWithAttribute(string param)
            {
                _param = param;
            }
             
    */

            
    public StartsWithAttribute()
            {
                _param 
    = "1";
            }

            
    /// <summary>
            
    /// 指定的值是否可以通过验证
            
    /// </summary>
            protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
                var boolean 
    = value.ToString().StartsWith(this._param);
                
                
    if (boolean)
                    
    return ValidationResult.Success;
                
    else
                    
    // new string[] { validationContext.MemberName } - 要对应到相关的 name 上,这样客户端才会有正确的验证提示效果
                    return new ValidationResult("必须以 1 开头"new string[] { validationContext.MemberName });
            }
        }
    }


    EndsWidthValidator.shared.cs

    代码
    /*
     * 验证规则:“CategoryName 必须以 1 结尾”,用于验证字段的验证器
     
    */

    using System;
    using System.Collections.Generic;
    using System.Linq;

    using System.ComponentModel.DataAnnotations;

    namespace Silverlight40.Web.Service.Validation
    {
        
    public class EndsWidthValidator
        {
            
    public static ValidationResult ValidateCategoryName(string s, ValidationContext context)
            {
                ValidationResult result 
    = ValidationResult.Success;
                
    if (s.EndsWith("1"))
                    result 
    = ValidationResult.Success;
                
    else
                    
    // new string[] { context.MemberName } - 要对应到相关的 name 上,这样客户端才会有正确的验证提示效果
                    result = new ValidationResult("必须以 1 结尾"new string[] { "CategoryName" });

                
    return result;
            }
        }
    }


    NumericAttribute.shared.cs

    代码
    /*
     * 验证规则:“必须是数字”
     
    */

    using System;
    using System.Collections.Generic;
    using System.Linq;

    using System.ComponentModel.DataAnnotations;

    namespace Silverlight40.Web.Service.Validation
    {
        
    public class NumericAttribute : RegularExpressionAttribute
        {
            
    public NumericAttribute()
                : 
    base("^[0-9]*$")
            {

            }

            
    /// <summary>
            
    /// 格式化错误信息
            
    /// </summary>
            
    /// <param name="name">指定的字段名</param>
            
    /// <returns></returns>
            public override string FormatErrorMessage(string name)
            {
                
    return string.Format(ErrorMessageString, name);
            }
        }
    }


    CategoryValidator.shared.cs

    代码
    /*
     * 验证规则:“CategoryName 必须包含 3”,用于验证实体的验证器
     
    */

    using System;
    using System.Collections.Generic;
    using System.Linq;

    using System.ComponentModel.DataAnnotations;
    using Silverlight40.Web.Model;

    namespace Silverlight40.Web.Service.Validation
    {
        
    public class CategoryValidator
        {
            
    public static ValidationResult ValidateCategory(Category category, ValidationContext context)
            {
                ValidationResult result 
    = ValidationResult.Success;
                
    if (category.CategoryName.Contains("3"))
                    result 
    = ValidationResult.Success;
                
    else
                    
    // new string[] { context.MemberName } - 要对应到相关的 name 上,这样客户端才会有正确的验证提示效果
                    result = new ValidationResult("必须包含 3"new string[] { "CategoryName" });

                
    return result;
            }
        }
    }



    2、客户端
    ValidationDemo.xaml

    代码
    <navigation:Page x:Class="Silverlight40.WCFRIAServices.ValidationDemo" 
               xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
               xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml" 
               xmlns:d
    ="http://schemas.microsoft.com/expression/blend/2008"
               xmlns:mc
    ="http://schemas.openxmlformats.org/markup-compatibility/2006"
               xmlns:navigation
    ="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
               xmlns:sdk
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
               xmlns:ns
    ="clr-namespace:Silverlight40.WCFRIAServices"
               Title
    ="ValidationDemo Page">
        
    <Grid x:Name="LayoutRoot">

            
    <StackPanel HorizontalAlignment="Left" DataContext="{Binding .}">

                
    <!--
                    用于显示验证错误列表
                
    -->
                
    <sdk:ValidationSummary Margin="3">
                    
    <sdk:ValidationSummary.Header>
                        错误列表:
                    
    </sdk:ValidationSummary.Header>
                
    </sdk:ValidationSummary>

                
    <!--
                    ValidatesOnDataErrors - 指定是否绑定数据实体上的 IDataErrorInfo 实现的验证错误
                    ValidatesOnNotifyDataErrors - 指定是否绑定数据实体上的 INotifyDataErrorInfo 实现的验证错误
                    ValidatesOnExceptions - 指定当出现异常时,是否报告验证错误
                    NotifyOnValidationError - 指定出现验证错误时是否引发 BindingValidationError 事件
                
    -->
                
    <StackPanel Orientation="Horizontal">
                    
    <TextBlock Name="lblCategoryName" Text="产品类别名称:" />
                    
    <TextBox Name="txtCategoryName" Text="{Binding Path=CategoryName, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnNotifyDataErrors=True, NotifyOnValidationError=True, ValidatesOnExceptions=True}" />
                    
    <sdk:Label Target="{Binding ElementName=txtCategoryName}" />
                    
    <sdk:DescriptionViewer Description="必须是数字;必须以 1 开头;必须以 1 结尾;必须包含 3" />
                
    </StackPanel>

                
    <!--
                    单击按钮后看验证提示效果
                
    -->
                
    <Button Name="btnAdd" Content="新增" Click="btnAdd_Click" />

            
    </StackPanel>
            
        
    </Grid>
    </navigation:Page>


    ValidationDemo.xaml.cs

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Navigation;

    using Silverlight40.Web.Service;
    using System.ComponentModel.DataAnnotations;
    using System.ServiceModel.DomainServices.Client;
    using Silverlight40.Web.Model;

    namespace Silverlight40.WCFRIAServices
    {
        
    public partial class ValidationDemo : Page
        {
            MyDomainContext _context 
    = new MyDomainContext();

            
    public ValidationDemo()
            {
                InitializeComponent();
            }

            
    protected override void OnNavigatedTo(NavigationEventArgs e)
            {

            }

            
    private void btnAdd_Click(object sender, RoutedEventArgs e)
            {
                Category category 
    = new Category();
                category.CategoryName 
    = txtCategoryName.Text;
                
    this.DataContext = category;

                
    // 为实体添加验证错误信息
                List<ValidationResult> validationResults = new List<ValidationResult>();
                
    if (!Validator.TryValidateObject(this.DataContext, new ValidationContext(this.DataContext, nullnull), validationResults))
                {
                    Entity entity 
    = (Entity)this.DataContext;
                    
    foreach (var item in validationResults)
                    {
                        entity.ValidationErrors.Add(item);
                    }
                }

                
    // 如果发现验证错误则。。。(客户端)
                if (category.HasValidationErrors)
                {
                    
    foreach (ValidationResult result in category.ValidationErrors)
                    {
                        
    string error = string.Format("属性 [{0}] 验证出错 [{1}]", result.MemberNames.First(), result.ErrorMessage);
                        MessageBox.Show(error, 
    "Error", MessageBoxButton.OK);
                    }

                    
    this.DataContext = category;
                }
                
    else
                {
                    _context.Categories.Add(category);
                    _context.SubmitChanges(OnSubmitCompleted, category);
                }
            }

            
    private void OnSubmitCompleted(SubmitOperation so)
            {
                
    if (so.HasError)
                {
                    MessageBox.Show(so.Error.ToString());
                    so.MarkErrorAsHandled();

                    
    // 如果发现验证错误则。。。(服务端)
                    if (so.EntitiesInError.Any())
                    {
                        
    foreach (ValidationResult result in so.EntitiesInError.First().ValidationErrors)
                        {
                            
    string error = string.Format("属性 [{0}] 验证出错 [{1}]", result.MemberNames.First(), result.ErrorMessage);
                            MessageBox.Show(error, 
    "Error", MessageBoxButton.OK);
                        }

                        
    this.DataContext = so.UserState as Category;
                    }
                }
                
    else
                {
                    MessageBox.Show(
    "添加成功");
                }
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    方便操作的命名范围scope
    使用Emmet加速Web前端开发
    Beanstalkd一个高性能分布式内存队列系统
    2000年互联网泡沫
    简单有效的kmp算法
    文本比较算法:计算文本的相似度
    字符串的四则运算
    文本比较算法:Needleman/Wunsch算法
    两则面试题(动态规划)
    文本比较算法:编辑距离
  • 原文地址:https://www.cnblogs.com/webabcd/p/1857199.html
Copyright © 2011-2022 走看看