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; }
}
}
Related
I have multiple related ViewModels:
ChangePasswordViewModel
ResetPasswordViewModel
RegisterViewModel
that each include multiple annotation attributes for the password property.
I would like to be able to define these attributes only once.
I tried using a MetadataType attribute to associate each ViewModel with a class that would include all of the associated attributes but since this includes properties that may not be in the individual View Models, I get an error message.
Use inheritance:
public class BasePasswordViewModel
{
[Required]
public string Password { get; set; }
[Required]
public string ConfirmPassword { get; set; }
}
public class ChangePasswordViewModel: BasePasswordViewModel { //... }
public class ResetPasswordViewModel : BasePasswordViewModel { //... }
public class RegisterViewModel: BasePasswordViewModel { //... }
All of your "shared" properties can go in BasePasswordViewModel and anything that is specific to ChangePasswordViewModel, ResetPasswordViewModel, RegisterViewModel can go in there.
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 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!
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'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.