ASP.net MVC - One ViewModel per View or per Action? - c#

Is it a better idea to have a single ViewModel per view or one per controller action?
Example:
public ProjectController : Controller
{
public ActionResult Edit(int id)
{
var project = ...;
return View(new ProjectEditViewModel(project));
}
[HttpPost]
public ActionResult Edit(ProjectEditViewModel model)
{
}
**OR**
[HttpPost]
public ActionResult Edit(Project model)
{
}
[HttpPost]
public ActionResult Edit(ProjectEditPostViewModel model)
{
}
}
Here are the three options, which is best?
Use the same ViewModel for my POST/GET actions.
Use a ViewModel for my GET action and my domain model for my POST action.
Use a different ViewModel for GET and a different ViewModel for POST.

Using a different view model for the GET and POST actions is the best and most flexible design. But using the same view model for the GET and POST actions also works in 90% of the cases and it is fine a good design. So if using the same view model works in your scenario don't hesitate to reuse it like this.
In the case where different view models are used for the GET and POST actions there is still some relation between those classes: inheritance or composition.

The correct answer
Neither. There's no silver bullet and shouldn't be.
The correct answer is therefore: use as many view models as your user interface process demands. That's regardless of views or controller actions.
Sometimes an action demands a view, other a view. But don't follow some strict guidelines that would hinder your development. View models will come naturally as you develop your application. And should. Otherwise you may end up with unreasonable views that are based on some guideline you've set in stone.
This is actually a similar answer as #DarinDimitrov's, but with a direct conclusion.

Use different model to receive input parameters in Post action (I don't even call it ViewModel in that case) than to pass output parameters to the view.
That way you can customize exactly what input parameters do you accept.

I follow this approach for basic forms:
One view model for the GET
One view model for the POST
The GET model inherits the POST model.
I will often pass a domain object to the GET model's constructor, and do 2 things with it:
Populate the POST model properties with data from the domain object.
Encapsulate the domain object as a local variable in the GET model. I use this for displaying some (read-only) data from the domain object. Saves a bit of effort. Some people will tell you not to do this.

Related

MVC 5 Bind Implement with all Parameters

So MVC5 has brought in that new Bind attribute, to my knowledge it is used to specify which properties of the parameter object that should be bound to. Also, this is a security measure to help prevent XSS and Model Binding attacks. Most tutorials show it in action against a model.
public async Task<ActionResult> Create ([Bind(Include="Id,Description,IsDone")] ToDo todo)
In my applications I only ever pass view models to and from controllers and views:
[HttpPost]
public ActionResult Create(UserViewModel vm)
{
}
Should I also use this technique here?
[HttpPost]
public ActionResult Create([Bind(Include="property, property2")]UserViewModel vm)
{
}
In all honesty there are very few times where I don't want to bind to every property in the view model.
Firstly, is my understanding of the Bind attribute accurate?
Secondly, is my understanding of when to use the Bind attribute accurate?
You're spot on!
You're also spot on!
You've got a good understanding of what the attribute is intended for. Only you can prevent forest fires know if you should use the attribute. If you're building a data-sensitive application you absolutely want to protect yourself from over posting. If you're building an internal low-risk application, perhaps you can skip the magic strings, trust your users, and not deem it worth your time.
The ASP.NET website has more information about over posting.

FormCollection to Model from code

I'm developing an ASP.NET web application.
In one view, I have a base model (BaseObject) and depending on a combo box selection there are more fields with specific informations to this object (with own model classes like SpecificObject1, SpecificObject2, ...).
To handle the controller action, my idea is to have the following code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Update(BaseObject model, FormCollection fc)
{
...
}
My BaseObject has a property for identifying the specific object, for example: model.SubObjectTypeId
My idea is to have a switch in the controller action and to "cast" the FormCollection to the specific model.
Is there a way to do this automatically or do I need to create helper classes which creates an instance of the specific object class and sets the parameters?
The input fields are having the same names as the properties are namend of the specific object.
PS: I'm trying to avoid using AutoMapper. I prefer built-in solutions by ASP.NET MVC.
Thanks for your help.
Usually in these cases is better to build a ModelBinder a class that has the task to create the correct instance for the controller action. It parses the Form collection and creates the instance to pass to the controller.
This way the controllers are thinner and are more respectful of the SRP. :-)

Is Creating an Instance of a ViewModel in a View ok?

