asp.net mvc 3 validation for Id field with EF code

2019-01-26 19:31发布

问题:

I have the following model:

public class Product
{
  [Key]
  [HiddenInput(DisplayValue = false)]
  public int Id { get; set; }

  [Required]
  [StringLength(10)]
  public string ProductCode { get; set; }

  [Required]
  [StringLength(40)]
  public string ProductName { get; set; }
}

and the following pair of Add methods in the controller:

[HttpGet]
public ActionResult Add()
{
  return View();
}

[HttpPost]
[ValidateInput(false)]
[ValidateAntiForgeryToken]
public ActionResult Add(Product product)
{
  productRepository.Add(product);

  return RedirectToAction("Index");
}

This is the Add view:

@using Models
@model Product

<h2>Add Product</h2>

@using (@Html.BeginForm("Add", "Home")) {
  @Html.AntiForgeryToken()
  @Html.EditorForModel()
  <input type="submit" id="btnSubmit" value="Submit"/>
}

Everything is displayed just fine, unfortunately I am unable to submit the form. It took me a while to figure out that the Id field gets validated. Indeed, if I remove the HiddenInput attribute, I can see on submitting that it tells me the Id field is required.

Is there a way to mark it as not required while still using EditorForModel()?

回答1:

If you must keep the primary key as part of the model, then you need to override the default for DataAnnotationsModelValidatorProvider that value types are required. Add the following to the Application_Start method in Global.asax.cs:

ModelValidatorProviders.Providers.Clear(); 
ModelValidatorProviders.Providers.Add(new DataAnnotationsModelValidatorProvider());
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;


回答2:

You should consider using view models instead of sending your domain entities as models to views.

public class ProductAddModel
{
  [Required]
  [StringLength(10)]
  public string ProductCode { get; set; }

  [Required]
  [StringLength(40)]
  public string ProductName { get; set; }
}

Then use a tool like AutoMapper to map the viewmodel back to your domain model

[HttpPost]
[ValidateInput(false)]
[ValidateAntiForgeryToken]
public ActionResult Add(ProductAddModel productAddModel)
{
  if (ModelState.IsValid)
  {
      Product product = Mapper.Map<ProductAddModel, Product>(productAddModel);

      productRepository.Add(product);
  }

  return RedirectToAction("Index");
}