Best way to populate SelectList for ViewModel in GET / POST

I have the following ViewModel:

public class EditViewModel { public int FooType { get; set; } public IEnumerable<SelectListItem> FooTypes { get; set; } } 

I initially populated it in my Edit action as follows:

 public ActionResult Edit(int id) { EditViewModel model = new EditViewModel(); model.FooTypes = new SelectList(repository.GetFooTypes(), "Id", "Value"); return View(model); } 

When I created the action for POST, I had to repeat the same code:

 public ActionResult Edit(int id, EditViewModel model) { if( !ModelState.IsValid ) { model.FooTypes = new SelectList(repository.GetFooTypes(), "Id", "Value"); return View(model); } return RedirectToAction("Index"); } 

I don't like having this code in two different places. Is there a common practice for refactoring this in one place, so I don't need to repeat this code?

+3
source share
3 answers

Given that C # is an object-oriented language, there are many options available.

The simplest would be to simply wrap it in a method inside the controller:

 private SelectList GetFooTypesList() { return new SelectList(repository.GetFooTypes(), "Id", "Value); } 

and call it when setting up the model

or if you use it in several classes, you can create a helper method in another class that takes a repository or IEnumerable as a parameter.

If you want a really advanced way, you can use ModelFactory to create a FooType model for you with the FooType property pre-populated so that the dispatcher does not have to worry about it at all.

There are many options, you just need to choose the one that is best for you.

My personal preference is a simple helper method in the controller.

0
source

I did this in the model before (when it was coding practice for this project team), but it depends on your philosophy on what “business logic” and “data access” are, and what belongs to the model against the controller. There are different and justified opinions.

A model where you need a NULL type for FooType:

 public class EditViewModel { public int? FooType { get; set; } public IEnumerable<SelectListItem> GetFooTypes(object selectedFooType = null) { return new SelectList(repository.GetFooTypes(), "Id", "Value", selectedFooType); } } 

Get, where you need to first create a model so that the Model property is available in the view:

 public ActionResult Edit(int id) { EditViewModel model = new EditViewModel(); return View(model); } 

View (without Barbara Vava):

 @Html.DropDownListFor(m => m.FooType, Model.GetFooTypes(Model.FooType)) 

An alternative that draws a “view” from a model might look like this:

Model:

 public class EditViewModel { public int? FooType { get; set; } public IEnumerable<int?> FooTypes { get { // declare/define repository in your model somewhere return repository.GetFooTypes(); } } } 

View:

 @Html.DropDownListFor(m => m.FooType, new SelectList(Model.FooTypes, "Id", "Value", Model.FooType)) 
0
source

In the answer "nekno" (answered September 30 at 22:19) there are two alternatives to ViewModel that either return "IEnumerable <SelectListItem>", or 'IEnumerable <int? > '. Both of these alternatives use the repository, but without creating it, so I would like to expand the sample code a bit and choose the second option, that is, the class with the property "IEnumerable <int?>",

 using Microsoft.Practices.ServiceLocation; // ServiceLocator , http://commonservicelocator.codeplex.com/ using MyOwnRepositoryNameSpace; // IRepository public class EditViewModel { public int? FooType { get; set; } public IEnumerable<int?> FooTypes { get { return Repository.GetFooTypes(); } } private IRepository Repository { get { return ServiceLocator.Current.GetInstance<IRepository>(); } } } 

The above kind of code with "Dependecy Lookup" now uses a dependency on the third part library, in this case, the Common Service locator library.

My question is how to replace the above code with "Injection of Dependency"? The ViewModel model itself would indeed be very trivial to implement, like this:

 using MyOwnRepositoryNameSpace; // IRepository public class EditViewModel { private readonly IRepository _repository; public EditViewModel(IRepository repository) { _repository = repository; } public int? FooType { get; set; } public IEnumerable<int?> FooTypes { get { return _repository.GetFooTypes(); } } } 

The problem is how to force the ViewModel to be injected into the implementation when the ASP.NET MVC structure creates an instance of “EditViewModel” and sends it as an argument to the action method, such as the signature of the tihs method:

 public ActionResult Edit(int id, EditViewModel model) { // How do we make the framework instantiate the above 'EditViewModel' with an implementation of 'IRepository' when the Action method is invoked ??? 

The official MVC guide does not seem to give anything good as far as I can see. In the section “Processing Changes” (methods “Public Action ActionResult Edit (...)”) on the following pages, they duplicate the creation of parameters in the same way as in the poster of this stack question that you are currently reading.

http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-5

http://mvcmusicstore.codeplex.com/SourceControl/changeset/view/d9f25c5263ed#MvcMusicStore%2fControllers%2fStoreManagerController.cs

If there is a decision on how to make a model for introducing a presentation model with your data retrievers (for example, a repository), I believe that some implementation of "IModelBinderProvider" or "IModelBinder" can be used, but I experimented with them without real success ...

So, can anyone provide a link to a complete working example with ASP.NET MVC 3 code that allows you to embed a data retriever in the view model constructor, which creates an instance of the frame and will send as an argument to the action method?

Update 2012-01-01 : For those who are interested in resolving this specific issue of introducing a ViewModel instance constructor, when the environment instantiates an object and sends it as an argument to the MVC Action Method parameter, I created a new question with a more specific subject and, therefore, I hope it is more likely that someone with the solution will find it and post a good answer: Embedding the constructor of the View Model instance used as the parameter of the action method

0
source

All Articles