For example I have the Models:
Student and Course.
Student has a List<Course> Courses{get;set;}
All data is already populated from the web service
I have a Student/Index which returns an ActionResult that takes a StudentViewModel
But I also have a Course/Index View which returns an ActionResult takes a CourseViewModel
That should set the foundation for my question:
Is it alright if I follow this option, which I think is very neat and simple:
Create an instance of a ViewModel in the Student/Index View
#foreach(var course in Model.Courses)
{
Html.RenderPartial("path/tocourse",
new CourseViewModel{Course = course}) ;
}
Or should I make StudentViewModel have a List<CourseViewModel>, so I can have:
#foreach(var courseViewModel in Model.CourseViewModels)
{
Html.RenderPartial("path/tocourse", courseviewModel) ;
}
At first glance, the above might look better, but in the Index action (or whatever) it would require me to do the following:
new StudentViewModel{
CourseViewModels = courses.Select(c=>new CourseViewModel{copy stuff}).ToList()
}
I hate that, and also it could confuse me later on or another developer, seeing that another indirection gives me access to Courses i.e StudentViewModel.StudentModel.Courses.
So which one is better approach? Surely it can't be that bad to create an instance of a ViewModel or a Model for that matter in a View?
It's perfectly OK to do this. It's not considered Best Practice. Best Practice would be to do as little processing or instantiation as possible in your View.
For the sake of SOC, I would re-factor this code to use Partials with Child Action Methods
Html.Action("path/tocourse");
The Child Action will instantiate and pass the Model, lightening your View.
[ChildActionOnly]
public ActionResult tocourse()
{
courseviewModel model = new courseviewModel();
return PartialView(model);
}
Ideally your view should not have any viewmodel instance logic rather the controller should do all that stuff and give that model to the view. View should be clean. And viewmodel should only have those properties that you need for the view. Now, you can have a model that is complex enough but if you find yourself that a particular model is very complex for your view, just make a viewmodel specific to that view with limited properties that your view needs.

ViewBag as a holder of session models

This is more of a high-level question than anything else.
I have a MVC project which, among other things, manages users.
I am currently sticking to a more strict approach that on my view pages I only use a model which is declared, meaning that I have a:
#model MVCApp.Models.SomeModel
At the top of each View.cshtml
There are some pages that require more than 1 model. At this point I consolidate the 2 models into 1, and send it to the view as one model.
Here comes the tricky part. Let's say I have some model which holds the user data. That user data is stored in the session cookies (typical Forms Authentication). It seems weird to me that I now have to wrap each and every model I use with my own model that holds both the User Model and the model which I want to use inside that View.
The question that I ask myself is why not pass the User Model to the ViewBag and use it inside the View. Why is that considered to be bad practice? It allows me to attach that model to every page without having to ultimately duplicate all my models.
I'd love to get some guidance. I might be looking at this the wrong way. Any help will be much obliged.
Thanks,
There are a couple of reasons why ViewBag should be avoided:
ViewBag is weakly typed
You don't get Intellisense in the view
Your view is a mixture of ViewBag and a view model and your view gets information from different places instead of centralizing everything into a strongly typed view model
ViewBag doesn't work with strongly typed helpers and expressions because dynamic types cannot be used with extension methods (that's not a limitation of ASP.NET MVC, it's .NET => you cannot dispatch extension methods on dynamic types)
Due to this weak typing nature of ViewBag you will have to cast in your views turning them into spaghetti code because HTML helpers expect specific types to be passed as arguments
... this list goes on (I really don't have time to fill it but it is very large list)
So now that we know that ViewBag is bad and shouldn't be used there are different ways you could solve this requirement by using view models.
One possibility is to use the Html.Action helper which allows you to insert some portion of HTML in the view by going through a full Controller/Model/View lifecycle. This way you could have a commonly used widget without interfering with your main view model.
Another possibility is to have a base view model which will contain a property representing user details and which will be populated by a custom global action filter that could executed everytime a controller action has finished executing and returned a view result. The action filter could intercept this view result, read the authentication cookie information and set the view model property. This assumes that all your view models derive from the common base view model. This obviously makes sense if you need to display this user information on each page.
For example:
public class UserInfoInjectorAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var result = filterContext.Result as ViewResultBase;
if (result == null)
{
// the controller action didn't return any view result => no need to continue
return;
}
var model = result.Model as BaseViewModel;
if (model == null)
{
// the controller action didn't pass a model or the model passed to the view
// doesn't derive from the common base view model that will contain
// the user info property => no need to continbue any further
return;
}
model.UserInfo = ... go ahead and read the forms authentication cookie
userData portion and extract the information
you are looking for
}
}
Now all that's left is to register this action filter as a global action filter and it will be applied on all controller actions.
Now if all your view models derive from this BaseViewModel you will know that once you arrive in the view the UserInfo property will be populated with the relevant information without polluting all your controller actions with code that does the fetching of this property. And still you get strong typing in the view => no ViewBag (youpeeee).
Of course depending on your specific scenario there might be other ways to achieve that (obviously not involving any ViewBag).
You can an ActionFilterAttribute and in those Actions that load views which needs specific ViewBag items, you initialize them.
I don't recommend it, as it will be harder to mantains, but will be a generic approach which may solve your problems.

