I have a project in which I have a database model class provided along with a separate EDMX EF model. In the same solution, I have a web service which accesses this project along with the model class. I want the model class to perform data annotations against the front end for validation, but is not getting validated at all.
For brevity, the model class (in my Model project) is as follows. My web service references this class and is used as the interface.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel;
using System.Runtime.Serialization;
[DataContract]
[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}
public class CustomerMetaData
{
[DataMember]
public object CustomerID { get; set; }
[Required]
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public object Email { get; set; }
}
When I hit the Submit button on the form, it tries to add the record and does not do any validation. A runtime error occurs informing me that the email address is required. I obviously want this validation to be done up front with the data annotations.
How can I accomplish this?
An actual runtime error is coming back saying that the email address should not be NULL when the record tries to be added. This is correct. The database column requires a value.
I thought that by having the data annotations in the model, if there is something wrong with the front end and the model is not valid once the form tries to be posted, the corresponding data annotation error should display on the form. I was under the impression that there is no need for writing any specific client side validation. The model is supposed to take care of that for you. Am I incorrect in this assumption?
There are articles on the web how to do this with CodeFirst, but I have seen none on how to do this with DataBaseFirst. How can this be accomplished?
Once again, my Customer class is as follows.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel;
using System.Runtime.Serialization;
namespa开发者_如何学编程ce YeagerTechModel
{
[Serializable]
[DataContract]
//[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
public Customer()
{
this.Projects = new HashSet<Project>();
}
[DataMember]
public short CustomerID { get; set; }
[Required]
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public string Email { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Company { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string FirstName { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string LastName { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Address1 { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string Address2 { get; set; }
[StringLength(50)]
[DataType(DataType.Text)]
[DataMember]
public string City { get; set; }
[StringLength(2)]
[DataType(DataType.Text)]
[DataMember]
public string State { get; set; }
[StringLength(10)]
[DataType(DataType.Text)]
[RegularExpression(@"^\d{5}(-\d{4})?$")]
[DataMember]
public string Zip { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
[DataMember]
public string HomePhone { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
[DataMember]
public string CellPhone { get; set; }
[StringLength(100)]
[DataType(DataType.Url)]
[DataMember]
public string Website { get; set; }
[StringLength(50)]
[DataType(DataType.EmailAddress)]
[DataMember]
public string IMAddress { get; set; }
[DataMember]
public System.DateTime CreatedDate { get; set; }
[DataMember]
public Nullable<System.DateTime> UpdatedDate { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
}
When I debug the "if (ModelState.IsValid)" in my client, the property always returns true. It's as if the DataAnnotations are not even being recognized. When debugging, I check the ModelState object and it has all the property values there (an empty string in all cases since I'm trying to force an error). I should be getting an isRequired error on the email address which I'm purposely leaving blank.
[HttpPost]
public ActionResult Create(YeagerTechWcfService.Customer cust)
{
if (ModelState.IsValid)
{
try
{
db.AddCustomer(cust);
TempData["ErrCode"] = "Customer successfully added.";
return RedirectToAction("Index", "Home");
}
catch (Exception ex)
{
ViewData["ErrCode"] = "CustErr";
ViewBag.Error = ex.Message;
return View();
}
}
else
return View();
}
Unfortunately this annotation only appears to affect rendering, not validation. I've just had the same problem with DataType.Url and it's also discussed in the question Is the DataTypeAttribute validation working in MVC2? (albeit for MVC 2 - but the problems seems the same in 3).
Just drop a regular expression data annotation on it:
[RegularExpression(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", ErrorMessage = "Email was invalid.")]
Just to expand on this a bit, in MVC 3 you could go another route to use the validation. I use MVC 3 + EF database first and I can use code like this in the extension/partial Model class:
[MetadataType(typeof(Foobar.Metadata))]
[Serializable]
public partial class Foobar
{
private sealed class Metadata
{
[Required]
[MinLength(10)]
public object Name { get; set; }
}
// Other stuff here
}
Then when I can feed my little Foobar an invalid name in a controller action and I can get the validation errors nicely by using TryValidateModel instead of ModelState.IsValid (Horror of horrors, I don't databind).
Foobar c = new Foobar();
c.Name = "ponies";
var y = TryValidateModel(c);
if (!y)
{
foreach (var item in ModelState.Values)
{
foreach (var err in item.Errors)
{
DoxLog.Error(err.ErrorMessage, err.Exception);
}
}
}
精彩评论