How do you wire lists/collections on view models using IoC, DI, and MVC?
I'm working with an MVC project, trying to implement IoC and DI. Both these are fairly new to me, so my apologies in advance if I'm completely going down the wrong road, or if my question is not worded clearly.
Suppose I have a view that needs to display an address form, one of the elements being a drop down list of states. (I realize an address outside the context of something else is not likely, but for the simplicity of an example, assume that is the case here.)
Suppose this is my view model:
public class AddressList {
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public List<string> States { get; set; }
public string Zip { get; set; }
}
Whose responsibility is it to populate the States list?
Should the controller do this, having had a service injected into it for getting the states? If so, does this same injection and population logic go in each of my controllers needing to populate an address? Or should it go somewhere else?
At what layer does this view model belong? If this view model is very specific to a given view in my app, shouldn't this also remain in my app, and therefore not used to pass into a service for populating the states?
I've searched for a few hours开发者_JAVA技巧 trying to find a good example of doing this, and am finding very little help. So I'm wondering if this is a wrong approach to begin with. If so, I'm certainly open to going about it differently.
I'm currently working with ASP.NET MVC2, Unity, and EF4, so any examples using those would be great. However, any examples would probably steer me in the right direction.
Thanks in advance.
EDIT: Sorry, but I think I may have just stumbled on what I'm looking for -- model binding:
http://www.dominicpettifer.co.uk/Blog/39/dependency-injection-in-asp-net-mvc-2---part-2--modelbinders-viewmodels
Is this what I need? Will this work with Unity (I see the examples here use Castle Windsor)?
Like other application boundary data structures, ViewModels are best modeled as data structures with a bit of behavior. The Controllers' responsibility is to load data and populate the ViewModels.
Thus, you should inject the necessary services into the Controller and use those services to populate the ViewModel.
What you need, does not have to be as complex as your explanation. To start with, in your model, you will not have to put list of states. So in your model you should have
public String State { get; set; }
Then in your view - assuming you have a strongly typed view to the AddressList, you have the below for the state
<div class="editor-label">
<%: Html.Label("State") %>
</div>
<div class="editor-field">
<%= Html.DropDownList(
"State",
new SelectList(Html.StateDropDownList(HttpContext.Current), "State",
"State", Model.State != null ? Model.State : null),
new { id = "State", width = "80px" })
%>
</div>
<div>
<div>
Note my extension method StateDropDownList, which could be implemented as follows; this is where the Ioc/DI thing can come in:
public static IEnumerable<State> StateDropDownList(this HtmlHelper htmlHelper, HttpContextBase current)
{
var stateList = current.Application.Get(Constants.General.StateNames) as IEnumerable<State>;
if (stateList == null)
{
var stateService = ((IIocContainer)current.Application["container"]).Resolve<IStateService>();
stateList = stateService.GetStates();
current.Application.Set(Constants.General.StateNames, stateList);
}
return stateList;
}
Note: IIocContainer can be replaced by wither a concrete type or the interface type for the Ioc in use. In addition, I did not use StateID, because you actually used State value (string) in your AddressList model, however, I believe using StateID, can be better and the dropdown will then change to:
<div class="editor-label">
<%: Html.Label("State Name") %>
</div>
<div class="editor-field">
<%= Html.DropDownList(
"StateID",
new SelectList(Html.StateDropDownList(HttpContext.Current), "StateID",
"State", Model.StateID != null ? Model.StateID : null),
new { id = "StateID", width = "80px" })
%>
</div>
<div>
<div>
I believe most you queestions must have been answered by the above, but if not, let me take the questions here now:
"Whose responsibility is it to populate the States list? Should the controller do this, having had a service injected into it for getting the states? If so, does this same injection and population logic go in each of my controllers needing to populate an address? Or should it go somewhere else?"
-- Ideally you will have this list in your datastore as part of reference data. So, each time you need the list, you can use the StateDropDownList extension method to retrieve it, and then bind to the Dropdown as I have put above. Since the list can be used in many place, you need not put the retrieval in a particular controller.
Whose responsibility is it to populate the States list?
Typically the Controller
Should the controller do this, having had a service injected into it for getting the states? If so, does this same injection and population logic go in each of my controllers needing to populate an address? Or should it go somewhere else?
Yep Controller.
Service injected in the constructor. Yes every controller that needs this. If you find there are many you should consider using a single StateController with a PartialView
精彩评论