Beginner mvc where to call methods

I am doing big project in Web Forms and entered a big mess of code(can be solved with little refactoring), so I decided to take a peek at mvc, seems like everyone favores it over web forms.
I have dll file with all LINQ to SQL classes and methods for existing sql db and I started teaching myself by reacreating this project in mvc.I first recreated my homepage from webforms to razor, so far so good and I recreated one of the user controls to partial view and looped it.
Partial view is strongly typed with one of L2S class, the thing is there is some raw data in it.Like for example My model for partial view is my L2S class PostDetails: it consist od some data ready from output like: Title, Permalink, ViewsNumber etc. but it also cointains some raw data like UserId(I need to call method from dll to get username),DateTimeCreated(on which I also need to call method to get time difference), In webforms I would do this in codebehind but I'm not sure where to do it in mvc, maybe in controller and pass it in ViewData.I am also asking this for future, not just this case.
You should perform those actions in the controller. The controller is exactly what it sounds like, it controls the data flow between the model and the view.
Here is an example using your PostDetails:
PostDetailsModel
String Title {get;set;}
String Permalink {get;set;}
Int ViewNumber {get;set}
Int UserId {get;set}
DateTime DateTimeCreated {get;set;}
GetDetailsView: this will be requested by your user, and will be a visual representation of the PostDetailsModel (however you want to format that). When this View is requested, a call is made to your controller....
PostDetailsController
//This method will (by default) come from calling [BASEURL]/PostDetails/GetDetails
public ActionResult GetDetails()
{
var details = new PostDetailsModel();
details.UserId = GetUserId();
details.ViewNumber = GetViewNumber();
....
//By default this looks for a view in the PostDetails folder
//by the name of your method (GetDetails)
return View(details);
}
Notice how the controller is the router between the model and the view, basically. A note, however, it would be better to fill your model from methods contained within some sort of business layer (however you implement that). Something like var details = BL.GetDetails();
Also, when the user makes requests to save data, then you can do that with another method that takes the data (whether it be the PostDetailsModel or an int or...) and does whatever it needs to do, then it can redirect back to the display action (or wherever you need it to go)
There is a wealth of information on MVC with a simple google search. Here is Microsoft's overview, but the wikipedia article is very succinct if you just want the basics
In MVC, All your requests will be handled by an action method in a controller. and then controller returns a view. So you can get the data in your controller (or a different layer which will be called from the controller) and pass that data to your view.
Strongly typed views are a clean way of doing things. Create a ViewModel for your scenario. Mostly ViewModels looks similar to the Entities. Ex : For Displaying the details about a customer, i will create a viewModel called "CustomerViewModel"
public class CustomerViewModel
{
public string CustomerId { set;get;}
public string FirstName { set;get;}
}
Then in my CustomerController, I will have a get method for the customer
public class CustomersController : Controller
{
public ActionResult Details(int id)
{
CustomerViewModel objCustomer=new CustomerViewModel;
objCustomer.FirstName="Samuel";
//Instead of hardcoding the values here , you can get it
// from the database using the id and assign to the properties
return View(objCustomer);
}
}
And you will have a view called "Details.chtml" in your Views\Customer
folder which is strongly typed to your CustomerViewModel
#model CustomerViewModel
<div>
<h2>#Model.FirstName</h2>
<p>#Model.CustomerId</h2>
</div>
This can be accessed like http://yourdomain.com/Customer/Details/25
Personally i prefer to keep my controller actions thin. so i write the GetFromDatabase code in a seperate service layer and i just call that method from my action method
I think that you'll find this article very useful:
MVC Overview
It explains in detail, as to what each component should be used for:
Models. Model objects are the parts of the application that implement
the logic for the application s data domain. Often, model objects
retrieve and store model state in a database. For example, a Product
object might retrieve information from a database, operate on it, and
then write updated information back to a Products table in SQL Server.
Views. Views are the components that display the application s user
interface (UI). Typically, this UI is created from the model data. An
example would be an edit view of a Products table that displays text
boxes, drop-down lists, and check boxes based on the current state of
a Products object.
Controllers. Controllers are the components that handle user
interaction, work with the model, and ultimately select a view to
render that displays UI. In an MVC application, the view only displays
information; the controller handles and responds to user input and
interaction. For example, the controller handles query-string values,
and passes these values to the model, which in turn queries the
database by using the values.

Categories