In MyMainView I have multiple PartialViews.
Each PartialView is strongly typed to a property exposed in MyMainView and each partial view also contains some common information.
eg
public class MainModel
{
public SubModel1 { get; set; }
public SubModel2 { get; set; }
public SubModel3 { get; set; }
public CommonStuff { get; set; }
}
Is there an accepted practice for achieving the sharing of this Common property?
I was thinking of having a property in the SubModel that reffered back to its parent. Is this recommended/not recommended?
eg.
public class SubModel1
{
public int Number { get; set; }
public MainModel ParentModel { get; set; }
}
Main goal here is to avoid loading up the same data over and over again.
For the model I am currently looking at, its a series of LookUp dictionaries that are shared across the View, and used in things like drop down lists.
This post will help you to solve the confusion.
In your case mostly you may have to query the complete model in the main action and feed it to the main view. From the main view pass the main model to the partial views that depends upon both the sub model as well as the common properties using Html.RenderPartial or only the sub models to the partial views those needs only that.
You should use child actions if you are displaying a sub model in a partial view and that partial view doesn't depends upon the main model, simply the partial view is completely independent of the main view.
You can also go for child actions suppose you need apply caching behavior for a particular section.
You can avoid child actions suppose you want to display the same model in two or more partial views in the same view, because you have to query the data again and again.
So the solution is you should judiciously choose child actions or Html.RenderPartials based upon the above comments.
You could use child actions. Phil Haack blogged about them. This way you could encapsulate the entire common functionality into a separate Model/Controller/View lifecycle which is distinct from the main one and embed it as a widget.
Related
I'm trying to refactor an editor screen. The editor's model was the domain model, and I'm moving to a view model for this screen because I need to only allow edit of a couple of fields if the user has a certain role. I want to use the same editor view for both creating and editing the model, though that may be part of my problem.
I've read elsewhere on SO that view models should be simplistic, so there is no need for something like an interface hierarchy in view models. However, how can I use the same strongly-typed view for two different view models, one for create and one for edit, since the view models will have almost-the-same-but-slightly-different properties depending on the user role?
Here's a simplified example using the two view models I created:
public class RequirementCreateView
{
public int Id { get; set; }
public string Name { get; set; }
public string Justification { get; set; }
public string ImpactIfNotFunded { get; set; }
... etc for about 40 properties ...
}
public class RequirementEditView
{
public int Id { get; set; }
public string Name { get; set; }
public string Justification { get; set; }
public string ImpactIfNotFunded { get; set; }
public string Decision { get; set; }
public string Status { get; set; }
... etc for about 40 properties ...
}
The two view models are identical except the Edit model has two extra properties Decision and Status that can only be set by someone with the appropriate role. I use AutoMapper to map from the domain Requirement object to the view model and vice-versa for the create/update action.
However, now that I have two view models obviously I can't use a single strongly-typed editor screen because things like ValidationMessageFor(m => Model.Name) won't work. That led me to consider an interface hierarchy for this set of view models, like so:
IRequirementEditorView --> common properties
|--> IRequirementCreateView --> create-specific properties (none right now)
|--> IRequirementEditView --> edit-specific properties
And then have the editor view screen reference IRequirementEditorView. But again, that goes against the current wisdom on simplistic view models. But then the alternative is to duplicate my editor screen, which violates DRY.
This obviously is a common problem, but I'm stumped right now. Any advice?
Thanks.
Edit I should clarify after looking at some other SO similar posts: when I say I'm using the "same" editor view screen, I am using two separate views, Create.cshtml and Edit.cshtml. Each of these then simply references a partial view that contains the actual editor form like so:
#Html.Partial("Controls/RequirementEditor", Model, ViewData)
That is what I had in place when I was using the domain object as the view model.
Turns out there was another way of thinking about this. Shortly after I posted this question I made a few changes and I'm much happier with the result. Here's what I did:
View model now has additional bool properties AllowDecisionEdit and AllowStatusEdit.
View model has two new IEnumerable properties DecisionsList and StatusList.
1 and 2 are populated in the controller and passed to the appropriate view (create or edit).
The create view calls Html.BeginForm() then calls the partial Html.Partial("Controls/RequirementEditor/Editor"). The edit view does the same but also adds Html.HiddenFor(m => Model.Id) before the partial call to ensure the edit form works properly.
So now I have one edit model, one editor partial form, two separate views (create and edit) that each use the same partial and the same editor, and the functionality is turned on or off in the controller. My approaches above smelled very, very bad and I wasn't happy with either one. Once I did this everything felt right with the world. :)
I have a Service class with a method called GetProducts(). That encapsulates business logic and calls the repository to get a list of products.
My MVC view wants to show that list of products as an MVC SelectList. Where is the correct place for that logic to go. I seem to have 3 options:
Model
The Model should expose a property called ProductSelectList. When the getter of this property is called by the View, the Model should call Service.GetProducts() and convert the result to a SelectList before passing it on.
Plausible argument: The Model should make calls to business logic and the repository. The View should merely render predetermined data. The Controller should not be involved, save for passing contextual data to the Model.
View
The View should contain code that calls Service.GetProducts() directly and converts the result to a SelectList inline.
Plausible argument: The View should call for this data directly as it is specifically for use on the View. There is no need to involve the Model or Controller, as we are calling an abstracted Service method anyway, so anything else just adds extra overhead.
Controller
The Controller should make the call to Service.GetProducts(), convert the results to a SelectList and pass it through to the Model, which should contain a simple ProductSelectList property. The View will access this property for rendering.
Plausible argument: The Controller knows which parameters to provide to the Service method, so it should make the call. The Model should be a simple placeholder for data, filled by the Controller. The View's job is to simply render the data from the Model.
I have a feeling that the correct answer is Model, but the other two make some reasonable points. Perhaps I've muddied the waters by already having a Service class that's separate to the Model?
Would anybody care to share their opinion? Is this just a matter of taste?
I personally subscribe to the logic of Number 3, allowing the controller to populate the Model (or View Model as is sometimes differentiated).
I have my views dumb and only displaying data.
I have my View Models store the information that the View will need, occasionally exposing 'get only' properties that format other properties into a nicer format. If my model needs access to my services, then I feel I'm doing something wrong.
The controllers arrange and gather all the information together (but do no actual work, that is left for the services.
In your example, I would have my controller action similar to:
public ActionResult Index()
{
IndexViewModel viewModel = new IndexViewModel();
viewModel.ProductSelectList = new SelectList(Service.GetProducts(), "Value", "Name");
return View(viewModel);
}
and my view model similar to:
public class IndexViewModel()
{
public SelectList ProductSelectList { get; set; }
public int ProductID { get; set; }
}
With the appropriate part of the view looking like:
#Html.DropDownListFor(x => x.ProductID, Model.ProductSelectList);
This way I'm content that I know where to look if there is an issue with anything and everything has a very specific place.
However, there is no correct way as seems always to be the case with these things. Stephen Walther has a good blog series on MVC tips. In one he talks about the View Model emphasis and although not a SelectList he populates, the SelectList is still data in much the same way his list of products is.
In a classic MVC architecture your Model shouldn't be much more than a container for your view data hence the reason it's often called a ViewModel. A ViewModel is different from the Entity Model(s) that your service layer manages.
Your controller is then responsible for populating your ViewModel from the entity model(s) returned by your service layer.
Due to convenience some developers will use their service layer entities directly in their ViewModels but long term that can lead to headaches. One way around that is to use a tool such as AutoMapper to automate the shuffling of data to and from your ViewModel and entity models.
Here's what a controller might look like. Notice that data such as the SSN does not get exposed to the view since there is a mapping from your Entity Models to your View Model.
public class Customer : IEntity
{
public string CustomerID { get; set; }
public string SSN { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
}
public class CustomerEditViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Country { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string PhoneNumber { get; set; }
}
public class CustomerController
{
[AcceptVerbs (HttpVerbs.Get)]
public ActionResult Edit ()
{
Customer customer = _customerService.GetCustomer (User.Identity.Name);
var model = new CustomerEditViewModel ()
{
FirstName = customer.FirstName,
LastName = customer.LastName,
Address1 = customer.Address.Address1,
Address2 = customer.Address.Address2,
Country = customer.Address.Country,
City = customer.Address.City,
State = customer.Address.State,
Zip = customer.Address.Zip,
PhoneNumber = customer.Address.PhoneNumber,
};
return View (model);
}
}
You're right that there are a number of ways to handle this, and that's even before considering variations like MVP, MVVM, et cetera. Since you're asking about ASP.Net MVC in particular, I will defer to Microsoft:
An MVC model contains all of your application logic that is not
contained in a view or a controller. The model should contain all of
your application business logic, validation logic, and database access
logic. For example, if you are using the Microsoft Entity Framework to
access your database, then you would create your Entity Framework
classes (your .edmx file) in the Models folder.
A view should contain only logic related to generating the user
interface. A controller should only contain the bare minimum of logic
required to return the right view or redirect the user to another
action (flow control). Everything else should be contained in the
model.
In general, you should strive for fat models and skinny controllers.
Your controller methods should contain only a few lines of code. If a
controller action gets too fat, then you should consider moving the
logic out to a new class in the Models folder.
Source
I would say your call belongs in the Model.
One thing to keep in mind is that the SelectList class is specific to MVC only. So in my opinion it shouldn't be included in any business logic, and model classes fall into that category. Therefore your select list should be a part of a view model class instead.
This is the way it works in my projects:
Controller method is called
Controller uses repository (business logic, in other words) to get model data
Controller converts the model data if necessary and creates a view model object
Controller passes the view model to the view
The view displays the data in the view model with limited logic to show or hide things, etc
I'd go with option 3. In general, I'll construct my MVC apps such that the controller makes a call to the service to return a model (or collection of models) which are then passed to the view.
I generally keep my models very thin. They are a flattened representation of the data with validation attributes and that's it. I use a service (or model builder) layer to construct the models and do business logic on them. Some folks embed that into the model, but I find that makes for a messy project.
You definitely don't want the view making any calls to your services.
Update...
I'm assuming that this SelectList is your model. If instead it's a part of your model, then you're right, you should put it in your model. I generally don't like to make it a method call, though. I'd have a property on my model:
public SelectList Products { get; set; }
And have my service or model builder class actually populate it. I don't usually have any data-oriented methods on my models.
I'm going with option 1.
Models are the place to make calls to business logic, et cetera.
View - Should display only what the ViewModel already has been populated with.
Controller - the job of the Controller is to direct the traffic coming in (from Web requests) to the Logic that is responsible for handling the request. Hence the term 'controller'.
There are always exceptions to these, but the best place (structurally) is the Model.
I had this problem when I started into MVC and came up with this solution.
The controller talks to a Service Layer. The service layer contains my Domain models and does all the processing for request from the Controllers. The service layer also returns ViewModels to satisfy requests from the controller.
The service layer calls a repository and gets the entities it will need to build the ViweModels. I often use Automapper to populate the ViewModel or collections within the view model.
So, my view models contain all that is needed by the View, and the Controller is doing nothing but handling request and forwarding them to the appropriate service handler.
I don't see a problem with having view specific items like SelectLists in the view Model either.
None of the above.
In my web layer I basically just have html and javascript views. The model shouldn't leak into the view and neither should the services.
I also have an Infrastructure layer which binds the services and model to the views. In this layer there are ViewModels, which are classes that represent what will be displayed on the screen, Mappers, which do the work getting data from services/model and mapping it to the view model, and Tasks, which perform tasks such as Saving, Updating and Deleting data.
It is possible to put a lot of this infrastructure in the Controllers, similar to the example Todd Smith has given above, but I find for anything other than trivial views the Controller becomes littered with code to load data and populate view models. I prefer a dedicated single responsibility mapper class for each view model. Then my controller will look something like
public class CustomerController
{
[AcceptVerbs (HttpVerbs.Get)]
public ActionResult Edit (int id)
{
return View (CustomerEditMapper.Map(id));
}
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult Save(CustomerEditViewModel model)
{
var errors = CustomerEditUpdatorCommand.Execute(model);
ModelState.AddErrors(errors);
return View ();
}
}
I'm torn between option 1 and option 3. I've ruled option 2 out completely as to me that's polluting the view with procedure calls not just presentation layer work.
Personally I would do it in the model and the getter would call the Service layer but I also subscribe to the belief that the model should only contain the information the view needs to render the page, by not fully containing the data in the model at the time you pass it to the view you are breaking this.
Another option here though would be to avoid tightly coupling the view and model by putting a Dictionary of the Products into the view through a Service Call then using the view to transform the Dictionary to a SelectList but this also gives you the ability to just output the information as well.
I think this boils down to a preference as to where you are happy having your logic.
I use helper #Html.EditorForModel() on all my views.
There is a desire that he skip two fields in my model, but only on this view, the other he must continue to display these fields as usual.
How can I skip these two fields only in this view?
Use the [ScaffoldColumn(false)] attribute.
E.g.
public class Person {
[ScaffoldColumn(false)]
public int PersonID { get; set; }
...
Solution and example sourced from: Pro ASP.NET MVC 3 Framework, Third Edition
I'd recommend writing viewmodels for any view that you want to deviate from default behaviour.
Side note: It's probably a good idea to write a viewmodel for every view, as you get separation of concerns, and it's easier to control the behaviour of each view.
Anyway...
For example, say your model is
class Herps {
public string Name { get; set; }
public int SecretToSomePeople { get; set; }
}
and you don't want to have SecretToSomePeople shown on one of your views, create a viewmodel that doesn't contain SecretToSomePeople
class Herps {
public string Name { get; set; }
}
and use that as the model for the desired view. Make sure you copy to/from the actual model somewhere though.
Strictly speaking, if you don't want to display the fields then they shouldn't be on the Model - the point of Models to to hold exactly the data required for the View.
This came up during one of our retrospectives and wanted some additional feedback and a spot check. We currently have a number of views that enable/disable based on boolean flags (Model.IsNew is an example). I'm of the opinion that views should be as simple as possible and controllers should determine the data for that view, not necessarily how it works. I think views, partial or full, should be -told- what to do and handle that vs the view determining what should be shown/hidden. A very basic example goes as follows but covers both sides of this and is mostly a reflection of what we have ...
A controller has a pair of methods (post/get) called Details. [Get]Details has a single parameter, Id and [Post]Details takes id and a viewmodel. Within the post, the method is ~30 lines long checking for valid model, determining if its new, if a certain value changed (triggers redirect) and so on (I think this is incorrect). The [Get]Details check for empty id, populates the necessary dropdowns, nothing fancy (I think this is right). The detail view itself contains a small bit of logic : If (!Model.IsNew) { RenderAction(History => History.Show(id); } (I think this within an if is incorrect, the Show should know what to display, regardless if its new). The plus to this is the layout for said Detail view isn't done twice. Details/Add would be nearly identical, minus some disabled fields depending on state (maybe these should be partials?) -- the entity could be disabled/deleted making the values editable or not.
Thoughts, opinions, insights?
why not create multiple Views and Actions?
Details
Edit
[HttpPost]
Edit
Create
[HttpPost]
Create
Then they could share a Model object
public ThingModel
{
public Thing Thing { get; set; }
}
or have the Create and Edit actions use a safer (prevent html injection) model which will also let you use the Validation options built in.
public ThingEditorModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public bool IsNew { get { return Id == 0; } }
}
And then for Edit and Create you can create an EditorTemplate (Shared/EditorTemplates/ThingEditor.ascx) that the Create and Edit could share
I think you're on the right track...use the 'main' view for layout and then use Templated Helpers for the 'logic'. Lean on Html.DisplayFor(x=>x.Thing) and EditorFor
You definately don't want the layout in two places.
OK, So i have been watching some MVC vids and reading some bits.
I am new to the entire MVC pattern, and until now have been happily wrapped up in the web forms world!
Like with so many demos it all seems great and I'm sure I'll have lots I dont understand as I move along, but in the first instance...
I can see that you can have a strongly typed view, which gets data from the controller. What happens if I want data in a view from different object types?? Say i want to show a grid of cars and a grid of people, which are not related in anyway??
Thx
Steve
Setup your strongly typed ViewData class with two properties like this
public class MyViewData
{
public IEnumerable<Car> Cars { get; set; }
public IEnumerable<People> People { get; set; }
}
and then fill them in the controller,
Sorry for the duplicate. In good MVC spirit try to use interfaces where possible to make your code more generic
Instead of artificially grouping models together you could keep then separate (logically and physically) and then in the view pull the various pieces together.
Check out this post for the a great explanation of [link text][1].
[1]: http://blog.codeville.net/2008/10/14/partial-requests-in-aspnet-mvc/ partial-requests
You can either pass both objects inside the ViewData hashtable, or create a MyViewViewModel, add two properties, and set them both from your controller.
What I think would be best to do in this situation would be create a class in the Models folder to hold both of these types.
Example:
public class CarsPeopleModel
{
public List<Car> Cars { get; set; }
public List<Person> People { get; set; }
}
Then your view would be:
public partial class Index : ViewPage<MvcApplication1.Models.CarsPeopleModel>
{
}