我在ASP.Net 4.0中使用WCF,EntityFramework 4.1和MVC3使用Razor。
DataAnnotations在以下场景中正常工作:
将POCO类放在另一个带有EF的DLL中,然后通过我的表示层直接调用填充模型。如果我尝试在前端网格上编辑电子邮件地址并故意输入虚假电子邮件,则该属性的DataAnnotation错误会出现。
但是,如果我使用带有 WCF 中间层调用的方法(而不是直接调用),数据会回来并且更新得很好,除了 DataAnnotations这一事实不适用于这种情况。如果我尝试在前端网格上编辑电子邮件地址并故意放入虚假电子邮件,则该属性的DataAnnotation 不会。
如何使用WCF进行操作?在没有识别DataAnnotations的情况下,必须存在某种WCF属性。
下面是相关代码:
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; }
}
}
控制器:
[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;
}
控制器:
[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()
)
答案 0 :(得分:5)
除了你正在使用的技术背后的一些理论之外,你不会错过任何东西。 WCF是用于公开服务的技术,它以可互操作的方式完成。服务公开的数据合同只是为数据创建。您在合同中使用了多少花哨属性或者您在属性的get
和set
方法中放置了多少自定义逻辑并不重要。在客户端,你总能看到:
[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应用程序之间创建紧密耦合。