0

I am very new in MVC and my previous experience was asp.net web forms, now i am getting difficulty to add Validation for @Html.DropDownList and @Html.DropDownListFor in Razor using C# asp.net mvc code first approach

Below is my design:

   <div class="form-group">
        @Html.LabelFor(model => model.State, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownList("States", new SelectList(ViewBag.States as System.Collections.IEnumerable, "StateId", "StateName", new { @class = "control-label col-md-2" }), "Select a State", new { id = "dd_State" })

        </div>
    </div>

      <div class="form-group">
        @Html.LabelFor(model => model.City, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(Model => Model.City, new SelectList(Enumerable.Empty<SelectListItem>(), "CityName", "CityName"),"Select a City", new { id = "dd_City" })
            <span id="span1" name="span1"></span>
          </div>
      </div>

Below is my Models code Register.cs and not able to add require fields of State and City

  [Table("Register")]
public class Register
{
    [Key]
    public int Sno { get; set; }
    [Required(ErrorMessage = "Name is required.")]
    [Display(Name = "Full name")]
    public string Fullname { get; set; }
    [Display(Name = "Email Id")]
    [Required(ErrorMessage = "Email is required.")]
    public string EmailId { get; set; }
    [Required(ErrorMessage = "Password is required.")]
    public string Password { get; set; }
    [Required(ErrorMessage = "Mobile is required.")]
    public string Mobile { get; set; }
    [Required(ErrorMessage = "Address is required.")]
    public string Address { get; set; }
    public string State { get; set; }
    public string City { get; set; }
    [Required(ErrorMessage = "Entity is required.")]
    public string EntityType { get; set; }
    public string Website { get; set; }
    public string PinCode { get; set; }
    public string accountactivated { get; set; }

}

Also i am not able to add bootstrap css to @Html.DropDownList and @Html.DropDownListFor please check dropdown look.

enter image description here

My State and city model class.

enter image description here

enter image description here

mazhar
  • 85
  • 1
  • 12
  • You have multiple issues with your code, including [Can the ViewBag name be the same as the Model property name in a DropDownList?](https://stackoverflow.com/questions/37161202/can-the-viewbag-name-be-the-same-as-the-model-property-name-in-a-dropdownlist). And to correctly implement cascading dropownlists, refer [this DotNetFiddle](https://dotnetfiddle.net/1bPZym) (you do not use `Enumerable.Empty()` in the view) –  Jul 27 '18 at 12:22
  • Your given url data is not coming from database and i refer this url : https://yogeshdotnet.com/custom-user-registration-form-in-entity-framework-code-first-and-asp-net-mvc-example/ for cascading already spent much time on this and is it not posible using my code. @StephenMuecke – mazhar Jul 27 '18 at 12:29
  • The first part of your comment makes no sense - the link I gave you explains that you cannot use the same name for the property your binding to and the `SelectList` - i.e. they cannot both be `States` in your case). And the link you have used is complete nonsense (written by someone who does not know what they are doing) –  Jul 27 '18 at 12:37
  • Please check my updated question mention state and city model classes and using code first approach using entity framework, check tell me i am going correct way or not. @StephenMuecke – mazhar Jul 27 '18 at 12:48
  • Study the DotNetFiddle (how you get the data is irrelevant) –  Jul 27 '18 at 12:51
  • What exactly are you trying to validate? That it's required or that the city exists within the state? There's no explanation in your question. You're using your domain model as your view model? That's a dangerous practice. – Jim Berg Jul 27 '18 at 12:51
  • Do you want those fields to be required on the form, just not in the database? That's the very reason you should be using a view model instead of your domain model. – Jim Berg Jul 27 '18 at 12:55
  • K thank you so much for your best suggestion for my registration form, i will work as you given url : https://dotnetfiddle.net/1bPZym according will create my registration form with cascading drop down list and sorry i am very new gone with wrong root. @StephenMuecke – mazhar Jul 27 '18 at 12:57
  • if i will use this url means its is good for cascading dropdown: https://www.aspsnippets.com/Articles/Cascading-Dependent-Country-State-City-DropDownLists-using-jQuery-AJAX-in-ASPNet-MVC.aspx . @StephenMuecke – mazhar Jul 27 '18 at 13:01
  • That is better code (although it could be improved a bit) –  Jul 27 '18 at 13:12
  • Ok thanks i will use as you given url and one more question that is using code first approach?. @StephenMuecke – mazhar Jul 27 '18 at 13:36
  • That is irrelevant. It makes no difference if you use EF with code first or database first or just ADO.Net. The main thing is that your editing data, so you use a view model, not the data model in the view (refer also [What is ViewModel in MVC?](https://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc)) –  Jul 27 '18 at 13:47

2 Answers2

1

Your problem is that you should NOT be using your EF domain model as your view model. You should create a view model that is specific to the needs of your view. You can then specify State and City as being required without having to make those values required in your database.

Your domain model should be as simple as:

[Table("Register")]
public class Register
{
    [Key]
    public int Sno { get; set; }
    [Required(ErrorMessage = "Name is required.")]
    [Display(Name = "Full name")]
    public string Fullname { get; set; }
    [Display(Name = "Email Id")]
    [Required(ErrorMessage = "Email is required.")]
    public string EmailId { get; set; }
    [Required(ErrorMessage = "Password is required.")]
    public string Password { get; set; }
    [Required(ErrorMessage = "Mobile is required.")]
    public string Mobile { get; set; }
    [Required(ErrorMessage = "Address is required.")]
    public string Address { get; set; }
    public string State { get; set; }
    public string City { get; set; }
    [Required]
    public string EntityType { get; set; }
    public string Website { get; set; }
    public string PinCode { get; set; }
    public string accountactivated { get; set; }
}

Then your view model can look like this:

public class RegisterViewModel
{
    public int Sno { get; set; }
    [Required(ErrorMessage = "Name is required.")]
    [Display(Name = "Full name")]
    public string Fullname { get; set; }
    [Display(Name = "Email Id")]
    [Required(ErrorMessage = "Email is required.")]
    public string EmailId { get; set; }
    [Required(ErrorMessage = "Password is required.")]
    public string Password { get; set; }
    [Required(ErrorMessage = "Mobile is required.")]
    public string Mobile { get; set; }
    [Required(ErrorMessage = "Address is required.")]
    public string Address { get; set; }
    [Required(ErrorMessage = "State is required.")]
    public string State { get; set; }
    [Required(ErrorMessage = "City is required.")] 
    public string City { get; set; }
    [Required(ErrorMessage = "Entity is required.")]
    public string EntityType { get; set; }
    public string Website { get; set; }
    public string PinCode { get; set; }
    public string accountactivated { get; set; }
 }

Now city and state will be required for entry on the form but not required in the database. An a migration will not be created for this class unless you add it to your context which is what you don't want to do.

Now you can just load the values you need for the view to work when for the HttpGet Action and move just what you want to save back into your entity to save it.

If a malicious user learned that you were using domain models as your view models, they could poke data into properties by simply adding elements to the form in the browser with the same name as the properties you don't think you're exposing. The other reason is that you must make sure each value in your model is returned to the controller or values will be cleared from the model when posted back. You can only do this by putting those values into inputs with names. That would give the malicious user all they need to figure out what to change.

It is a better practice to use separate view models specific to presentation of data. Then map the data from the view model to the domain model and vice versa.

Jim Berg
  • 609
  • 4
  • 7
  • I use this example for my registration: https://yogeshdotnet.com/custom-user-registration-form-in-entity-framework-code-first-and-asp-net-mvc-example/. @Jim Berg – mazhar Jul 27 '18 at 13:34
  • the above url is wrong way to develop code fist application. @Jim Berg – mazhar Jul 27 '18 at 13:35
  • @mazhar Are you asking me or telling me? Code first is about how you develop your domain models as classes and then add a migration to your database based on the classes you create. There's nothing wrong with what you did in that respect. You should have domain model classes (what you use to manipulated data in the database) and view model classes (what you use to communicate to your views). They should not be the same thing for the very reason you're encountering. – Jim Berg Jul 27 '18 at 14:01
  • Please tell what should to next and Stephen is saying use some different example. @Jim Berg – Mr doubt Jul 27 '18 at 19:44
0

Try the below code. By adding new { @class = "form-control" } inside the DropDownListFor method, this should resolve the styling issue.

With regard to validation, you just need to add the required attribute over City/States and this should render the dropdown without "Select City/State" placeholder.

     <div class="form-group">
        @Html.LabelFor(model => model.City, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(m => m.City, Utility.GetCityList(), new { @class = "form-control" })
            @Html.ValidationMessageFor(model => model.City, "", new { @class = "text-danger" })
        </div>
    </div>

For dropdowns for countries/cities etc that I may use more than once, I put them in a Utility class inside Models folder, and reference my Utility at the top of my view like this:

    @using SampleApp.Models

In the Utility class, I will have a method like below that returns the SelectList to the dropdown.

    public static IEnumerable<SelectListItem> GetCityList()
    {
        IList<SelectListItem> list = new List<SelectListItem>
        {
            new SelectListItem() {Text="New York", Value="New York"},
            new SelectListItem() {Text="London", Value="London"}
        };

        return list;
    }
mulldev
  • 43
  • 6