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.
Related
I'm learning MVC. I have an application that I developed using webforms that I'm porting over, but I've hit a bit of a snag.
I'm using the Entity Framework as well.
Currently, my models represent database tables. Generally my controller will grab the data from the table and create a view model that will be passed to the view.
Where I'm a bit confused is when I need to make some transformations based on the model data and pass it to the view I'm not sure where that transformation takes place.
In the webforms application I would have a class where I would create new objects from and then all of the transformations would happen there. A good example would be a User; the database would store first and last name, and the object would have a public property for FullName that would get set in the constructor.
I've read some conflicting discussions on Thin Controllers/Fat Models, and vice-versa. I'm just a little confused. Thin controllers and fat models seems to be the recommended way according to the Microsoft docs, but they don't really give real world examples of doing so.
So with an example:
public class UserEntity
{
public int ID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
}
public class UserController : Controller {
{
protected readonly DBContext _context;
public UserController(DBContext context)
{
_context = context;
}
public IactionResult Index(int id)
{
var _user = _context.Users.Single(u => u.id == id);
UserViewModel _viewModel = new UserViewModel
{
FirstName = _user.FName,
LastName = _user.LName,
FullName = ""
};
return View(_viewModel)
}
}
If the above isn't perfect, forgive me - I just wrote it up for a quick example. It's not intended to be flawless code.
For Fullname, where would I put logic that would give me that information. Now, I realize that in this very simple example, I could easily get the full name right there. But let's just pretend that it's a much more complex operation than concatenating two strings. Where would I place a GetFullName method?
Would I have a method in my model? Would I instead create a User class and pass the returned model data? What about having a separate class library? If either of the latter, would I pass User objects to my view model or would I set view model properties from the User object that was created?
Entity Framework often correlates a representation of the business from a relational data implementation. This approach is ideal for a clean representation of the business model's. But within a web page that direct representation often doesn't translate or play well within the application structure.
They end up usually implementing a pattern called model-view-view-model (MVVM). Basically, a transformation of a single or multiple entities into a single object to be placed within the view as a model. This transformation solves an abundance of issues, example.
public class UserModel
{
private readonly UserEntity user;
public UserModel(UserEntity user) => this.user = user;
public string Name => $"{user.First} {user.Last}";
}
The entity and database reflect a users name separated, first and last. But placing the entity into another structure, allows you to build a representative model to adhere to the view. Obviously a simple example, but the approach is often utilized for a more transparent representation since the view and database may not directly coincide with each other exactly.
So now your controller would do something along these lines.
public class UserController : Controller
{
public IActionResult Index(int id) => View(new UserModel(new UserService().GetUserInformation(id)));
}
I finished answering, what I'm trying to say with an example a comment expresses quite well.
ViewModels are what the name implies. Models for specific views. They
aren't domain entities or DTOs. If a method makes sense for a view's
model, a good place to put it is in the ViewModel. Validations,
notifications, calculated properties etc. are all good candidates. A
mortgage calculator on the other hand would be a bad candidate -
that's a business functionality – Panagiotis Kanavos 7 mins ago
I am new to MVC. According to MVC tutorial, Model are the classes which contains business logic. But in all the example which i referred, Model contains only the declaration (using interface). Why the Model cannot contain definition of business logic. Since i compared with MVVM model, where Model contains definition.
Why model look like this?
public interface IDBModel
{
void addRecord();
void deleteRecord();
}
Instead of like below.,
public Class DBModel
{
void addRecord()
{
// Insert logic
}
void deleteRecord()
{
// Delete logic
}
}
Kindly help me to understand the "Model" purpose in MVC and MVVM with some real time examples.
A model is meant to encapsulate data, making it easier to transfer from different logical areas of your application. The first example you give is incorrect, in that you're defining an interface with methods. You're more likely to see a model that looks like this:
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName() {
return string.Format("{0} {1}", FirstName, LastName);
}
}
Notice that I'm using properties as a way to transfer data, but have a method that performs lightweight logic (this could have also been done as a read only property). 90% of the time this is what your models will look like.
I would treat the M in MVC more like a view model. It contains all properties and formatting logic needed for the view to display itself. No need to have interfaces for it.
The controller is responsible for building that view model based on the models it receives from the services.
I think you misunderstood about the Model.
Worng: Model are the classes which contains business logic (not the business logic).
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.
Take a look at official ASP.NET MVC Site.
Why model look like this?
Your application may follow certain different patters. other than MVVM.
Real Time Examples / Basic Understandings : Click Here
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..
In my Controller I have a ProductInfo class from my Domain Model and I need some of its information to populate my View Model ProductStatsVM.
How do you populate the View Model? I heard three possible ways:
Populate the View Model directly from the Controller (not good, I want to keep my Controller slim)
By using a View Model constructor and pass the domain model as parameter. (I have to create a constructor for each domain model class I want to use)
By using a Fill() method. (I saw it on the web, no idea how it works I guess this way the ViewModel should be aware of the Service Layer and creates coupling).
I know there are tools like AutoMapper, which I am going to use indeed, but before I want to understand the logic on how to fill a View Model from the Controller without using any additional tool.
The idea is that your controller action queries some repository to fetch a domain model. Then it passes this domain model to a mapping layer which is responsible to convert it to a view model and finally it passes the view model to the view:
public ActionResult Index(int id)
{
ProductInfo product = repository.GetProductInfo(id);
ProductViewModel viewModel = Mapper.Map<ProductInfo, ProductViewModel>(product);
return View(viewModel);
}
and you could even make your controller slimmer by introducing a custom action filter that will automatically intercept the Model in the OnActionExecuted event and call into the mapping layer to substitute it with the corresponding view model so that your controller action now becomes:
[AutoMapTo(typeof(ProductViewModel))]
public ActionResult Index(int id)
{
ProductInfo product = repository.GetProductInfo(id);
return View(product);
}
and of course now the view is strongly typed to ProductViewModel:
#model ProductViewModel
...
Up to you to implement the Mapper.Map<TSource, TDest> method. And if you don't want to implement it yourself you could download AutoMapper which already has this method for you.
The mapping layer is something that is part of the MVC application. It must be aware of both the domain models coming from your service layer and the view models defined in your MVC application in order to be able to perform the mapping.
Don't use constructors (other than the default parameterless one) in your view models. The default model binder will choke if the view model doesn't have a parameterless constructor in your POST actions and you will have to implement custom model binders.
Since viewmodels are needed to populate UI, it should be good idea to get them populated via controllers. You still may keep them slim by using Automapper.
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.