-1

I am new to ASP.NET MVC 5. I am trying to make a user-management software. but in the user registration(create) controller my model is getting invalidated. Don't know why. I might have a mistake in my model Binding. Here is the attached code. Any Help is appreciated.

Model file

public class UserData
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int userid { get; set; }


    [Required(ErrorMessage = "Domain ID")]
    [Display(Name = "Domain ID")]
    public string domainid { get; set; }

    [Required(ErrorMessage = "Choose Role")]
    [Display(Name = "Role")]
    public string role { get; set; }

    [Required(ErrorMessage = "Choose Country")]
    [Display(Name = "Country")]
    public string country { get; set; }

    [Required(ErrorMessage = "Choose BU")]
    [Display(Name = "BU")]
    public string bu { get; set; }

    [Required]
    [RegularExpression(@"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@"
 + @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
            [0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
 + @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
            [0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
 + @"([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$", ErrorMessage = "Please Provide Valid Email-ID")]
    [Display(Name = "Email"),DataType(DataType.EmailAddress)]
    public string email { get; set; }


    [HiddenInput(DisplayValue=true)]
    public DateTime date_from { get; set; }

    [HiddenInput(DisplayValue = true)]
    public DateTime date_to { get; set; }

    [HiddenInput(DisplayValue=true)]
    public bool active { get; set; }

       }

ViewModel File

 public class UserRegistrationViewModel

{

    public UserData userdata { get; set; }

    public string SelectedRole { get; set; }
    public IEnumerable<SelectListItem> RoleList { get; set; }


    public string SelectedCountry { get; set; }
    public IEnumerable<SelectListItem> CountryList { get; set; }


    public string SelectedBU { get; set; }
    public IEnumerable<SelectListItem> BUList { get; set; }

}

Controller file

 public class UserDatasController : Controller
{
    private ApplicationDataContext db = new ApplicationDataContext();

    // GET: UserDatas
    public ActionResult Index()
    {
        return View(db.UsersData.ToList());
    }
       public ActionResult Create()
    {
        var model = new UserRegistrationViewModel();
        model.CountryList = from p in XDocument.Load("C:/Users/inkosah/Documents/Visual Studio 2013/Projects/Policy Assessment/Policy Assessment/country_list.xml").Descendants("Name")
                           //var a=Path.GetFullPath("Policy Asse")
                           let value = (string)p.Element("Text")
                           select new SelectListItem
                           {
                               Selected = (value == model.SelectedCountry),
                               Text = (string)p.Element("Text"),
                               Value = value
                           };
        model.BUList = from q in XDocument.Load("C:/Users/inkosah/Documents/Visual Studio 2013/Projects/Policy Assessment/Policy Assessment/bu_list.xml").Descendants("BU")
                      let value2 = (string)q.Element("BU_Name")
                      select new SelectListItem
                      {
                          Selected = (value2 == model.SelectedBU),
                          Text = (string)q.Element("BU_Name"),
                          Value = value2
                      };


        model.RoleList = from n in XDocument.Load("C:/Users/inkosah/Documents/Visual Studio 2013/Projects/Policy Assessment/Policy Assessment/UserRoleList.xml").Descendants("Role")
                        let value1 = (string)n.Element("Role_Name")
                        select new SelectListItem
                        {
                            Selected = (value1 == model.SelectedRole),
                            Text = (string)n.Element("Role_Name"),
                            Value = value1
                        };
        return View(model);
    }

    // POST: UserDatas/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "SelectedRole,SelectedCountry,SelectedBU")]UserRegistrationViewModel RegisterData,[Bind(Include="domainid,email")] UserData userdata)
    {
        userdata.date_from = DateTime.Now;
        userdata.date_to = DateTime.MaxValue;
        userdata.active = false;
        userdata.role = RegisterData.SelectedRole;
        userdata.bu = RegisterData.SelectedBU;
        userdata.country = RegisterData.SelectedCountry;

        if (ModelState.IsValid)
        {

            db.UsersData.Add(userdata);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(userdata);
    }

create.cshtml

    @model Policy_Assessment.ViewModels.UserRegistrationViewModel

@{
    ViewBag.Title = "User Registration Page";
}


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>User Input</h4>
        <hr />
        @Html.ValidationSummary(true)
        <div class="form-group">
            @Html.LabelFor(model => model.userdata.domainid, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.userdata.domainid)
                @Html.ValidationMessageFor(model => model.userdata.domainid)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.userdata.role, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @*@Html.EditorFor(model => model.role)*@
                @Html.DropDownListFor(model => model.SelectedRole, Model.RoleList, "-----Role-----")
                @Html.ValidationMessageFor(model=>model.SelectedRole)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.userdata.country, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @*@Html.EditorFor(model => model.country)*@
                @Html.DropDownListFor(model => model.SelectedCountry,Model.CountryList,"----Country-----")
                @Html.ValidationMessageFor(model => model.userdata.country)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.userdata.bu, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model=>model.SelectedBU,Model.BUList,"--Select BU----")
                @Html.ValidationMessageFor(model => model.userdata.bu)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.userdata.email, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.userdata.email)
                @Html.ValidationMessageFor(model => model.userdata.email)
            </div>
        </div>

        @*<div class="form-group">
            @Html.HiddenFor(model => model.userdata.date_from, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.HiddenFor(model => model.userdata.date_from)
                @Html.ValidationMessageFor(model => model.userdata.date_from)
            </div>
        </div>

        <div class="form-group">
            @Html.HiddenFor(model => model.userdata.date_to, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.HiddenFor(model => model.userdata.date_to)
                @Html.ValidationMessageFor(model => model.userdata.date_to)
            </div>
        </div>

        <div class="form-group">
            @Html.HiddenFor(model => model.userdata.active, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.HiddenFor(model => model.userdata.active)
                @Html.ValidationMessageFor(model => model.userdata.active)
            </div>
        </div>*@

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Register" class="btn btn-default" />
            </div>
        </div>
    </div>
}

@*<div>
    @Html.ActionLink("Back to List", "Index")
</div>*@

<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

Context File

 public class ApplicationDataContext : DbContext
{
    public ApplicationDataContext()
        : base("DefaultConnection")
    { }

    public System.Data.Entity.DbSet<Policy_Assessment.ViewModels.UserRegistrationViewModel> UserRegistrationData { get; set; }

    public System.Data.Entity.DbSet<Policy_Assessment.Models.UserData> UsersData { get; set; }


}

Please Note i am a beginner in MVC ASP.Net. Any Help or Explanation would be helpful.

Breakpoint at userdata object

Breakpoint at ModelState. Here in the role,country,and for bu i am getting the null value. but in the userdata object the value is showing.

Koushik Saha
  • 673
  • 1
  • 10
  • 25
  • What's the validation message? – Michael Nov 05 '14 at 12:09
  • i mean to say my model is getting invalidated when doing the (Modelstate.isvalid). even though i am getting my all values inside the create action method. – Koushik Saha Nov 05 '14 at 12:15
  • Put a breakpoint in your create method, once hit, expand the ModelState object and check all object in dictionary to know validation is failing for which property. – SBirthare Nov 05 '14 at 12:15
  • i have done that also. pls take a look at the controller file. before checking ModelState.isvalid I am assigning the values also. but in the modelstate some of the values (role,bu,country) null value is showing. don't understand what is happening. – Koushik Saha Nov 05 '14 at 12:41
  • Expand the "Errors" collection and read the error. – CodeCaster Nov 05 '14 at 12:42
  • @CodeCaster well its null. even though i am setting the value. – Koushik Saha Nov 05 '14 at 12:59
  • 1
    `ModelState` gets filled before your action method is called. Setting properties afterwards won't automagically clear your model errors. – CodeCaster Nov 05 '14 at 13:01
  • @CodeCaster can u tell me in which part of my code i am having the error? – Koushik Saha Nov 05 '14 at 13:04
  • 1
    I just explained. The model you get posted is not valid according to your validations. If you want to clear errors for a specific property, see [MVC3 Remove ModelState Errors](http://stackoverflow.com/questions/7424003/mvc3-remove-modelstate-errors). – CodeCaster Nov 05 '14 at 13:05
  • @CodeCaster can u give me some example for binding complex objects ? – Koushik Saha Nov 05 '14 at 13:10
  • The `role` property of `UserData` is required, but your not binding anything in your view to that property (only to `SelectedRole`) so when it posts back its its null and therefore invalid. –  Nov 05 '14 at 21:57
  • @StephenMuecke i want `selectedRole` value in the role property. How can i get that? i am writing this in the view `@Html.DropDownListFor(model => model.SelectedRole, Model.RoleList, "-----Role-----")`. Help would be appreciated as i am new in MVC. – Koushik Saha Nov 06 '14 at 05:54
  • @user3132179, Personally I would modify the view model to include all the `UserData` properties that you want to edit rather than including `public UserData userdata { get; set; }`, and then map from the view model to the data model in the POST method, but if you want to do it this way, delete property `SelectedRole` and just bind to `userdata.role` as in `@Html.DropDownListFor(m => m.userdata.role, Model.RoleList, ...)` (ditto for other properties) –  Nov 06 '14 at 06:04
  • @StephenMuecke thank u for the advice. can u give me a small example the way you want to approach this issue? – Koushik Saha Nov 06 '14 at 06:10

1 Answers1

1

Your posting back your data model (included as a property of your view model). The data model has a [Required] attribute for property role but you are creating a control for this property so nothing is bound, meaning its null and therefore its invalid. Two ways to solve this.

A. Remove property string SelectedRole from the view model and bind directly to the the data model that's included in the view model

@Html.DropDownListFor(m => m.userdata.role, Model.RoleList, ...)

Now, userdata.role will contain the selected option value and will be valid (note you would need to do this for the other 2 properties as well).

B. Remove property UserData userdata from the view model and include in the view model the properties from UserData that you are editing

public class UserRegistrationViewModel
{
  [Required(ErrorMessage = "Domain ID")]
  [Display(Name = "Domain ID")]
  public string domainid { get; set; }
  [Required(ErrorMessage = "Choose Role")]
  [Display(Name = "Role")]
  public string role { get; set; }
  [Required(ErrorMessage = "Choose Country")]
  [Display(Name = "Country")]
  public string country { get; set; }
  [Required(ErrorMessage = "Choose BU")]
  [Display(Name = "BU")]
  public string bu { get; set; }
  [Required]
  [Display(Name = "Email"),DataType(DataType.EmailAddress)]
  [EmailAddress]
  public string email { get; set; }
  public SelectList RoleList { get; set; }
  public SelectList CountryList { get; set; }
  public SelectList BUList { get; set; }
}

Note I've excluded properties you don't appear to be editing, used [EmailAddress] rather than your Regex (could not see what the regex was doing that an EmailAddress attribute is not already doing) and used SelectList rather than IEnumerable<SelectListItem> which means you can simplify it to

public ActionResult Create()
{
  var model = new UserRegistrationViewModel();
  var roles = from n in XDocument.Load(....
  model.RoleList = new SelectList(roles, "value", "value");
  ....
  return View(model);
}

and then in the POST method, map the properties from the view model to a new instance of the data model, setting the other properties such as date_from if required (alternatively you could put these default values in a constructor) and save to the database.