How to create a complex view model in ASP.NET MVC? - c#

Creating and updating a complex view model is what I struggle with most of the time when I'm working on a web project.
For instance, I got a PageViewModel that takes a background image URL and a page title to pass to _Layout.cshtml, so
#model WebApplication.ViewModels.PageViewModel
<body background-image=#Model.BackgroundImageUrl>
...
</body
As for every other view model I now got 2 options:
Derive from PageViewModel
Create a property on PageViewModel to hold the specific view model (composition over inheritance etc.)
For obvious reasons I'm more inclined towards option 2. In any case, for GET actions I now need to initialise all the properties from PageViewModel as well as the properties from the view model I actually need for a particular action, e.g.
public PageViewModel
{
public string BackgroundImageUrl { get; set; }
public ContactViewModel Contact { get; set; }
}
is created like
public IActionResult Contact(int contactId)
{
...
var viewmodel = new PageViewModel
{
BackgroundImageUrl = ...,
ContactViewModel = new
{
...
}
}
}
which to me is a recipe for disaster.
Things get even worse on POST, because ideally I will post only those fields that are relevant to the action in question, that is
public IActionResult Contact(ContactViewModel viewmodel)
{
if (ModelState.IsValid)
{
... (this is the easy case)
return RedirectToAction(...)
}
... (now we have a problem)
}
If anything goes wrong in the POST action I need to rebuild the entire view model graph, which is not too bad for the above example but in a real world application this gets extremely messy very fast (just think of populating drop down lists with data from a store). Controller actions are supposed to be lean, aren't they? It doesn't feel right to make the view models responsible for retrieving their own data either, so probably I should come up with a view model factory. That in turn will produce a plethora of factories, one for each view model which, again, will get messy.
I'm wondering if there is a better approach.

