wcf - 使用 DataAnnotations 通过 WCF 引用 MVC 模型

标签 wcf asp.net-mvc-3 entity-framework-4.1

我在带有 EntityFramework 4.1 的 ASP.Net 4.0 和带有 Razor 的 MVC3 中使用 WCF。

DataAnnotations 在以下情况下工作正常:

将 POCO 类放在另一个带有 EF 的 DLL 中,然后使用来 self 的表示层的直接调用来填充模型。如果我尝试在前端网格上编辑电子邮件地址并故意放入虚假电子邮件,则该属性出现 DataAnnotation 错误。

但是,如果我使用带有 WCF 中间层调用(而不是直接调用)的方法,数据会返回并得到更新,除了 DataAnnotations不要在这种情况下工作。如果我尝试在前端网格上编辑电子邮件地址并故意放入虚假电子邮件,则该属性的 DataAnnotation 不会出现。

如何使用 WCF 让它工作?一定有某种 WCF 属性我遗漏了,它无法识别 DataAnnotations。

下面是相关代码:

2 层场景:

型号

 using System;
using System.Collections.Generic;
//using System.ServiceModel;
//using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;
using DataAnnotationsExtensions;

namespace YeagerTechModel
{
    public class Customer
    {
        public Customer()
        {
            this.Projects = new HashSet<Project>();
        }


        public short CustomerID { get; set; }


        [Required]
        [StringLength(50)]
        [DataType(DataType.EmailAddress)]
        [Email]
        public string Email { get; set; }


        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string Company { get; set; }


        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string FirstName { get; set; }


        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string LastName { get; set; }


        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string Address1 { get; set; }


        [StringLength(50)]
        [DataType(DataType.Text)]
        public string Address2 { get; set; }


        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string City { get; set; }


        [StringLength(2, MinimumLength = 2, ErrorMessage = "Must have a length of 2.")]
        [DataType(DataType.Text)]
        public string State { get; set; }


        [StringLength(10)]
        [DataType(DataType.Text)]
        [RegularExpression(@"^\d{5}(-\d{4})?$", ErrorMessage = "Invalid Zip")]
        public string Zip { get; set; }


        [StringLength(12)]
        [DataType(DataType.PhoneNumber)]
        [RegularExpression(@"^\s*([\(]?)\[?\s*\d{3}\s*\]?[\)]?\s*[\-]?[\.]?\s*\d{3}\s*[\-]?[\.]?\s*\d{4}$", ErrorMessage = "Invalid Phone")]
        public string HomePhone { get; set; }


        [StringLength(12)]
        [DataType(DataType.PhoneNumber)]
        [RegularExpression(@"^\s*([\(]?)\[?\s*\d{3}\s*\]?[\)]?\s*[\-]?[\.]?\s*\d{3}\s*[\-]?[\.]?\s*\d{4}$", ErrorMessage = "Invalid Phone")]
        public string CellPhone { get; set; }


        [StringLength(100)]
        [DataType(DataType.Url)]
        [Url]
        public string Website { get; set; }


        [StringLength(50)]
        [DataType(DataType.EmailAddress)]
        [Email]
        public string IMAddress { get; set; }


        public System.DateTime CreatedDate { get; set; }


        public Nullable<System.DateTime> UpdatedDate { get; set; }


        public virtual ICollection<Project> Projects { get; set; }
    }
} 

Controller :

