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.
Related
I've been able to successfully return a model to a view and display the results in a strongly-typed fashion.
I have never seen an example where multiple models get returned. How do I go about that?
I suppose the controller would have something like this:
return View(lemondb.Messages.Where(p => p.user == tmp_username).ToList(), lemondb.Lemons.Where(p => p.acidity >= 2).ToList());
Does MVC let you return multiple models like that?
And then in the view I have this line at the top of the file:
#model IEnumerable<ElkDogTrader.Models.Message>
And I frequently make calls to "model" in the view.
#foreach (var item in Model)
If there were 2 models, how would I refer to them separately?
Is this possible with multiple models, or is this why people use ViewBag and ViewData?
You can create a custom model representing the data needed for your view.
public class UserView
{
public User User{get;set;}
public List<Messages> Messages{get;set;}
}
And then,
return View(new UserView(){ User = user, Messages = message});
In the view:
Model.User;
Model.Messages;
The ViewBag is useful because it is dynamically typed, so you can reference members in it directly without casting. You do, however, then lose static type checking at compile time.
ViewData can be useful if you have a one-off on your view data types and know the type and will be doing a cast in the view anyway. Some people like to keep the actual typed view pure in a sense that it represents the primary model only, others like to take advantage of the type checking at compile time and therefore make custom models needed for the view.
I believe ViewModel should be the way to go. Within the customary ViewModel, you can reference other models or define all the related domain models in the viewModel itself.
In my HomeController.cs I have some data, which I need to pass to my /Shared/_Layout.cshtml via ViewBag. But I have no idea, how can I do it.
This is my /Shared/_Layout.cshtml
#foreach (var item in ViewBag.Order)
{
<li>#item.Name [ #item.Count ]</li>
}
And here is HomeController.cs
public ActionResult Index()
{
ViewBag.Order = SELECT FROM DB -> ADD TO LIST
}
You don't have access to the Viewbag in the Layout View unfortunately.
You could however use:
PartialView call to a method in a base controller
Simply define a base controller that is a parent for all your controllers. This can also be handy for some error handling by the way.
And in your layout use #Html.Partial("ViewName") to call your base controller.
Use Ajax call
Use javascript in your layout view to execute a controller function that returns the data you need.
Use Session variables instead
since session variables are accesable in layout views.
There are probably more answers too, but I believe these will probably be the most common solutions to your problem.
(If you need any help implementing one of these solutions please give me a sign and I'll explain it more deeply how to do it.)
A fairly common method of passing content to the layout, is to let all ViewModel classes implement a base class (or interface), which will then be the #model of your _Layout view.
Assuming you want to pass on some text MyText to all of your pages:
// My base view model class
public class ViewModelBase {
public string MyText { get; set; }
}
// Some other view model
public class MyOtherViewModel : ViewModelBase {
// other properties
}
// In the _Layout view, implement the base class
#model ViewModelBase
...
#Html.DisplayFor(m => m.MyText)
...
#RenderBody()
...
This way, your _Layout view can work with all the properties of the ViewModelbase class, while whatever view is rendered after that still will have the properties of their child view model - here MyOtherViewModel - available.
Hope that helps!
On a side note, I would not recommend an extended use of ViewBags for passing data to your view in MVC, simply because it has a very low maintainability compared to other methods, due to it not being strongly typed. In my opition, ViewBags does not have any real benefits compared to - for instance - using viewmodels.
As an alternative, you can create a base controller inheriting from the controller and assigning the ViewBag variable to your list in the base controller constructor, like so
public class BaseController : Controller {
public BaseController(){
ViewBag.Order = SELECT FROM DB -> ADD TO LIST
}
}
Then in other controllers, inherit from the base controller like so
public class HomeController : BaseController {
}
This then allows you to assign the view bag for each controller request and the view bag variable will be available in the Layout View.
I myself have used this technique to show a list of car makes that is shown throughout the website.
As a suggestion though, I would implement some form of caching, to save constant calls to the back end.
However if you want to keep the functionality in the home controller you will need to restructure it so that it can be used via an Ajax call using jQuery/Javascript as #counterflux has suggested in their second point
Just to make it clear, my question is how do you CREATE multiple objects using a single view. My ViewModel works fine, I can display multiple objects no problem.
Its been a while between .NET coding (last time I was coding in 2.0). I have created an MVC 4 project and successfully created a ViewModel (displaying data on a single view from multiple objects).
However, I cheated. I populated the database directly. I now face the question in reverse, what is the best practice for creating multiple objects from a single view?
In my example, I have a User, who has a userId. The userId is a foreign key in UserDetails.
Just trying to get back into the swing of it and wondering what you guys do?
There are 6 ways to pass multiple object in MVC
ViewModel
Partial View
ViewBag
ViewData
TempData
Tuple
Each one have there own pros and cons.you have to decide base on your issue in hand.
For more information you can refer code project article on it: How to Choose the Best Way to Pass Multiple Models in ASP.NET MVC
Let me give advantage and disadvantage of View Model
ViewModel :
Advantages
ViewModel allows us to render multiple model types in a View as a
single model.
Great intellisense support and compile time error checking on View
page.
ViewModel is good for security purpose also as Views have only what
they exactly need. Core domain models are not exposed to user.
If there is any change in core domain model, you do not need to
change anywhere in View code, just you need to modify corresponding
ViewModel.
Disadvantages
ViewModels add another layer between Models and Views so it increases
the complexity a little bit. So for small and demo applications, we
can use tuple or other ways to keep the things simple for demo.
Option 1:
The best approach is to use strongly typed views with Model or ViewModel.
For Example, you have two classes User and Education, you want to display all education details of user in a view, you can create a custom view model and pass it to view, where you view is strongly typed view model:
public class User
{
public int UserId {get;set;}
public string UserName {get;set}
-------
------
}
public class Education
{
public int UserId {get;set;}
public int DegreeId {get;set;}
public long Marks {get;set;}
---------------
--------------
}
Now create a view Model like this:
public class EducationViewModel
{
public User user {get;set;}
public List<Education> educationList {get;set;}
}
now pass the ViewModel to View and do this in View:
#model AppNameSpace.ViewModels.EducationViewModel
Tip: Create a folder named ViewModels and put all the viewmodel classes in it.
Option2:
Option 2 is to user ViewBag and pass multiple object from control to your view, ViewBag is accessible when you set some value in it in controller, you can access in the view of that action, after that it is automatically washed out, and its null if you access again it.
you can use ViewBag like this:
ViewBag.Message = "Using ViewBag";
and read value like this in View:
string Message = ViewBag.Message as string;
Option 3:
Option 3 is to store data in TempData, its once read only, means you set value in it, and when you read it, its automatically removed, TempData internally uses Session Variables.You can use TempData like this:
TempData["Key"] = "value";
now you read it in view:
string val = TempData["Key"] as string;
after reading it, it will be automatically removed, but you can keep it if you need it further like this:
TempData.Keep("Key");
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.
Let's say I have a theoretical MVC framework that uses a ViewData object to pass data from the controller to the view. In my controller, let's say I have some code like this (in pseudocode):
function GetClientInfo()
{
// grab a bunch of data from the database
var client = Database.GetClient();
var clientOrders = Database.GetClientOrders();
var clientWishList = Database.GetClientWishList();
// set a bunch of variables in the ViewData object
ViewData.set("client", client);
ViewData.set("clientOrders", clientOrders);
ViewData.set("clientWishList", clientWishList);
showView("ClientHomePage");
}
And then in my ClientHomePage view, I display the data like so:
<p>Welcome back, [ViewData.get("client").FirstName]!</p>
<p>Your order history:</p>
<ul>
[Html.ToList(ViewData.get("clientOrders")]
</ul>
<p>Your wishlist:</p>
<ul>
[Html.ToList(ViewData.get("clientWishList")]
</ul>
This is what I understand MVC to be like (please correct me if I'm wrong). The issue I'm having here is those magic strings in the view. How does the view know what objects it can pull out of the ViewData object unless it has knowledge of what the controller is putting in there in the first place? What if someone does a refactor on one of the magic strings in the controller, but forgets to change it in the view, and gets a runtime bug instead of a compile-time error? This seems like a pretty big violation of separation of concerns to me.
This is where I'm thinking that a ViewModel might come in handy:
class ClientInfo
{
Client client;
List clientOrders;
List clientWishList;
}
Then the controller creates an instance of ClientInfo and passes it to the view. The ViewModel becomes the binding contract between the controller and the view, and the view does not need to know what the controller is doing, as long as it assumes that the controller is populating the ViewModel properly. At first, I thought this was MVVM, but reading more about it, it seems like what I have in mind is more MVC-VM, since in MVVM, the controller does not exist.
My question is, what am I not understanding here about MVC vs. MVVM? Is referring to variables in the ViewData by magic strings really not that bad of an idea? And how does one insure that changes made in the controller won't adversely affect the view?
Your understanding of MVC is wrong, it stands for Model View Controller but you are missing the Model in your example. This is the typed entity that gets passed back to the View to do the rendering. In ASP.Net MVC you would use typed Views that also type the Model within the View so it is checked at compile time. This eliminates the need for magic strings (second part of your question).
In MVVM you have Model View ViewModel. This is a way of binding a ViewModel directly to the UI layer via a View which is used a lot in WPF. It replaces the need for a controller and it's generally a 1-to-1 mapping with the UI. It's just an alternative mechanism that solves the same problem (of abstraction and seperation of concerns) but better suited to the technology.
Theres some useful info here which might help understand the difference.
Best approach to use strongly typed views
Models:
public class ContentPage
{
public string Title { get; set; }
public string Description { get; set; }
}
public class ContentPagesModel
{
public ContentPage GetAboutPage()
{
var page = new ContentPage();
page.Title = "About us";
page.Description = "This page introduces us";
return page;
}
}
Controller:
public ActionResult About()
{
var model = new ContentPagesModel();
var page = model.GetAboutPage();
return View(page);
}
View:
#model Experiments.AspNetMvc3NewFeatures.Razor.Models.ContentPage
#{
View.Title = Model.Title;
}
<h2>About</h2>
<p>
#Model.Description
</p>
for more detail check out here
I case of using string as keys of ViewData - yes, it will be a lot of exceptions if someone will refactor code.
It sounds like your understanding of MVC is very old, probably based on MVC 1. Things have changed tremendously in the last couple of years.
Now we have strongly typed view models, and we have the ability to use expressions in the view, which by default aren't compile-time validated, but they can be for debug purposes (though it slows down the build a great deal).
What's more, we don't pass model data through ViewDate anymore (well, not directly anyways.. it's still passed that way but the framework hides it).