I have a question relating to best practices on validation using MVC and POCO. From what I can tell, the best practice is to have a ViewModel that mirrors the POCO and then use something like AutoMapper to parse the ViewModel to the POCO after it (the view model) is validated.
That's all well and good, but I'm wondering if there are any problems with inheriting from the POCO and over ridding only properties I wish to validate in the View Model?
POCO:
public partial class Sector
{
public virtual int SectorId { get; set; }
public virtual string Name { get; set; }
}
My ViewModel might look like this:
public class SectorDTO : Sector
{
[Required]
[StringLength(10)]
public override string Name {get; set;}
}
UPDATE
This solution ended up not working, mostly due to the way my business layer and data layer's are setup. My solution was instead to create a ViewModel that contained a DTO with all the validation, and then use AutoMapper to change the object back to the POCO type.
I did like below:
public partial class SectorMetaData
{
[Required(ErrorMessage="Required Filed")]
public int SectorId{ get; set;}
[Required(ErrorMessage="Required Filed")]
public string Name{get; set;}
}
[MetadataType(typeof(SectorMetaData))]
public partial class Sector
{
public int SectorId{ get; set;}
public string Name{get; set;}
}
This class should be same namespace as POCO class.
Hope this helps!
Related
I am using Data Annotations in my MVC 4 project with Scaffolding Nuget to create CRUD views. I am using Layer level Database model not EF.
So my Class look like as below:
[MetadataType(typeof(CustomerMetaData))]
public partial class UserProfile: IBrObject
{
public UserProfile(string aspUserName): this()
{
this.AspUserName = aspUserName;
}
public string AspUserName { get; set; }
public DateTime MetaDateFirstSaved { get; set; }
}
public class CustomerMetaData
{
[ReadOnly(true)]
[ScaffoldColumn(false)]
[DisplayName("ASP UserName")]
public object AspUserName { get; set; }
[DisplayName("Date First Saved")]
[DataType(DataType.Date)]
public object MetaDateFirstSaved { get; set; }
}
when i am trying to create views with Scaffolding Nuget it still shows AspUserName column not hide or not read only.
How i can hide or readonly ?
You use object in metadata and string and DateTime respectively in actual view model so they don't match.
Update
Another possibility (I pretty sure this is what's happening in your case) is because your model type in the view defined as Interface type rather than class type.
In your view replace #model IBrObject with #model UserProfile.
Hope this helps
object AspUserName != string AspUserName
I've had a read through Jimmy Bogards post from a whiel back on how they do view models, in my own project I've come across a few places where there is quite a lot of information that needs to displayed at one time on the screen such as a form that needs to be filled out where all fields are shown at once.
So our view models would look something like
public class FormViewModel
{
public string field1 {get;set;}
public int field2 {get;set;}
public DateTime field3 {get;set;}
public string field4 {get;set;}
...snip
public string field50 {get;set;}
}
Now the forms do have sections so we could introduce a bit of structure into the viewmodels like this:
public class FormViewModelSection1
{
public string field1 {get;set;}
public int field2 {get;set;}
}
public class FormViewModelSection2
{
public DateTime field3 {get;set;}
public string field4 {get;set;}
}
and then the main viewmodel becomes
public class FormViewModel
{
public FormViewModelSection1 {get;set;}
public FormViewModelSection2 {get;set;}
}
so we would return the more complex viewmodel to a main view that basically just delegates each of its sections out to be rendered through a renderpartial like
<div>
My form
<%: Html.RenderPartial("soemascx", Model.FormViewModelSection1)%>
</div>
or maybe use an editorfor to render the contents.
My question is, is the "recomposing" of the viewmodel a valid thing to do or is it undoing some of the benefits that are provided by making a view model so flat.
I'd say there's no right answer to your question. It all up to usability and functionality. Maybe even personal coding style.
Meaning as long is it is
working (displaying, posting back, validating etc)
serves the purpose
understandable by others (read maintainable)
consider it to be good solution. If you'd ask about what I'd do: I'd go with one flat class well decorated (data annotations) for names and validation, and structures supporting visual representation (like lists for combo boxes, enums (or whatever you comfortable with) for radio buttons.
As a note, I had some bad experience with hierarchies of view models (inheritance) - was working really poorly with validation (inherited data annotations don't work as expected with view model inheritance).
So to answer your specific question - no, you not doing anything wrong ... its up to you how to do it.
Hope this helps.
I personally don't separate my ViewModels into child ViewModels unless it's for something like a "UserControl" type thing, e.g. A small form on the side of the web page would be a separate ViewModel and the main page ViewModel will reference it.
But generally, I have a BaseViewModel which is an abstract class that has all the shared fields (like pagetitle etc), then I have a ViewModel for the View itself which inherits BaseViewModel. example:
public abstract class BaseViewModel
{
public string PageTitle { get; set; }
public string MetaDescription { get; set; }
public string MetaKeywords { get; set; }
}
I might have a small signup form that i use in a few of my pages. So i'll create a separate ViewModel for this small form. One benefit of separating this out into it's own object is that when the user submits the form, I can pass in the specific SignupViewModel object instead of the main page with all it's entities.
public sealed class SignupViewModel
{
[Required]
public string YourName { get; set; }
[Required]
public string YourEmail { get; set; }
}
Then for an basic web page with the above usercontrol:
public sealed class PageViewModel : BaseViewModel
{
public string PageID { get; set; }
public string PageContents { get; set; }
public SignupViewModel UserSignupForm { get; set; }
}
I suppose there's a number of different ways to tackle the same thing, but this above is how I do it.
My ASP.NET MVC site connects to a WCF service to get data. The WCF service returns a data contract like this:
[DataContract]
public class Person
{
[DataMember]
public string First { get; set; }
[DataMember]
public string Last { get; set; }
}
The view model in my MVC project looks like this:
public class MyViewModel
{
public string SomeExtraField1 { get; set; }
public string SomeExtraField2 { get; set; }
public string SomeExtraField3 { get; set; }
public Person Person { set; set; }
}
Should my view model be referencing the "Person" data contract that is returned from the data service? Or should I create a new "Person" class in my MVC project that mirrors the properties on the "Person" data contract?
The WCF service call is hidden behind an interface. It seems to be that having the interface reference the data contract makes my interface a leaky abstraction. However, I have a few people that believe creating an additional "Person" class in my MVC project that mirrors the data contract is code bloat.
What are are the best practices surrounding this type of layering/decoupling?
Should my view model be referencing the "Person" data contract that is returned from the data service?
No, avoid this, it's giving developers the false impression that they are using view models. I quite often see code like this when doing code reviews:
public class MyViewModel
{
public SomeDomainModel1 Model1 { get; set; }
public SomeDomainModel2 Model2 { get; set; }
...
}
and that's just wrong. When I critique them for not using view models they show me this and tell me: "Darin, look, I am using view models", unfortunately that's not how view models are supposed to work. They are not wrappers around domain models.
Or should I create a new "Person" class in my MVC project that mirrors the properties on the "Person" data contract?
Yes, you could create a PersonViewModel and include only the properties that your view needs of course.
Or if the particular view you are designing this view model for needs only some properties you could also make it look like this:
public class MyViewModel
{
public string SomeExtraField1 { get; set; }
public string SomeExtraField2 { get; set; }
public string SomeExtraField3 { get; set; }
// this would be for example the concatenation of your domain model
// first name and last name as that's what this particular view needs to
// display
public string PersonFullName { set; set; }
}
As far as the conversion between your domain models and view models is concerned, AutoMapper is simply put: excellent.
I'd say create a Mapper layer that would convert between the WCF Person class and the "mirror" Person class. That way you are tying your MVC implementation to a POCO and not directly to WCF. This adds the ability to swap out WCF with another service without touching MyViewModel in the future if need be (looser coupling).
I've seen somewhere how to do this before on a blog but I forgot where or how. Lets say I have a domain in a class library. I'd like to data annotate the properties of this domain as my viewmodel in the web project.
How do I accomplish this?
For example. This domain is in my class library:
public class Person {
public int Id {get; set;}
public string FirstName {get; set;}
}
In my web project, there is this:
//Do i need to set some attribute here?
public class CreatePersonViewModel{
[Required()]
[DisplayName("First Name")]
public string FirstName {get; set;}
}
This code can be mapped to Person without a tool. Probably partial or something.
The whole idea of using a view model is to decouple it from your domain model and to have something which is adapted to the needs of the view. The view model should be declared in the web project and contain all the necessary properties and formatting attributes that this particular view might require. The domain model shouldn't be polluted with any view specific data annotations. So if your model looks like this:
public class Person {
public int Id { get; set; }
public string FirstName { get; set; }
}
You could have the following view model:
public class CreatePersonViewModel {
[Required]
[DisplayName("First Name")]
public string FirstName { get; set; }
}
and then have the controller fetch the model from some repository, map it to the view model (AutoMapper can help you here) and pass the view model to the view.
Do you mean annotate your Domain objects or your view model objects?
Using the System.ComponentModel.DataAnnotations validation attributes (and deriving any of your own from ValidationAttribute, you can validate values bound to the properties of your viewmodel at the point of model binding.
Scott Guthrie has a detailed blog post about Model validation with data annotation validation attributes.
EDIT: you say in a comment to another poster that your types already exist. You can add the MetadataTypeAttribute to the existing type to indicate another type that holds the validation logic to be applied to the properties of your existing type.
You can create a 'buddy' class for your data annotation attributes
[MetadataType(typeof(ResourceMetadata))]
public partial class Resource
{
public object Value { get; set; }
}
public class ResourceMetadata
{
// The metadata class can define hints
[UIHint("ResourceValue")]
public object Value { get; set; }
}
Are you talking about this type of thing?:
using System.ComponentModel.DataAnnotations;
public MyClass
{
[DisplayName("Street Address")]
public string StreetAddress { get; set; }
}
EDIT:
If you need to add Data Annotations to generated class like an Entity do this:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
namespace Something
{
[MetadataType(typeof(MetaMyClass))]
public partial class MyClass
{
//You can just leave this empty if you have nothing additional to add to the class
}
public class MetaMyClass
{
[DisplayName("Street Address")]
public string StreetAddress { get; set; }
}
}
i'd like to know, I have a application in asp.net mvc and nhibernate. I've read about that in the Views on asp.net mvc, shouldn't know about the Domain, and it need use a DTO object. So, I'm trying to do this, I found the AutoMapper component and I don't know the correct way to do my DTOS, for some domain objects. I have a domain class like this:
public class Entity
{
public virtual int Id { get; set; }
public virtual bool Active { get; set; }
}
public class Category : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Category() { }
}
public class Product : Entity
{
public virtual string Name { get; set; }
public virtual string Details { get; set; }
public virtual decimal Prince { get; set; }
public virtual int Stock { get; set; }
public virtual Category Category { get; set; }
public virtual Supplier Supplier { get; set; }
public Product() { }
}
public class Supplier : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Supplier() { }
}
I'd like to get some example of how can I do my DTOs to View ? Need I use only strings in DTO ? And my controllers, it should get a domain object or a DTO and transform it on a domain to save in repository ?
Thanks a lot!
Cheers
There is no guidelines on this matter and it depends on your personal chice. I have few advices that have proven useful in practice:
1. Use flat DTOs - this means that the properties of the DTO must be as primitive as possible. This saves you the need for null reference checking.
For example if you have a domain object like this:
public class Employee
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop Employee Boss{get; set;}
...
}
And you need to output in a grid a list of employees and display information for their 1st level boss I prefer to create a DTO
public class EmployeeDTO
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop bool HaveABoss{get;set}
prop string BossFirstName{get; set;}
prop string BossLastName{get; set;}
...
}
or something like this (-:
2. Do not convert everything to sting - this will bind the DTO to a concrete view because you'll apply special formatting. It's not a problem to apply simple formatting directly in the view.
3. Use DTOs in your post actions and than convert them to domain objects. Usually controller's actions are the first line of deffence against incorrect data and you cannot expect to be able to allways construct a valid domain object out of the user's input. In most cases you have to do some post-processing like validation, setting default values and so on. After that you can create your DTOs.