[GridAction]
        public ActionResult Index()
        {
            ViewData["ErrCode"] = string.Empty;

            if (HttpContext.User.IsInRole("Admin"))
            {
                try
                {
                    //IEnumerable<YeagerTechWcfService.Customer> customerList = db.GetCustomers();

                    //IEnumerable<YeagerTechModel.Customer> customerList = db.GetCustomers();
                    DbContext.Configuration.ProxyCreationEnabled = false;
                    IEnumerable<Customer> customerList = DbContext.Customers.Where(p => p.CustomerID > 0);

                    if (DbContext.Database.Connection != null)
                    {
                        if (DbContext.Database.Connection.State != System.Data.ConnectionState.Closed)
                        {
                            DbContext.Database.Connection.Close();
                            DbContext.Database.Connection.Dispose();
                        }
                    }

                    return View(new GridModel<YeagerTechModel.Customer>
                    {
                        Data = customerList

                    });
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else
            {
                //HttpCookie cn = Request.Cookies["strCookieName"];
                //if (cn != null)
                //{
                //    YeagerTechWcfService.Customer cust = db.GetCustomerID(Convert.ToInt16(cn.Value),false);

                //    if (cust != null)
                //    {
                //        return View(new GridModel<YeagerTechWcfService.Customer>
                //        {
                //            //Data = cust
                //        });
                //    }
                //    else
                //        return View(new GridModel<YeagerTechWcfService.Customer>());
                //}
                //else
                //{
                //    TempData["ErrCode"] = "CustView";
                return RedirectToAction("Index", "Home");
                //}
            }
        }

查看:

@model Telerik.Web.Mvc.GridModel<YeagerTechModel.Customer>
@{
    ViewBag.Title = "Customer Index";
}
<h2>
    Customer Index</h2>
@(  Html.Telerik().Grid<YeagerTechModel.Customer>(Model.Data)
      .Name("Customers")
            .DataKeys(dataKeys => dataKeys.Add(o => o.CustomerID)
                                            .RouteKey("CustomerID"))
                .ToolBar(commands => commands.Insert().ButtonType(GridButtonType.Text).ImageHtmlAttributes(new { style = "margin-left:0" }))
      .Columns(columns =>
            {
                columns.Bound(o => o.CustomerID).Hidden(true);
                columns.Command(commands =>
                {
                    commands.Edit().ButtonType(GridButtonType.Text);
                }).Width(200).Title("Command");
                columns.Bound(o => o.Email).Width(200).Filterable(false);
                columns.Bound(o => o.Company).Width(200).Filterable(false);
                columns.Bound(o => o.FirstName).Width(100).Title("FName").Filterable(false);
                columns.Bound(o => o.LastName).Width(100).Title("LName").Filterable(false);
                columns.Bound(o => o.Address1).Width(200).Title("Addr1").Filterable(false).Sortable(false);
                columns.Bound(o => o.Address2).Width(100).Title("Addr2").Filterable(false).Sortable(false);
                columns.Bound(o => o.City).Width(100);
                columns.Bound(o => o.State).Width(40).Title("ST");
                columns.Bound(o => o.Zip).Width(60);
                columns.Bound(o => o.HomePhone).Width(120).Filterable(false).Sortable(false);
                columns.Bound(o => o.CellPhone).Width(120).Filterable(false).Sortable(false);
                columns.Bound(o => o.Website).Width(100).Filterable(false).Sortable(false);
                columns.Bound(o => o.IMAddress).Width(100).Filterable(false).Sortable(false);
                columns.Bound(o => o.CreatedDate).Format("{0:MM/dd/yyyy}").ReadOnly(true).Width(120).Filterable(false).Sortable(false);
                columns.Bound(o => o.UpdatedDate).Format("{0:MM/dd/yyyy}").ReadOnly(true).Width(120).Filterable(false).Sortable(false);
            }).DataBinding(dataBinding =>
                dataBinding.Ajax()
                        .Insert("_InsertAjaxEditing", "Customer")
                        .Update("_SaveAjaxEditing", "Customer"))
    .Editable(editing => editing.Mode(GridEditMode.InLine))
    .Pageable()
    .Sortable()
    .Filterable()
    .Scrollable()
 )

NTier 场景 型号:

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;
using DataAnnotationsExtensions;

namespace YeagerTechModel
{
    [Serializable]
    [DataContract(IsReference = true)]
    public class Customer
    {
        public Customer()
        {
            this.Projects = new HashSet<Project>();
        }

        [DataMember]
        public short CustomerID { get; set; }

        [DataMember]
        [Required]
        [StringLength(50)]
        [DataType(DataType.EmailAddress)]
        [Email]
        public string Email { get; set; }

        [DataMember]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string Company { get; set; }

        [DataMember]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string FirstName { get; set; }

        [DataMember]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string LastName { get; set; }

        [DataMember]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string Address1 { get; set; }

        [DataMember]
        [StringLength(50)]
        [DataType(DataType.Text)]
        public string Address2 { get; set; }

        [DataMember]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "Must have a minimum length of 3.")]
        [DataType(DataType.Text)]
        public string City { get; set; }

        [DataMember]
        [StringLength(2, MinimumLength = 2, ErrorMessage = "Must have a length of 2.")]
        [DataType(DataType.Text)]
        public string State { get; set; }

        [DataMember]
        [StringLength(10)]
        [DataType(DataType.Text)]
        [RegularExpression(@"^\d{5}(-\d{4})?$", ErrorMessage = "Invalid Zip")]
        public string Zip { get; set; }

        [DataMember]
        [StringLength(12)]
        [DataType(DataType.PhoneNumber)]
        [RegularExpression(@"^\s*([\(]?)\[?\s*\d{3}\s*\]?[\)]?\s*[\-]?[\.]?\s*\d{3}\s*[\-]?[\.]?\s*\d{4}$", ErrorMessage = "Invalid Phone")]
        public string HomePhone { get; set; }

        [DataMember]
        [StringLength(12)]
        [DataType(DataType.PhoneNumber)]
        [RegularExpression(@"^\s*([\(]?)\[?\s*\d{3}\s*\]?[\)]?\s*[\-]?[\.]?\s*\d{3}\s*[\-]?[\.]?\s*\d{4}$", ErrorMessage = "Invalid Phone")]
        public string CellPhone { get; set; }

        [DataMember]
        [StringLength(100)]
        [DataType(DataType.Url)]
        [Url]
        public string Website { get; set; }

        [DataMember]
        [StringLength(50)]
        [DataType(DataType.EmailAddress)]
        [Email]
        public string IMAddress { get; set; }

        [DataMember]
        public System.DateTime CreatedDate { get; set; }

        [DataMember]
        public Nullable<System.DateTime> UpdatedDate { get; set; }

        [DataMember]
        public virtual ICollection<Project> Projects { get; set; }
    }
}

