I plan to create a Asp.Net MVC app which contains edit/create pages for a large model with many-to-many relationship with other models. I found the Saving Many to Many relationship data on MVC Create view and plan to use it.
In the example, the create page uses the following ViewModel.
public class UserProfileViewModel
{
public int UserProfileID { get; set; }
public string Name { get; set; }
public virtual ICollection<AssignedCourseData> Courses { get; set; }
}
And the UserProfile model has only two properties so the ViewModel just duplicates all the properties.
public class UserProfile
{
public UserProfile()
{
Courses = new List<Course>();
}
public int UserProfileID { get; set; }
public string Name { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
However, in my case, there will be a lot of properties (with data annotations), say 50 properties. Should the ViewModel duplicate all these properties (with data annotations too)? (looks ugly?) Or is there a better way?
Update
Is it a good practice to define ViewModel as
public class UserProfileViewModel
{
public UserProfile UserProfile { get; set; }
.... // Other properties needed by the view.
}
One shortcoming of this way is it expose all the properties in the Model even it's not needed in the view.
The thing with View Models is very simple: the View Model should consist only from data needed by the View. That is, the view model design is driven by the (static) view. Static because you can updates parts of the view via ajax in the browser so it makes no sense for your model to contain that info (except if it's required as init values for the JavaScript).
How the data is stored or how it's used by the business layer (if any) is not the view model concern.
Updated
The cleanest and safest way is to define the view models with the properties you need (you can copy paste them from the other model it's ok in this scenario) then use AutoMapper to map the business object to the view model. This way you can evolve both models differently. Personally, very rarely my view model is identical to a business model, they resembles a lot but there those tiny differences that complicate the things.
From a Separation of Concerns point of view, the busines model is for business usages, persistence model is for persistence usage while view model is for the view usage. Don't mix them or you'll have one model serving too many masters, which leads to complications down the road.
Taken from: This excellent explanation of ViewBag, ViewData and TempData
The type of data that suits ViewModels well is as follows:
Master-detail data
Larger sets of data
Complex relational data
Reporting and aggregate data
Dashboards
Data from disparate sources
So in summary, yes the ViewModel is what to use when the view requires a lot of complexity, it suits your needs. As for using and populating every property that should be determined by what the particular view requires. ViewModels are not necessarily one to one representations of a model / entity. That should be dictated by your view requirements, e.g. UserCourseViewModel could aggregate the UserProfile and Course entities, but not necessarily all of both of their properties, unless of course all properties are required by the view.
Rachels summary:
The ViewData and ViewBag objects give you ways to access those extra pieces of data that go alongside your model, however for more complex data, you can move up to the ViewModel. TempData, on the other hand, is geared specifically for working with data on HTTP redirects, so remember to be cautious when using TempData.
Related
I'm using code-first with entity framework for modeling and creating my db.
I'm just wondering - when I return objects to the user - I don't want to return data sensitive fields like id.
Should I add an atttibute like [DoNotReturn] combined with a filter to remove this fields when returning to the user, or should I just make a whole new class which doesn't contain these fields?
Example:
public class UserAccount
{
//Option 1 - Hide fields
[DoNotReturn]
public int Id { get; set; }
[Index(IsUnique = true)]
[MaxLength(50)]
public string Username { get; set; }
public decimal Cash { get; set; }
[DoNotReturn]
public Account Account { get; set; } //Contains Email / Password
//Option 2 - return a `safe` version
public User UserAccountToFriendly() {
return new FriendlyUser(this.Username, this.Cash);
}
}
Keep your database model separate from your view model that's the approach I have taken and doing it for a long time. it will give you a good separation. Once you start dealing with ViewModel then you can use a library like Automapper or custom mapping classes to convert ViewModel to database model or vice-versa. I hope it helps
Never use your database models as result for end-users and keep it separate from Presentation/Application layer.
There are so many problems that you will encounter:
disclosure of sensitive data (you've mentioned about);
performance issues and waste of RAM and CPU (for instance, you have Order entity with dozens of properties, it would be better to load only those properties that is required instead all);
problems with serialization (with enabled lazy-loading, for instance MVC could try to serialize whole object with navigation properties... );
etc...
I'd like to recommend the following:
return original database entity from Repository layer if necessary, but don't forget to cast it on Presentation layer to another completely brand new xxxModel, xxxViewModel, xxxResponse, etc;
return xxxView from Repository layer if you want to achieve best optimizations, but don't forget to cast it on Presentation layer to brand new object. (any changes on one layer shouldn't affect others, especially end-users);
I've researched about MVC for a while and similar questions like this and this.
They, however doesn't answer my question. In a lot MVC examples (Both ASP.NET MVC and JAVA MVC) They usually provide the Model with fields E.G (Name, Age etc) and then allow the view to "read" those fields.
But from what I've understood is that the View should not know about the Model, cause if the View does then it's not (correctly) encapsulated.
Pictures however shows that the View knows about the Model to display correct data.
If I understood correctly is that the Model can be business logic for a system and the View is not supposed to be connected to that.
Lets say that my Model fetch data from a database, then it's still my Model that is my business logic and not the database or am I thinking wrong?
So my questions is
Should the View know about the Model to use correct data?
Is the Controllers job to fetch data from E.G a database and create a Model from that, and the View should use the Model data for display?
What is Model Business Logic? (Please don't use fields to explain)
a lot of this is open to interpretation. There are a number of approaches and is down to which ever suits you best. My approach is below if its some help.
Should the View know about the Model to use correct data?
Yes. The view has a model import directive for it to bind to when it's rendered. If the view didn't know anything about the model it was accessing then how could it bind to the data.
Is the Controllers job to fetch data from E.G a database and create a Model from that, and the View should use the Model data for display?
No, the controller should no nothing about the implementation of the data layer. The controllers only job should be to invoke the services that it needs to build up the view model.
What is Model Business Logic? (Please don't use fields to explain)
Not to sure about the exact term "Model Business Logic". Model can be used to describe domain models or in this case View models. Business logic are operations you perform on business or domain model objects populated by some service.
The way how i handle ViewModels and business logic as you say is to separate out the domain model, e.g. Customer or Order in a separate dll and have those domain objects populated by a service. Then your View Model becomes a composite of domain model objects.
So in all.. the controller makes a call out to services that consume datalayers which in term return you populated domain objects. These can then be used to populate your view model which is then used by the view.
I've added below a very simplistic look at approach which will hopefully point you in the right direction.
public class MyController
{
[HttpGet]
public ViewResult GetCustomer(int customerID)
{
var myViewModel = new CustomerViewModel();
var myService = new MyServiceLayer();
var myCustomerDetails = myService.GetCustomerDetails(customerID);
myViewModel.Customer = myCustomerDetails;
return View("CustomerDetails", myViewModel);
}
}
public class CustomerViewModel
{
public CustomerDomainObject Customer { get; set; }
}
public class CustomerDomainObject
{
public string Name {get;set;}
}
public class MyServiceLayer
{
public CustomerDomainObject GetCustomerDetails(int customerID)
{
var myCustomer = new CustomerDomainObject();
var dataLayer = new MyDataLayer();
var myCustomerData = dataLayer.GetCustomerDetails(customerID);
var myDataRow = myCustomerData.Tables[0].Rows[0];
myCustomer.Name = myDataRow["Name"].ToString();
return myCustomer;
}
}
public class MyDataLayer
{
public DataSet GetCustomerDetails(int customerID)
{
//Execute proc etc...
return new DataSet();
}
}
In ASP.NET MVC you have strong typed views. This is a razor thing that let you access to your model properties easily when you are building your view. You will easily notice this since IntelliSense will work whenever you are trying to access a property like #Model.Name. If it should or not be strong typed, IMHO it just relay on what you need, there are not cons on using strong typed views. It will help you big time whenever you code your views, and you will have less runtime errors for sure.
For 'Model Business Logic' I would say that you can for sure have a lot of Logic in your model, but that is not as simple as it sounds. You will probably have to work with patterns and have small classes which responsible for one thing.
Look at this link: https://msdn.microsoft.com/en-us/library/hh404093.aspx
Generally speaking it's a good idea to completely separate the domain model from its view representation. Domain model contains the entire business logic, which can be quite complex. Also, the presentation layer usually requires extremely simplified objects (just data structures, without any business logic). Specific view technologies might apply heavy restrictions to the objects. Besides of that, we often change/aggregate domain objects to suit the final user specific needs (by creating specialized DTOs). Therefore, since presentation and domain layers are so distinct (and domain model should never depend on view), I often completely separate them. This allows to create a more supple design.
I have the following setup: fluent nhibernate + asp.net mvc 4.
I have a seperate project in VS where all my objects are stored, these objects are directly mapped to the database.
However, to display data from these objects in the views, I need 'models'.
Do I need to create new model objects, based on these database mapped objects, or can I just pass these database objects as a model to the view? (is this a good idea?)
Thanks!
In my opinion you should create additional ViewModel classes. If some changes are to be made to the data that get displayed, it's easier to just modify these models; your domain mappings will not be affected by some particular "rendering" circumstances.
Another advantage would be that you can decorate the properties with formating attributes, without enforcing these settings on future projects that depend on your domain.
For example, say you have the following Customer class in your base project:
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
}
You can add a [Required] attribute on the Name property to make it mandatory. If for a particular project you need to also make the Address property mandatory, you would decorate it with another [Required] attribute. If you directly use the domain model classes, you will enforce that the Address property would always be required, even though the project requirements would not state that. This can be further extended to different validation attributes and also additional data that you may want to sent to the view along with the model (such as composite fields).
This is largely a design decision that depends on the size of the project, etc. Without getting into too much detail, the short answer is yes, you can use your database objects/models directly in your Views.
Sometimes it may be desirable to create specific view models if you only want to show a subset of the fields, or do different validation than the database in your View. You can then can validate this view model in your controller and if everything is okay, map it to your nHibernate models.
I am not an experienced MVC3 developer but I'm trying to be. I am familiar with POCO classes and also ViewModels, as the former describes each classes of the database and the latter is used for strong type views in mvc3. My question is not that complicated for the experienced developers but I am a little confused about that.
The matter is that, I have a solution containing three projects;
The Model class library in which I have wrote my POCO classes. Here is an example:
.
public class Service
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int ServiceID { get; set; }
//------------------------------------------------------------//
[Required, MaxLength(30)]
[LocalizedAttribute("Name")]
public string Name { get; set; }
//------------------------------------------------------------//
[MaxLength(100)]
[LocalizedAttribute("Description")]
public string Description { get; set; }
//------------------------------------------------------------//
[Required]
public long ModifiedByUserID { get; set; }
[ForeignKey("ModifiedByUserID")]
public virtual User OperatorUser { get; set; }
//------------------------------------------------------------//
[Required, MaxLength(10)]
public int ModifiedDate { get; set; }
}
The repository and UnitOf Work class Library
The MVC application
Now, Did I correctly address the POCO classes? (I am using EF Code First to generate the database of course) If So, are they inferred as ViewModels too? I have used them to generate Strongly-Type View.
What is the best and actually standard way to define POCO classes and ViewModels?
I would appreciate any kind guidance,
To be honest, it depends on the size of your project.
If you look at most of the Microsoft examples, they use their POCOs as Models simply because their examples are small projects.
If however you are developing anything near an enterprise level application you really shouldn't be using your POCO's as models. There should be clear separation of concerns. Strictly speaking your Web project shouldn't even know about your POCO objects in those scenarios, a typical implementation is a common interface that both the POCO and the View Model can implement and see. That way saves you exposing your POCO objects to your Web layer.
ViewModel is a middle layer between data(Poco) and View, which usually contains additional logic to control UI.
If ViewModel doesn't have any specific data, I don't see the reasons not to use Poco as ViewModel.
In other case, to keep data as Poco, you can create ViewModel with the same fields as your Poco class and use Automapper to Poco->ViewModel, ViewModel->Poco transformation.
I agree with mt_serg. In my application, I use POCO classes directly if it is a straightforward case.
However if in my view I also need to display for example drop-down lists that are populated from the db, then I create a ViewModel that includes the POCO classes with the additional lists and use the VM in the view passed in from the controller. I don't however redo my work and create the VM with the same fields as the POCO + additional fields. I find this method works for me, since I do not have to take care of transformations myself and I let the MVC framework sort that out for me. Hope this helps
Is the following OK to do? I know Domain Models should never be used in views but is it ok to use Domain Models in your View Models? For some very small models it doesn't seem worth it to be creating and managing a View Model for them.
For Example
public class LoginDomainModel
{
public string Email { get; set; }
public string Password { get; set; }
public string DisplayName { get; set; }
public long UserTypeID { get; set; }
public virtual UserType UserType { get; set; }
}
public class UserTypeDomainModel
{
public UserType()
{
this.Logins = new List<Login>();
}
public long UserTypeID { get; set; }
public string UserType { get; set; }
public string Description { get; set; }
public virtual ICollection<Login> Logins { get; set; }
}
public class LoginViewModel
{
public string Email { get; set; }
public long UserTypeID {get; set;}
//Right here
public List<UserTypeDomainModel> UserTypesSelectList {get; set;}
}
Personally I use domain models in the view if they would naturally be an exact fit. That is likely to happen only on trivial projects that are CRUD in nature (editing the domain entities in a straightforward way). I find it a waste of time to create an exact copy of a domain entity for the sake of purity.
I will never modify a domain model in the slightest to account for needs of the view. In 95%+ of my projects, this is the circumstance I find myself in. The moment you pollute the domain for the sake of the view, you introduce maintainability headaches.
It depends on what you mean by "Domain model". Do you mean EF entities? Or do you mean business layer objects?
It's never a good idea to pass EF entities to the view, particularly if you're using default model binding. This can create security issues if you are not careful. Although the same issues can occur if you're not careful with business objects passed to the view.
One of the huge advantages of view models is that you have much finer control over mapping of data, so you can validate more easily that only the correct maps occur.
It all comes down to your app though. If it's a simple app, then it may not be worth the trouble of doing more complex mappings. If it's a complex app, that must live for a long time, and will likely to be updated a lot.. then you should definitely invest the effort.
I struggled for a long time with the perceived duplication caused by separate view models and domain models. I would assert that since they are intended for different purposes it's not really duplication, but it still feels "wrong" to declare so many similar properties.
In very small projects (especially ones with a highly trusted group of authenticated users) I may just bind directly to the domain models and be done with it. Or I may mix and match if the view model requires a different structure (as #Eric J. describes).
However: The ModelBinder will attempt to match values in the request to properties on your model. This means that any property on your domain model can potentially be populated by a (rogue) request. There are ways to prevent this, but for me the peace of mind outweighs a little extra effort creating separate view models.
I don't see an absolute need to create a separate view model for readonly, unbound values (possibly the list of user types in your case, though public virtual ICollection<Login> Logins may negate this).
Alternatively, you may wish to project the domain model to a UI-oriented abstraction (e.g. IEnumerable<SelectListItem>). You can use SelectListItems for a variety of input mechanisms, so you aren't tying yourself to a particular UI behavior.
Even with abstraction, you may still need to validate that the request doesn't contain an illegal value. For example, perhaps only super admins can assign certain UserTypeDomainModel IDs. Regardless of abstraction, you still need to validate this.
TLDR: abstract domain models as much as is practical, find appropriate abstractions (a new view model isn't always the correct answer), and be (slightly paranoid) about input validation.