
 April 12, 2019 12:28 by 
 Peter
 PeterIn this  article, I will explain about getting lookup dataa into you view  ASP.Net MVC 6. This is a super common problem I encounter when building  ASP.net MVC applications. I have a form that has a drop down box. Not  only do I need to select the correct item from the edit model to pick  from the drop down but I need to populate the drop down with the  possible values.
Over  the years I've used two approaches to doing this. The first is to push  into the ViewBag a list of values in the controller action. That looks  like
public ActionResult Edit(int id){  
    var model = repository.get(id);
    ViewBag.Provinces = provincesService.List();
    return View(model);
}
Then  in the view you can retrieve this data and use it to populate the drop  down. If you're using the HTML helpers then this looks like
@Html.DropDownListFor(x=>x.province, (IEnumerable<SelectListItem>)ViewBag.Provinces)
This becomes somewhat messy when you have a lot of drop downs on a page. For instance consider something like
public ActionResult Edit(int id){  
  var model = repository.get(id);
    ViewBag.Provinces = provincesService.List();
    ViewBag.States = statesService.List();
    ViewBag.StreetDirections = streetDirectionsService.List();
    ViewBag.Countries = countriesService.List();
    ViewBag.Counties = countiesService.List();
    return View(model);
}
The  work of building up the data in the model becomes the primary focus of  the view. We could extract it to a method but then we have to go hunting  to find the different drop downs that are being populated. An approach  I've taken in the past is to annotate the methods with an action filter  to populate the ViewBag for me. This makes the action look like
[ProvincesFilter]
[StatesFilter]
[StreetDirectionsFilter]
[CountriesFilter]
[CountiesFilter]
public ActionResult Edit(int id){  
  var model = repository.get(id);
  return View(model);
}
One of the filters might look like
public override void OnActionExecuting(ActionExecutingContext filterContext)  
{
    var countries = new List<SelectListItem>();
    if ((countries = (filterContext.HttpContext.Cache.Get(GetType().FullName) as List<SelectListItem>)) == null)
    {
        countries = countriesService.List();
        filterContext.HttpContext.Cache.Insert(GetType().FullName, countries);
    }
    filterContext.Controller.ViewBag.Countries = countries;
    base.OnActionExecuting(filterContext);
}
This filter also adds a degree of caching to the request so that we don't have to keep bugging the database.
Keeping  a lot of data in the view bag presents a lot of opportunities for  error. We don't have any sort of intellisense with the dynamic view  object and I frequently use the wrong name in the controller and view,  by mistake. Finally building the drop down box using the HTML helper  requires some nasty looking casting. Any time I cast I feel  uncomfortable.
@Html.DropDownListFor(x=>x.province, (IEnumerable<SelectListItem>)ViewBag.Provinces)
Now  a lot of people prefer transferring the data as part of the model; this  is the second approach. There is nothing special about this approach  you just put some collections into the model.
I've always  disliked this approach because it mixes the data needed for editing with  the data for the drop downs which is really incidental. This data seems  like a view level concern that really doesn't belong in the view model.  This is a bit of a point of contention and I've challenged more than  one person to a fight to the death over this very thing.
So  neither option is particularly palatable. What we need is a third option  and the new dependency injection capabilities of ASP.net MVC open up  just such an option: we can inject the data services directly into the  view. This means that we can consume the data right where we retrieve it  without having to hammer it into some bloated DTO. We also don't have  to worry about annotating our action or filling it with junk view  specific code.
To start let's create a really simple service to return states.
public interface IStateService  
{
    IEnumerable<State> List();
}
public class StateService : IStateService  
{
    public IEnumerable<State> List() {
        return new List<State>
        {
            new State { Abbreviation = "AK", Name = "Alaska" },
            new State { Abbreviation = "AL", Name = "Alabama" }
        };
    }
}
Umm, looks like we're down to only two states, sorry Kentucky.
Now we can add this to our container. I took a singleton approach and just registered a single instance in the Startup.cs.
services.AddInstance(typeof(IStateService), new StateService());  
This is easily added the the view by adding
@inject ViewInjection.Services.IStateService StateService
As the first line in the file. Then the final step is to actually make use of the service to populate a drop down box:
<div class="col-lg-12">  
         @Html.DropDownList("States", StateService.List().Select(x => new  SelectListItem { Text = x.Name, Value = x.Abbreviation }))
</div>  
That's  it! Now we have a brand new way of getting the data we need to the view  without having to clutter up our controller with anything that should  be contained in the view.
HostForLIFE.eu ASP.NET MVC 6 Hosting
European   best, cheap and reliable ASP.NET hosting with instant activation.   HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European   Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and   Performace. HostForLIFE.eu security team is constantly monitoring the   entire network for unusual behaviour. We deliver hosting solution   including Shared hosting, Cloud hosting, Reseller hosting, Dedicated   Servers, and IT as Service for companies of all size.
