1

I have an ASP.NET MVC project with entities based on EF6 (model first). So my entities are all auto-generated for me. I have an entity, Site and I just want the user to select a Site before proceeding. I have tried a couple of ways, all of them work, but they seem very messy and unnecessary.

I was curious about the cleanest way to create a DropdownList of Sites, then get the selected site when the form is submitted (by Id or whatever other mechanism is better).

Currently I have:

The index where the user is asked to select a site:

public ActionResult Index()
{
    ViewBag.Sites = new SelectList(db.Sites.ToList(), "Id", "Name");
    return View();
}

The view:

@using (Html.BeginForm("SetSite", "Home"))
{
    @Html.Label("sites", "Site:");
    @Html.DropDownList("Sites", null, new { @class = "selectpicker" });

    <div style="width:100%;height:25px"></div>
    <button class="btn btn-default" style="width:100%">Go</button>
}

And the SetSite action, where the form is submitted

[HttpPost]
public ActionResult SetSite()
{
    if (Request.Form["Sites"] != null)
    {
        Session["Site"] = db.Sites.Find(Request.Form["Sites"]);
        return RedirectToAction("Home");
    }
    else
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
}

A few problems arise from this method. First, I really wanted to take advantage of the @model functionality in razor and point it towards my Site class, but since it's auto-generated, I don't want to go poking around and adding a whole bunch of view properties. (beggars can't be choosers?)

Second, the Request.Form['Sites'] returns a string, and converting it to and int is ugly as hell.

As I mentioned, I'd like to use the @model functionality with Html.DropDownListFor. Is that possible when working with a list of Sites from the DB?

How can I get this done cleanly?

ekad
  • 14,436
  • 26
  • 44
  • 46
Matthew Goulart
  • 2,873
  • 4
  • 28
  • 63
  • 2
    Why don't you use a ViewModel? – Hamid Mosalla Feb 09 '17 at 13:20
  • @HamidMosalla I'm not using a view model because when I look at the auto-generated views created by visual studio, they are able to do what I am trying to achieve by using the model-first classes. In other words, VS was able to use just one class, `Site`, to generate views for CRUD. So why can't I generate a view for choosing a site the same way? I'd like to avoid creating extra classes if I can and also continue the same design patters as the scaffolding. – Matthew Goulart Feb 09 '17 at 13:23
  • 1
    There is not need to use Request.Form for this simple CRUD operation. Go with the @model and follow MVC (Model-View-Controller) structure – Ubiquitous Developers Feb 09 '17 at 13:23
  • @UbiquitousDevelopers I agree with you entirely. My question is, *how do I do that*. I tried defining a model and creating a `DropDownListFor` but I can't seem to figure out how to create the `DroDownListFor` properly, using a model. – Matthew Goulart Feb 09 '17 at 13:25
  • 1
    Never use a data model in your view when editing data - [What is ViewModel in MVC?](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) –  Feb 09 '17 at 21:13

2 Answers2

1

Solution 1:- Controller:-

private List<Country> GetCountries()
        {
            var list = new Entity.Result<List<Entity.Country>>();
            list = _context.Countries.Select(tc => new Entity.Country
            {
                Id = tc.Id,
                Name = tc.Name,
                IsdCode = tc.Code,
            }).ToList();
            return list.Data.Select(x => new Country
            {
                id = x.Id,
                Name = x.Name,
            }).ToList();
        }

HttpGet Method:-

 public ActionResult Add(int id)
            {

                try
                {

                }
                catch (Exception ex)
                {

                }
                finally
                {
                    ViewBag.countryList = GetCountries();

                }
                return View()
            }

View Method:-

@Html.DropDownListFor(x => x.countryId, new SelectList(ViewBag.countryList, "id", "Name"), KahandasDhanji.Common.Localization.Application.Resources.ddlCountry,
                                    new { @id = "ddlCountry", @rows = 1 })

In Http Post Form Submitimg u handle that model value in HTTPPOST Method.

Solution 2:- FormCollection class we can capture the form's values within the controller.

[HttpPost]
public ActionResult Add(FormCollection form)
{           
  string strDDLValue = form["Sites"].ToString();

  return View(MV);
}

Hope Its Work !!!

Dhiren Patel
  • 630
  • 8
  • 16
  • Thank you for your solution! I am trying to implement it. In Solution 2, what do I do if the form value is supposed to be an `int`. Do I have to `Convert.ToInt32(Request.Form["Id"])`? This is ugly to me. Is there a better way? – Matthew Goulart Feb 09 '17 at 13:41
  • there no other way either u can use fromcollection or create viewmodel to handle form data... – Dhiren Patel Feb 09 '17 at 13:55
1

You can use a ViewModel to avoid converting the string value from Request.Form. Below is how your ViewModel class should look like

public class MyViewModel
{
    public MyViewModel()
    {
        this.DropdownItems = new List<SelectListItem>();
    }

    public int SelectedSiteId { get; set; }
    public List<SelectListItem> DropdownItems { get; set; }
}

Change the get action method in your controller as below

public ActionResult Index()
{
    List<Site> sites = db.Sites.ToList();

    MyViewModel model = new MyViewModel();

    foreach(var site in sites)
    {
        model.DropdownItems.Add(new SelectListItem() { Text = site.Name, Value = site.ID.ToString() });
    }

    return View(model);
}

Add @model MyViewModel at the first line in your view code and use Html.DropDownListFor method to generate the dropdownlist

@model MyViewModel

@using (Html.BeginForm("SetSite", "Home"))
{
    @Html.Label("SelectedSiteId", "Site:");
    @Html.DropDownListFor(m => m.SelectedSiteId, Model.DropdownItems, new { @class = "selectpicker" })
    <div style="width:100%;height:25px"></div>
    <button class="btn btn-default" style="width:100%">Go</button>
}

The post action method in your controller should look like below. model.SelectedSiteId will be the selected value of the dropdownlist and the type is int so you won't have to do any conversion such as Convert.ToInt32(Request.Form['Sites']).

[HttpPost]
public ActionResult SetSite(MyViewModel model)
{
    Session["Site"] = model.SelectedSiteId;
    return RedirectToAction("Home");
}
ekad
  • 14,436
  • 26
  • 44
  • 46