Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Monday, 20 May 2013

Id column of viewmodel not bound on Postback in MVC

This weekend I had an issue with the postback of a simple viewmodel object. For some reason the validation of this object failed even though the Id was not required.
     public class SkillViewModel
    {
        public int Id { get; set; }

        [Required]
        public virtual string Description { get; set; }
        [Required]
        public virtual string Name { get; set; }
    }
      [HttpPost]
        public ActionResult Create(SkillViewModel skill)
            if (ModelState.IsValid)
            {
                SkillRecord oRecord = new SkillRecord()
                {
                    Name = skill,
                    Description = skill.Description
                };

                SkillService.Create(oRecord);

                return RedirectToAction("Index");
            }

            return View(skill);
        }
To solve this issue, I started by adding some debugging code to the controller action to find out what was going wrong.
var errors = ModelState.SelectMany(e => e.Value.Errors);
This gave me the following error: "The Id field is required.". This is strange. Of course changing the name of the Id property works, but this is not what I want. So what is going on. In the create I am underposting, this means I am not posting the Id. This gave me problems in combination with my defined routes.
routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
Since I am not posting the Id from by razor view, the binding takes tries to get the id from the route, which is not there and cause a validation error. There are two solutions, either add '[Bind(Exclude = "Id")]' before the parameter in the Create method or add an additional route (before the existing one) without the id in it:
routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );