This question already has answers here:
c# mvc model vs viewbag
(5 answers)
Closed 8 years ago.
In a ASP.Net MVC project What are the best practices for deciding when to pass data via the Model or via ViewBag.
In my Model i generally have properties that are used for validation for my entity object.
However in the same Model class i am not sure weather it is good practice to then include properties that are not to do with my business entity but instead the layout of the page. So for example i have many properties that decide weather to render certain parts of my page and messages to display if the users has performed a ajax action.
Below is a sample of code to better explain.
Model
public class MyModel {
[Required(ErrorMessage="The Name field is required")]
public string Name{ get; set; }
public string SaveSuccessMessage {get; set;}
}
View
#model MyNameSpace.MyModel
<div>
Some Content......
Html.TextBoxFor(m => m.Name);
<input type="button" value="Save Changes" onclick="DoAjaxCall()">
</div>
#If(Model.SaveSuccessMessage != null)
{
<div class="myClass">
<a class="close">x</a>
Model.SaveSuccessMessage
</div>
}
When a user saves changes the controller then has to tell the PartialView to display a success message generated on the server. I can do this a few ways such as passing it via ViewBag
if(ViewBag.SaveSuccessMessage != null)
However it seems passing it via the Model as shown in my sample is a better option as it is strongly typed and i have all my data i need in one place. But i am not sure if this goes against the MVC philosophy.
The way im handling my Views does then result in very large Model classes for complicated pages. Is passing data like this via model recommended?
"Best Practice" is to create a ViewModel that includes the data from the Model and any other data (selection lists, etc.) that are necessary to generate the view. Then map the results from the ViewModel back to the Model.
ViewBag is a shortcut to avoid defining a class that seems to be almost exactly like your Model. In practice, you will often find yourself creating a ViewModel for various reasons:
Adding properties to your model that you don't want exposed to the view (e.g. password field of a user object)
Using strongly-typed properties that don;t exist on the model (e.g. select lists)
composite views (data from multiple "models")
etc.
Related
So I'm consuming a RESTFul API to get the data I need. This API returns json and i converted this to C# models. The API returns some general info about a vendor and an array with products. The array of products also consists out of arrays for pricing information and product availability etc...
The problem im facing is that when a product is selected by a user to buy i have to gather specific information out of the different array's. Currently I've made a ViewModel for the data that needs to be send to process the order. This is done by binding the actual data using hidden fields and use a HttpPost from the view, resulting in +/- 30 hidden fields to set the proper data values.
I'm kinda new to MVC and this seems dirty. I thought i would be able to pass the models(for example the VendorModel,ProductModel,PricingModel,AvailabilityModel) from the view(with a POST) to the controller and create the ViewModel(based on the models send) so that i can send that to the API.
Is this actually how it should be done or is my design faulty and should i approach this differently?
A side note: One of the things i found is that most people suggest to use an identifier to get the data you need but the problem is that the API doesn't have the right calls to get Product, Pricing, Availability data based on Id, its just one big object with array's based on the search query.
Edit
So after some information i decided to try out nested models and created a viewmodel like this:
public class TestViewModel
{
public TestViewModel()
{
productInfo = new ProductInfo();
}
public ProductInfo productInfo { get; set; }
}
My view is like this(super simpel):
#using (Html.BeginForm("CreateOrder","Products"))
{
//Vender info etc...
//This is how i render partial view now:
{Html.RenderPartial("Info/ProductInfo", Product.ProductInformation.ProductInfo);}
<input type="submit" value="Order" class="btn btn-default" />
}
My controller(TestViewModel.ProductInfo is always null):
public ActionResult MakeReservation(TestViewModel testViewModel)
{
//Doesnt do anything just debugging TestViewModel
return View();
}
I'm not posting any inputs but just want to pass the modal with the data to the controller. How will MVC know which data to bind, because now it doesnt bind. Do i have to bind it myself somehow?
I had the similar situation and I have one suggestion, you can pass all the models to the view as save in a javascript object as JSON using the example code which I used like below-
<script type="text/javascript">
var pageBlockOptionsJSON = #(Html.Raw(Json.Encode(DesignOrderBlocks)));
var controlTypeJSON = #(Html.Raw(Json.Encode(controlList)));
</script>
Then you can do all the manipulations using jQuery to structure and create a javascript object and post that object to Controller Action. You can create the same or exact structure which is needed on the server. As specified in this url - http://www.nickriggs.com/posts/post-complex-javascript-objects-to-asp-net-mvc-controllers/
In this way you don't need to have use huge amount of hidden fields and you can do all the dirty work on the client side using jQuery.
I am sure this will help you out in doing the thing in the right way. Let me know if you need some details.
For people that somehow find this questions i solved this issue by saving the model to an database as an search result using entity framework. After getting the result i save it and create a viewmodel. After posting i send the id's that entity framework generated and search the right models in the database creating a new postviewmodel.
I'm developing a site in MVC, and I have a payment form which includes customer information as well as payment information. I'm not storing payment info in my database, so I don't want to add any of it to my customer info model. It'd be nice if I could do something like this:
public void PaymentConfirmation(CustomerInfo customer, PaymentInfo payment)
{
//do stuff
}
But I don't think the mvc model binder does anything like that by default. What's the best practice for handling situations like this?
I am assuming that when you say
I'm not storing payment info in my database, so I don't want to add
any of it to my customer info model.
What you mean is that your customer model is a domain model (generated from EF or some other ORM). If not using an ORM, the single responsibility principle still comes into play in that PaymentInfo is really not related to the CustomerInfo and should have its own base class. Not combining these into a big "do everything" class makes sense.
What you can do, however, is create a ViewModel for this particular view that contains all of the information that you need. This will not cause a DB change and is, basically, a simple wrapper for all the data that is needed by the view to do whatever it does. A basic example would be
public class PaymentConfirmationViewModel{
public CustomerInfo Customer {get;set;}
public PaymentInfo Payment {get;set;}
}
As you can see, we are wrapping two stand alone classes into one for consumption by the view/action result. However, using View Models allows you to completely customize and restrict/add the information that is available to your view. Meaning, if there are properties on the domain model that the view does not need, then don't make them part of the view model.
Now, your controller method would be
public void PaymentConfirmation(PaymentConfirmationViewModel model)
{
//do stuff
}
The only other item you would need to change is your view, in that your Html Helpers would need a slightly different lambda expression (random example).
#Html.LabelFor(x=>x.FirstName)
would become
#Html.LabelFor(x=>x.Customer.FirstName)
If you are manually creating your input fields in raw HTML, the the following updates would occur.
<input type="text" id="FirstName" name="FirstName" />
would become (note the underscore in the ID attribute of the input field)
<input type="text" id="Customer_FirstName" name="Customer.FirstName" />
I've come across an interesting question during my development. Right now, I use a database-agnostic unit of work layer to abstract the access of data from the actual database dependencies in my ASP MVC 4 web application.
Each individual database project which implements the unit of work interfaces are aware of my business models (models that go directly to/from the database). I'm not too sure how I feel about this approach, but that's not the question I am going to ask.
Should I be using a solution like AutoMapper to convert my business models to/from domain models - models that are passed to the view and used for any work that shouldn't have access to database fields (i.e., IDs)?
For example, consider inside my BusinessModels project, I have the following classes
BusinessModels
/UserAccounts/
User.cs
- ID
- Username
- HashedPassword
- Salt
UserSettings.cs
- IsSubscribedToNewsletter
- AllowDirectEmails
Would it make any sense to bind these User, and UserSettings models into a single model using AutoMapper like so
MyProject
/DomainModels/
User.cs
- Username
- HashedPassword
- Salt
- IsSubscribedToNewsletter
- AllowDirectEmails
for the purpose of views?
This question also extends to non-MVC projects but I feel seeing as I am working on an MVC project it would make more sense to ask it in that tag.
TLDR is there any point in mapping business models/entities to view models or does that provide an unnecessary layer of abstraction? And if so, would the Repositories contain business models, or view models (which map automatically to business models under-the-hood)?
You can use view models for two different things:
rendering a new view (GET action), passing the view model object as the model for the view
receiving data back from the view, in a Post Action (POST action), using the view model as parameter
(I know, the second is arguable. But it's not strange to use the view models for this)
The model for the GET action needs all the properties neccessary to render the View:
the values of the entity you're showing/editing
extra values needed to render the view (for example SelectLists for drop down lists)
Suppose that you have a User which can belong to one UserGroup.
In this case, if you want to edit the user, the model needs:
the User data
a list of UserGroups
I'd use a model like this:
public class EditUserModel
{
public User User {get;set;}
public SelectList UserGroups {get;set;}
}
As you can see, I directly add the User as a property. But I don't add the list of categories as a property, because I don't need the whole list of categories, with all their properties in the view. Besides, if you unit test the controller you can verify that the SelectList is as expected (that couldn't be done if you created the User Groups list in the view)
But, what if you don't need all the properties of the user in the View? Is it worth removing the User property, and add individual properties for Name, Email, JoinedData, Active... ? I think the anser is NO. Imagine you add/remove or rename some of the User entity properties. If you had individual properties in the view model, you'd have to change them as well, before updating the View. And, if you rely on automatic mapping (auto mapper, value injecter) you would't even realized if you make some mistake.
I also said that the view model can be used for posting back data to the controller. So you could do this:
[HttpPost]
public ActionResult Edit(EditUserModel userModel)
If you do so, the model binder will populate the userModel with the values in the form controls. So you'lll get back a half empty model. In this case, the UserGroups list would be null, and, depending on how many of the User's properties you edit, the User could also have many null/non-initialized properties.
To avoid making errors, in some occasions is advisable to create a different model (and probably auxiliary classes) to make it clear what is expected to be posted to the model.
For example, if you have an action to show the whole user data, but which only allows to change its password, you could create a class with two properties: Password, and PasswordConfirmation.
In this case, the view model for the POST could only have the Password and PasswordConfirmation. And derive a model for the GET which has this inherited properties, and also the list of User Groups and the User.
Why inheriting and not using independent classes? Simply beacuse when you use something like Html.TextBoxFor(m => m.User.Name), the Model Binder will be able to set the Name property of the User property, only if the parameter for the post action has the same structure. I.e. if the view model for the get has this structure:
public ChangePasswordModel
{
public string Password {get;set;}
public string PasswordConfirmation {get;set;}
// extra properties, like the list of user groups, the user data...
}
And the model for the post has this structure:
public PostedChanegPasswordModel
{
public User User {get;set;}
}
The content of the input rendered by Html.TextBoxFor(m => m.EditedUser.Name) won't be bound to the User.Name of the PostedEditViewModel.
But if you make this:
public EditUserModel : PostedEditUserModel
{
// extra properties, like the list of user groups
}
the data will be bound without any problem.
In general you have to be careful with the models you use for posting and getting. And I recommend using as many different view models as neccesary.
When to use automatic property mapping to completely new view and different models?
You must have a very strong reason to have different view models. This could be a result of starting the application from outside in (i.e. design first) or because a team is developing the UI before or while the business logie is being implemented.
In this case you can find that the classes for the view models, and the views themselves are already defined, and are quite similart to your entities, but not exactly equal. This is one case when I think it can be good to use mappers.
The other reason to use different classes would be to decouple the interface from the logic. But this usually only happens in the previous case.
Regards viewmodels I treat them like a summary of the data you wish to work with.
So taking from your example, your viewmodel would contain data from both the User and UserSettings classes. Let's say you had a view named UserData.cshtml then I would code it up like so:
public class UserDataViewModel
{
public string Username { get; set; }
public bool AllowDirectEmails { get; set; }
// etc ...
}
public ActionResult UserData()
{
var viewModel = new UserDataViewModel();
viewModel.UserName = "Whatever";
viewModel.AllowDirectEmails = false;
// Or however you get the data for the user.....
return View(viewModel)
}
Hopefully you get the idea. So you are on the right track with merging information from externals classes into one viewmodel class. Bascially tie everything together in the viewmodel class.
I name the viewmodel class the same as the view that it's going to be used for. This can help documentation, as well as make it easier for devs new to the code to follow.
I'm hoping you guys can answer me a question?
I've only just started out using ASP.NET MVC3 have come unstuck at a certain point. I've been learning this stuff from books and I'm slightly unsure on a few things.
Can a VIEW, only have one #Model reference?
At the moment I have a VIEW setup with a HTTP-POST on a ViewResult, that validates the data in the View, entered by the user and then "on post", passes this info to a method that writes it back to a database(ADO.NET - Access). Now I need to change my VIEW, so that I can replace a couple of my text boxes for Dropdownlistfor controls. The Data to populate these controls will need to be passed in from the Database.
Would I be correct in saying that this data needs to be passed in the HTTP-GET Viewresult of the page, and if so, can i reference more than one #Model in this same View (*.cshtml).
I have a class that takes in the user response, and this is referenced in the View. But will i need to create a new class for the dropdownlist data and reference that too. So that in the background I populate the data into a SelectListItem, pass it to the View and then populate each drop down control within the view?
I'm sorry if this is poorly written, very hard to explain, I find learning from books hard and I'm pretty stuck now. Any help would be appreciated. Just to give me an understanding of how this all wraps around. I'm comfortable with the C# syntax, but very unsure of MVC3!
There are two ways you can handle this.
Use a View Model.
In this scenario you have a class that contains your data model as well as other things required by the view, so something like this:
public class ViewModel
{
public MyDomainModel Model { get; set; }
public IEnumerable<SelectListItem> SelectListItems { get; set; }
}
Use ViewBag.
In this case you add everything extra into the ViewBag dictionary. So in the controller, you'd have stuff like this:
ViewBag.SelectListItems = new SelectListItem[] { ... };
Then you can reference in the view itself
#Html.DropDownList("myselectlist", ViewBag.SelectListItems)
I think that this will help you pluralsight mvc3 intro. It sure helped me
I have one class like
public class Questions
{
public long ID { get; set; }
public string questionText { get; set; }
public int questionType { get; set; }
}
Now when various questions are created in the view and submitted, what should be the controller's action code and how should I design my view so that I can get the list of questions with all the properties set directly?
Thanks in advance.
Model binding to IList<T>
I've written about model binding to IList<T>. I think this is exactly the problem that you're trying to solve. And there are some more posts on my blog that may help you lots especially because you didn't say whether you're having an HTML form of questions or Javascript objects built by some generic question form. Anyway. These two posts will help you address both problems:
Asp.net MVC model binding to IList<T>
Sending complex JSON objects to Asp.net MVC using jQuery Ajax
By understanding Asp.net MVC model binding you will be able to easily bind your client-side data (forms or objects) to:
public ActionResult AddQuestions(IList<Question> questions)
{
// process questions
}
Suppose you're posting back an HTML form
The main requirement is that you index your HTML field names correctly, because names are those that get posted back to server. In your case your fields should be:
<input type="text" value="questions[0].questionText" />
<select name="question[0].questionType">
<!-- options -->
</select>
When you dynamically add new pairs (to form new questions) you have to make sure:
item indexing starts with 0 and
there are no gaps in indexes.
If you also provide the ability to remove certain questions (while adding/editing them), you will have to reindex items on each removal.
Model validation (forms or correctly prepared objects)
The great thing about doing it this way is that you can put data annotations attributes to your application model class and get your posted objects automatically validated, so you don't have to do this yourself.