Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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()?

like image 370
Marcel Popescu Avatar asked Mar 21 '26 02:03

Marcel Popescu


2 Answers

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;
like image 98
counsellorben Avatar answered Mar 23 '26 15:03

counsellorben


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");
}
like image 30
Eranga Avatar answered Mar 23 '26 16:03

Eranga