WCF 调用:

public IEnumerable<Customer> GetCustomers()
        {
            YeagerTechEntities DbContext = new YeagerTechEntities();

            DbContext.Configuration.ProxyCreationEnabled = false;

            IQueryable<Customer> customer = DbContext.Customers.Where(p => p.CustomerID > 0);

            CloseConnection(DbContext);

            return customer;
        }

Controller :

[GridAction]
        public ActionResult Index()
        {
            ViewData["ErrCode"] = string.Empty;

            if (HttpContext.User.IsInRole("Admin"))
            {
                try
                {
                    IEnumerable<YeagerTechWcfService.Customer> customerList = db.GetCustomers();

                    return View(new GridModel<YeagerTechWcfService.Customer>
                    {
                        Data = customerList
                    });
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

查看:

@model Telerik.Web.Mvc.GridModel<YeagerTech.YeagerTechWcfService.Customer>
@{
    ViewBag.Title = "Customer Index";
}
<h2>
    Customer Index</h2>
@(  Html.Telerik().Grid<YeagerTech.YeagerTechWcfService.Customer>(Model.Data)
      .Name("Customers")
            .DataKeys(dataKeys => dataKeys.Add(o => o.CustomerID)
                                            .RouteKey("CustomerID"))
                .ToolBar(commands => commands.Insert().ButtonType(GridButtonType.Text).ImageHtmlAttributes(new { style = "margin-left:0" }))
      .Columns(columns =>
            {
                columns.Bound(o => o.CustomerID).Hidden(true);
                columns.Command(commands =>
                {
                    commands.Edit().ButtonType(GridButtonType.Text);
                }).Width(200).Title("Command");
                columns.Bound(o => o.Email).Width(200).Filterable(false);
                columns.Bound(o => o.Company).Width(200).Filterable(false);
                columns.Bound(o => o.FirstName).Width(100).Title("FName").Filterable(false);
                columns.Bound(o => o.LastName).Width(100).Title("LName").Filterable(false);
                columns.Bound(o => o.Address1).Width(200).Title("Addr1").Filterable(false).Sortable(false);
                columns.Bound(o => o.Address2).Width(100).Title("Addr2").Filterable(false).Sortable(false);
                columns.Bound(o => o.City).Width(100);
                columns.Bound(o => o.State).Width(40).Title("ST");
                columns.Bound(o => o.Zip).Width(60);
                columns.Bound(o => o.HomePhone).Width(120).Filterable(false).Sortable(false);
                columns.Bound(o => o.CellPhone).Width(120).Filterable(false).Sortable(false);
                columns.Bound(o => o.Website).Width(100).Filterable(false).Sortable(false);
                columns.Bound(o => o.IMAddress).Width(100).Filterable(false).Sortable(false);
                columns.Bound(o => o.CreatedDate).Format("{0:MM/dd/yyyy}").ReadOnly(true).Width(120).Filterable(false).Sortable(false);
                columns.Bound(o => o.UpdatedDate).Format("{0:MM/dd/yyyy}").ReadOnly(true).Width(120).Filterable(false).Sortable(false);
            }).DataBinding(dataBinding =>
                dataBinding.Ajax()
                        .Insert("_InsertAjaxEditing", "Customer")
                        .Update("_SaveAjaxEditing", "Customer"))
    .Editable(editing => editing.Mode(GridEditMode.InLine))
    .Pageable()
    .Sortable()
    .Filterable()
    .Scrollable()
 )

最佳答案

不,除了您正在使用的技术背后的一些理论之外,您没有遗漏任何东西。 WCF 是公开服务的技术,它以可互操作的方式进行。服务公开的数据契约只是为数据创建的。无论您在契约(Contract)中使用了多少花哨的属性,或者您在属性的 getset 方法中放置了多少自定义逻辑,都无关紧要。在客户端你总是看到这个:

[DataContract(IsReference = true)]
public partial class Customer
{
    [DataMember]
    public short CustomerID { get; set; }

    [DataMember]
    public string Email { get; set; }

    [DataMember]
    public string Company { get; set; }

    [DataMember]
    public string FirstName { get; set; }

    [DataMember]
    public string LastName { get; set; }

    [DataMember]
    public string Address1 { get; set; }

    [DataMember]
    public string Address2 { get; set; }

    [DataMember]
    public string City { get; set; }

    [DataMember]
    public string State { get; set; }

    [DataMember]
    public string Zip { get; set; }

    [DataMember]
    public string HomePhone { get; set; }

    [DataMember]
    public string CellPhone { get; set; }

    [DataMember]
    public string Website { get; set; }

    [DataMember]
    public string IMAddress { get; set; }

    [DataMember]
    public System.DateTime CreatedDate { get; set; }

    [DataMember]
    public Nullable<System.DateTime> UpdatedDate { get; set; }

    [DataMember]
    public Project[] Projects { get; set; }
}

这样做的原因是,一旦您公开服务,它就会以可互操作的方式公开其所有契约——服务和操作契约由 WSDL 描述,数据契约由 XSD 描述。 XSD 只能描述数据的结构而不能描述逻辑。验证本身可以在 XSD 中以某种有限的方式进行描述,但 .NET XSD 生成器不会这样做。一旦您将服务引用添加到您的 WCF 服务,代理生成器将把 WSDL 和 XSD 作为源,并在没有所有这些属性的情况下再次创建您的类。

如果您想要进行客户端验证,您应该首先在客户端实现该验证 - 这可以通过使用 buddy classes 来完成。对于 WCF 代理使用的部分类。如果您不想使用这种方式,则必须在 WCF 客户端和 WCF 服务之间与您的实体共享程序集,reuse those types添加服务引用时。这将在您的服务和 ASP.NET MVC 应用程序之间创建紧密耦合。

关于wcf - 使用 DataAnnotations 通过 WCF 引用 MVC 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7942182/

相关文章:

wcf - 将异常映射到 REST Web 服务中的 HTTP 状态代码

wcf - WCF HTTP 绑定(bind)是否在 TCP 上运行?

c# - 在 IIS 6 中托管 .net 4.0 REST WCF 服务

c# - MVC3 网格中的部分结果

c# - 派生属性上的自定义模型绑定(bind)不起作用

asp.net-mvc - 如何避免授权码逻辑重复

c# - 在 Entity Framework (4.1) 中具有一对多双向关系的优点和缺点是什么?

c# - 映射到嵌套类

java - 从 .NET 客户端使用 Java Web 服务

entity-framework - Entity Framework 代码优先只读集合