One possibility to consider is to use a child action responsible for some portion of the layout.
So for example you could have the following child action which will be responsible for populating the background image URL:
[ChildActionOnly]
public ActionResult BackgroundImage()
{
var model = new MyViewModel
{
BackgroundImageUrl = ...
};
return PartialView(model);
}
and then have a corresponding partial view:
#model MyViewModel
<img src="#Model.BackgroundImageUrl" alt="" />
which can be included in your main Layout (which in this case doesn't need a view model because the different portions of it will be assembled from the child actions):
<body>
#Html.Action("BackgroundImage", "SomeController")
...
</body>
Using this approach the main action that is responsible for rendering the view doesn't need to know and assemble a complex view model. It will focus only on its specific view model.

Related

What's the best way to return List of data from controller [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I have a List<MyModel> that I am returning from controller to view
Shall I create a new class to hold this List and return object of the new class or I can return the List itself..
which one is a better programming practice ??
It depends on what your exact requirements are, consider the below two scenarios.
Using MVC webapi with any js framework like angular/jquery or returning partial view.
You just want to bind the list to a grid and that grid will be updated with new data from same controller action. In this scenario its better to return the list instead of view model, this will ensure that only required data is sent back to view.
``
[HttpPost]
public List<string> Index(string txtJsonIn)
{
return new List<string>();
}
Using MVC without any js/ajax calls
In this case the view will be loaded with values from ViewModel everytime, so if you just keep the List as your return value from action, it will be hard to add new property in future.
class MyViewModel
{
List<string> MyList { get; set; } //Your list that you need right now
string PropertyThatCanBeAddedInFuture { get; set; }
}
[HttpPost]
public MyViewModel Index(string txtJsonIn)
{
return new MyViewModel();
}
You can write the view as below
#foreach (string str in Model.MyList)
{
<tr>#str</tr>
}
Also using viewModels is always a good way to have loose coupled code, don't directly use any model from database, instead use Automapper to map your viewmodel to models from database.
In a partial view I have often used an IEnumerable where there is repeating logic
#model IEnumerable<Result>
#foreach (Result res in Model)
{
<div data-id="#res.ID">
<p>
<!-- Code goes here -->
</p>
</div>
}
View-model is just a conceptual term in MVC's presentation layer. Technically it's just a concrete class.
So real question here whether to use View-model/class or directly pass List.
Now back to the point - Wrapping 'only' list in another class will yield nothing unless you have few other members to be wrapped and passed to view. If there's something more than a List that your view needs, create a class (call it View-model in MVC) to wrap all that stuff and pass it to view.
There is really no reason to create a view model other than personal preference if you just have that one property UNLESS there is any chance that you will be adding more properties in the future.
However it is best practice to utilize interfaces whenever possible to keep your code decoupled. That said you should switch it to IEnumerable instead of list.
I always create a viewmodel, to pass data to my view, populate it in your controller and then pass it to your view. This is a clean way of working in MVC.
TIP : Make a new folder ViewModels in your Models folder.
The same way with Entities, never directly use your entities , use viewmodels that provide just the things you need in your views. Also take a look at Data Annotations , these can come in handy when using a viewmodel for form validation etc...
you can just create a viewmodel like Jelman said and in it just declare a list of your model like this by creating another class file in your model folder that is going to contain your list of model
namespace projectname.Models
{
public class ModelNameViewModel
{
public List<ListOfModel> { get; set; }
}
}
or you could simply Change the declaration on the top of your view to have a list of your model like this if there is no other field you need to add to the model
#model List<YourModelName>
While you can return that model to the view, chances are that not all data will be used in the view. Therefore we create view model classes which only hold data relevant to the view and we use a mapper (take a look at AutoMapper) to map between the two objects.
While this adds another class to manage, it keeps the domain model nice and clean and without any "view specific" properties (such as lists used in drop-downs etc.)
What you end up returning will end up being whatever you need in the view, as you might want to have some other data (or metadata) with that collection, in which case an object wrapper will be used.
Hope this helps.
It is more correct to create a new model containing a list. If tomorrow you need to add a new property, you can easily add it to this model without changing viewmodel in your view.
Compare:
You have a model with a list of objects:
class MyModel
{
public List<int> Comments {get;set;}
}
Your view looks like this:
#model MyModel
foreach(var comment in Model.Comments)
...
and when you need to add new property, you an easily do this:
class MyModel
{
public string Title {get;set;}
public List<int> Comments {get;set;}
}
your view will looks like
#model MyModel
...
Model.Title
...
foreach(var comment in Model.Comments)
...
So you do not need to change the model type in the controller and in the view, you simply add new properties to the created model

Domain driven design, best practice. Where should I create my view models

In my web application a product is defined by N number of product options and a product object. To display a full product I need to create a view model that will hold the product object, a list of product options and for each product option a list of possible values. My question is what is best practice? Where should I construct this object?
In my mvc application I have a service layer, should I do it in the service layer and have something like productservice.getproduct(id) return the view model ready for the view...or in my controller do I use a combination of...
Productservice.getProduct(Id) and productoptionService.getProductoptions(productId)
And then inside the controller construct the view Model?
My guess is to go with the first option, any ideas?
Your question is a bit complicated because what one developer means by a service is something else to another.
So how do we continue?
Well we know it is the responsibility of the Controller to mediate between the View and the ViewModel.
Mapping from the request to the ViewModel
Choosing the appropriate View
And delivering the ViewModel to the View
Keeping in mind that one ViewModel to one View is generally a good practice.
So what about your Domain model?
Well it's best to keep that seperate don't allow it to leak into your controller, this is to prevent any sort of UI specific information from accidentily making its way onto your Domain model.
Personally I practise the following, I have a slim layer (call it a manager or service) that returns a ViewModel, and receives a ViewModel when talking to the controller. But when talking to my internals talks with my Domain model.
So Controller -> Manager -> Service
Manager maps between Domain model and ViewModel.
For example:
public class MemberManager
{
public MemberService MemberService {get;set;}
public MemberViewModel GetMember(int id)
{
var domainModel = MemberService.GetMember(id);
return new MemberViewModel { FullName = domainModel.FullName };
}
public bool UpdateMember(MemberViewModel viewModel)
{
MemberService.Update(new MemberDomainModel { Id = viewModel.Id, FullName = viewModel.FullName });
return true; // all good.
}
}
And your controller.
public class MemberController
{
public MemberManager MemberManager {get;set;}
public ActionResult View(int id)
{
var viewModel = MemberManager.Get(id);
return View(viewModel);
}
}
From my understanding of DDD and MVC's view-model, the one you mentioned return from productservice.getproduct(id) is belong to domain model and the view model is just used for
pass data to view for display purpose. So in my opinion, you should have a view-model which is a combination of Productservice.getProduct(Id), productoptionService.getProductoptions(productId)
and you should construct your view-model in your controller by calling these 2 methods.

In MVVM, is every ViewModel coupled to just one Model?

In an MVVM implementation, is every ViewModel coupled to just one Model?
I am trying to implement the MVVM pattern in a project but I found that sometimes, a View may need information from multiple Models.
For example, for a UserProfileView, its UserProfileViewModel may need information from UserAccountModel, UserProfileSettingsModel, UserPostsDataModel, etc.
However, in most articles I read about MVVM, the ViewModel only consists on one Model via Dependency Injection. So the constructor takes in only one Model.
How would the ViewModel work when it has to get information from multiple Models? Or would such a situation ever occur in MVVM?
PS: I am not using the Prism or Unity Framework. I am trying to implement similar patterns into a project that I am working on which doesn't use Prism or Unity. That's why I need to understand exactly how some of these things work.
In my understanding of the MVVM pattern, the only practical requirement is that the View gets all its data from the properties of a ViewModel (probably through a binding mechanism). The ViewModel is a class that you craft specifically for that view, and takes on the responsability of populating itself as required. You could think of it like ActiveRecord for the view.
As such, it doesn't matter what you do inside the ViewModel to obtain the data that its properties should show. You could get it by querying some services, reading one or more business entity models, generating it on the spot, or all of the above. It's perfectly normal to need a combination of all these things to make a functional view.
As in any presentation pattern, the point is just to separate the process of showing some data on the screen, from the process of obtaining that data. That way you can test each part of the process separately.
Edit: Here's a small but hopefully complete example of the flow of dependencies.
// Model/service layer
public class MyModelA
{
public string GetSomeData()
{
return "Some Data";
}
}
public class MyModelB
{
public string GetOtherData()
{
return "Other Data";
}
}
// Presentation layer
public class MyViewModel
{
readonly MyModelA modelA;
readonly MyModelB modelB;
public MyViewModel(MyModelA modelA, MyModelB modelB)
{
this.modelA = modelA;
this.modelB = modelB;
}
public string TextBox1Value { get; set; }
public string TextBox2Value { get; set; }
public void Load()
{
// These need not necessarily be populated this way.
// You could load an entity and have your properties read data directly from it.
this.TextBox1Value = modelA.GetSomeData();
this.TextBox2Value = modelB.GetOtherData();
// raise INotifyPropertyChanged events here
}
}
public class MyView
{
readonly MyViewModel vm;
public MyView(MyViewModel vm)
{
this.vm = vm;
// bind to vm here
}
}
// Application layer
public class Program
{
public void Run()
{
var mA = new MyModelA();
var mB = new MyModelB();
var vm = new MyViewModel(mA, mB);
var view = new MyView(vm);
vm.Load();
// show view here
}
}
You can use multiple models in a view model. The purpose of the view model is to abstract away the business / data layer (i.e. the model).
However, using more than one model usually indicates that the view is too large. You might want to split it into user controls (which have their own view models).
a viewmodel contains the "view logic" - so all you wanna show on the view is exposed through the viewmodel. if you wanna show data from diffenrent "models" then your viewmodel agregate this and the view can bind to.
the main purpose from mvvm was btw unit test. this mean easy testing of view logic without UI.
EDIT: why do you think:
ViewModel only has one single parameter for the View in its constructor
EDIT2:
there btw two main approaches to work with mvvm, first is "View First" second is "Viewmodel First" you can of course mix up both and choose the best approach for you needs.
A ViewModel may and in many cases does use multiple Models. It is itself a "Model" of your view.
Consider a profile screen that a user enters their personal information including address. If the address is stored in an "addresses" table and the rest in a "profile" table, then the ViewModel uses both the Profile and Address models to create a unified ViewModel.
As jgauffin mentioned in his answer, many times you can use user controls to achieve a one to one relationship, but you can also introduce needless complexity by trying for this 100% of the time.
I would make sure you understand the difference between view, viewmodel, and all other model classes. The ViewModel is the model object that is filled with data that the view can be bound to. It just exists to provide data to the view, which makes the ViewModel object unit-testable, and the whole business logic separate from the view. So, you can develop your business logic entirely without using the view itself, and can replace the view with just building or using another view and binding to the ViewModel object's properties. If a view is full of empty text fields for example, the contents of the text fields can be bound to different properties of the view model.
There usually really should only be one view model. BUT if it's too complex, you can use subproperties of the bound objects like described in Binding to ViewModel.SubClass.Property (sub-property)
The ViewModel can get the data it returns to the view from a lot of different sources, business objects, databases, whatever.
Usually there is one ViewModel per Model. These ViewModels contain the logic to handle the model's data. On the other side every view has it's own view model, too. So this means:
class ModelA
{
bool TestValue{get;set;}
}
class ViewModelA<ModelA>
{
ValueViewModel<bool> TestValue{get; private set;}
public ViewModelA(ModelA model)
{
base.Model = model;
this.Initialize();
}
}
class ModelB
{
string Username;
}
class ViewModelB<ModelB>
{
ValueViewModel<string> Username{get; private set;}
public ViewModelB(ModelB model)
{
base.Model = model;
this.Initialize();
}
}
These are the ViewModels that encapsulate the models. The views have their own ViewModels:
public ViewModelForExactlyOneView
{
public ViewModelA{get;set;}
public ViewModelB{get;set;}
}
To answer your question, ViewModel1 refers to ViewModelA and ViewModelB. The View therefore can get it's data from ViewModel1.ViewModelA.TestValue.
just use the User model in your view
public partial class User : Login
{
public string Password { get; set; }
public List<Customer> customer { get; set; }
}
in this the another model login inherited and the customer model also used in this model..

How could I make my View Model

I have a partial view that contains my form input(textboxes). I have 2 other partial views that use this same form. One for adding a product and one for editing a product.
This form uses a view model(Lets call it CoreViewModel). Now editing product has a couple more fields then adding a product.
I am wondering how can I add these extra fields without them showing up on an add product form?
I cannot add these extra fields to the edit product view they must be in the CoreViewModel otherwise I think styling it will be a nightmare.
I was thinking of having maybe a base class and then for the editing. I would send it a view model that inherits this base class.
Check in the view if the View Model is of this inherited class and not a base class and if it is not a base class render the code.
This way I am not sticking the edit specific code into my CoreViewModel that both the add view and the edit view have access.
I hope this sort of makes sense.
Thanks
Edit
Using Muhammad Adeel Zahid code as I base I think I got it to work
public class CreateViewModel
{
......
......
}
public class EditViewModel:CreateViewModel{
public string AdditionalProperty1{get;set;}
public string AdditionalProperty2{get;set;}
}
Controller
EditViewModel viewModel = new EditViewModel();
// add all properties need
// cast it to base
return PartialView("MyEditView", (CreateViewModel)viewModel);
View 1
#Model CreateViewModel
#using (Html.BeginForm())
{
#Html.Partial("Form", Model)
}
Form View
#Model CreateViewModel
// all properties from CreateView are in here
// try and do a safe case back to an EditViewModel
#{EditViewModel edit = Model as EditViewModel ;}
// if edit is null then must be using this form to create. If it is not null then it is an edit
#if (edit != null)
{ // pass in the view model and in this view all specific controls for the edit view will be generated. You will also have intellisense.
#Html.Partial("EditView",edit)
}
When you post it back to your Edit action result just take in the EditViewModel and cast it back to your base. Then you will have all the properties as it seems to work
I have often read people advising against such things. They often urge having viewmodel per view (even for edit and create view of same entity for that matter). Again, it all comes down to what you are doing. You may have different data annotations on edit and create view for different validation needs but if they are the same, we probably have a point to use same viewmodel for create and edit.
To solve your scenario I can't figure out couple of options. First, keep a boolean property in your view model telling you if it is and edit or create and conditionally render you properties on view
public class MyViewModel
{
public string P1{get;set;}
....
public boolean Editing{get;set;}
}
Set Editing property to false in Create ActionResult and to true in Edit ActionReult. This is the simplest method. The second one is little dirtier, but you will feel like using the technology. You can use dynamic behavior of c# 4.0. have your page inherit from dynamic in iherits directive of the page (I use aspx view engine). Then have a create ViewModel:
public class CreateViewModel
{
......
......
}
and one Edit ViewModel
public class EditViewModel:CreateViewModel{
public string AdditionalProperty1{get;set;}
public string AdditionalProperty2{get;set;}
}
and in your view you can do something like:
<%:if(Model.GetType().Name.ToString() == "EditViewModel"){%>
<%:Html.Textbox("AdditionalProperty1")%>
<%:Html.Textbox("AdditionalProperty1")%>
<%}>
There is a price to pay with dynamic. You lose intellisense and you can't use strongly typed helpers (at least in asp.net MVC 2).

ASP.NET MVC: Populating Derived Strongly Typed View with Base Strongly Typed View

In my application I have different pages: Contact Us, About Us, Home
They all have the same base elements that needs to populate the view:
Page Title
Meta Description
User Information
However on each page, they have some elements that are different:
Contact Us
Contact Information Model
Contact Form Model
About Us
Extended User Information Model
Home
Home Page Text Property
They are all routed to the same Controller Action Method because most of the functionality is similar other than populating the "extra" information dependent on page type.
So far I have done something where:
PageDetailViewData pageDetailViewData = new PageDetailViewData {Title = title, Desc = desc....}
and following this I have:
switch ((PageType)page.PageType)
{
case (PageType.Contact):
return View("ContactUsDetails", pageDetailViewData);
default:
return View(pageDetailViewData);
}
The question is how do I populate the "extra" information? I am not sure if I am going about doing this the right way. Any insight to better structure the logic flow would be appreciated.
The answer of using interfaces to imply some commonality between your view models is certainly going to help to answer some of the points in your questions.
I would however ask how wise it is to "refactor" your Action to support multiple views of differing data structures.
MVC controller actions typically represent the minimum amount of code required to gather the specific data required to generate the intended view. It's not completely uncommon for a single action to return different views of the same model data (Html view or Mobile view for example) but by varying both the structure of the data and view that will generated you introduce a few problems.
In particular you violate common best practices like the Single Responsibility Principle and make your code much more complicated to test - and Pain free testing and TDD are part of the big win with ASP.Net MVC after all.
Personally I would have a separate Action.
As far as your view models are concerned, how would you do it if this was a database?
You would have separate queries for separate data right?
A user's profile information would be queried separately from the page meta data information. This would be done for a number of reasons that could include the ability to cache certain parts of the data but not others for example.
So with the above suggestions your code might look like this (Warning: this code wasn't written in Visual Studio and is probably full of syntax issues):
public interface IMetaDataViewModel
{
PageMetaData MetaData{get; set;}
}
public class HomeViewModel : IMetaDataViewModel
{
public PageMetaData MetaData{get; set;}
public string HomePageText{get; set;}
}
//other view models go here....
public class CommonPagesController : Controller
{
private MetaDataProvider _metaProvider = new MetaDataProvider();
private PageDataProvider _pageDataProvider = new PageDataProvider();
private ContactDataProvider _contactDataProvider = new ContactDataProvider();
public ActionResult Home()
{
var viewModel = new HomeViewModel
{
MetaData = _metaProvider.GetPageMeta();
HomePageText = _pageDataProvider.GetPageData();
};
return View(viewModel);
}
public ActionResult Contact()
{
var viewModel = new ContactViewModel
{
MetaData = _metaProvider.GetPageMeta();
ContactFormData = _contactDataProvider.GetData();
};
return View(viewModel);
}
//you get the picture...
}
There are several ways you could also refactor out the generation of the view model code but thats one possible pattern.
I appreciate that this answer does have a certain amount of opinion in it but I would consider having separate actions to be best practice.
Hope that helps.
The title of your question almost gives you the answer. You can use some form of polymorphism to accomplish this. You could define a base class with the shared properties, or alternatively an interface like this:
public interface ICommonPage
{
string Title { get; }
string MetaDescription { get; }
string UserInformation { get; }
}
Then define three strongly typed ViewModel classes that all implement this interface (or derive from the base class):
ContactUsViewModel : ICommonPage
AboutUsViewModel : ICommonPage
HomeViewModel : ICommonPage
On each of those ViewModel classes, you add the extra properties that you need for those Views.
In your Controller Action, you will need to switch on PageType to select the correct ViewModel and populate it with data.
You will also need to creat three different Views (.aspx) that are strongly typed to each ViewModel class.
If you have shared rendering for the common data, you can extract that into a strongly typed UserControl (.ascx) that is typed to ICommonPage.

Categories

Resources