Using EF POCO classes as MVC 2 models (with data annotations) - asp.net-mvc

I have a 4 layered web application programmed in C#... .Net 4.0:
UI Layer
Business Layer
Data access Layer
Entities layer
My data layer contains an edmx
My entities layer contains my POCO objects (generated by a t4 script), and that layer is referenced in all other layers.
When creating an MVC form to create a new customer, for example.... I already have the customer class with fields for first name, last name, etc in my entities layer, but that auto-generated POCO class does not have data annotations for validation... I.E. [Required], etc. for when the form is submitted
My solution right now is to create new model classes that are pretty much the same as my poco classes but also have these additional validation annotations.
What I want to know is if theres an easy way to use certain POCO objects in the MVC model (in the UI layer) without having to almost rewrite the class... and also without modifying the t4 that generates these POCO classes (since I'm not up to speed on t4).
I saw this from another post on stackoverflow http://automapper.codeplex.com/ ... not sure if this will do it or is the best solution.

If your POCO class is declared as such:
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
}
then if you just change the T4 to make it a partial class, you can then define in a separate file:
[MetadataType(typeof(PersonMetadata))]
public partial class Person {
internal class PersonMetadata {
[Required]
// insert other metadata here
public string FirstName { get; set; }
// and if you don't want metadata for lastname, you can leave it out
}
}
Two extra points - the metadata class doesn't have to be nested in the partial you define, I think it's neater though. Also, the types don't have to match in the metadata class, so you could make them all object if you wanted to (and you might see some examples on the web with it like this)

Modifying a T4 template is not very hard at all. I recently faced the same issue and decided to read up on T4 a bit and then modify the template to create the generated properties the way I need them (annotations, and in my case with NotifyPropertyChange etc. as I use the same POCO objects in an MVC UI and in a Silverlight UI).
Even though you're looking for a solution that doesn't require modifying T4, I hope this is useful.

Related

Validation approach on MVC3 CRUD application with EF4-based WCF as backend

I develop a simple MVC3 CRUD application - simple controllers / views, which uses WCF service for CRUD data access.
The WCF uses EF4.1 with DbContext, and simple CRUD-style methods: ListEntities, GetEntity(ID), AddEntity (entity), DeleteEntity(ID)
If I develop the MVC application directly with EF, code first, I can annotate properties in the entity classes with validation attributes, and the MVC application will automatically recognize validation errors and report them in the UI when I try to save and a validation error occurs (e.g. a required field is not set).
But in my application I don't use this approach and I face two problems:
My entities in the WCF are generated from the EDMX, which in turn was also generated from the database. So I cannot actually add to them any data validation annotation attributes, because they'll vanish as soon as the entities will be regenerated from the EDMX. Is there any solution to this?
Since my client (MVC app) does not share the data contract classes with WCF (for clear separation), but instead it is generated form service reference, even if I find a way to add data annotation attributes to server-side data contract classes, will they be recognized and recreated when the data contract proxy class is created on client side?
So how could I made the MVC application to use client side validation and error message reporting for validation failures when binding to entities exposed by WCF service as data contracts?
One idea I have is, on client side, to create derived classes for all entities exposed as data contracts, and apply annotation attributes to them to desired properties. But this doesn't looks like a good solution to me, because with this I create a logic "coupling" between UI client and the WCF service / data layer (forcing UI to know about data more than it should do - by putting BL logic in client).
Can anyone give me some suggestions on how to handle those this situation?
Thanks
1: Yes you can add validation using the System.ComponentModel.DataAnnotations.MetaDataType.
I answered this question at MVC Partial Model Updates
2a: What you can do is create a seperate Class Library Assembly that contains all the interfaces (with or without additional MetaDataTypes) and use that on both the WCF service and the MVC application. After you add the reference to your MVC application, when adding the WCF Service reference, you can match the WCF Service DataContacts directly to the interfaces in the Assembly. One Caveat is that both the WCF service and MVC application are dependant on the Assembly (some might consider this tightly coupled) but this should be ok because you are only tightly coupling at the interface level, and whether or not you choose to allow VS to recreate it's own interfaces/classes or reuse what you already created in the Assembly it boils down to the same thing in my opinion.
2b: If you decide not to use a Class Library, I'm pretty sure that the service reference classes are partial, and you can simply create another .cs file with partial classes and add the interfaces as I described in part 1 to the partial classes.
Update
I am currently using Entity Framework to access my database. Entity Framework, like WCF References, classes are Auto-Generated classes will look something similar to:
[EdmEntityTypeAttribute(NamespaceName="MyNameSpace", Name="Info ")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class Info : EntityObject
{
public static Info CreateInfo (global::System.Int32 id)
{
Info info= new Info ();
info.Id = id;
return info;
}
public string Name { get; set; }
public string FavoriteColor { get; set; }
// etc etc
}
In a separate file with the same namespace as the previous partial class, I have created:
[SomeAttribute1]
[AnotherAttribute2]
public partial class Info: IInfo
{
}
So now my auto-generated class is not only based on an Interface I created IInfo so the actual methods are not exposed (because my datatier in MVC returns interfaces), but it also has Attributes (for Data Annotations or whatever).
What I would suggest is instead of putting your data annotations directly on your WCF Service reference class is to use the MetedataType DataAnnotations. This allows you to separate the actual data object with the data annotations validations. Especially helpful if you want to use the same data class with different validations based on whatever (maybe administrators don't have to have a valid favorite color).
For example:
public interface NormalUser
{
[Required]
string Name { get; set; }
[Required]
string FavoriteColor { get; set; }
}
public interface AdminUser
{
[Required]
string Name { get; set; }
string FavoriteColor { get; set; }
}
[MetadataType(typeof(INormalUser))
public class NormalUserInfo : Info { }
[MetadataType(typeof(IAdminUser))
public class AdminUserInfo : Info { }
In this example we have two different classes NormaUserInfo and AdminUserInfo which both have different validations. Each of them have inherited from Info so they are valid models that can be passed into the WCF Service.
Out of my mind, as I can't test it right now...
Let's say your autogenerated code is like this:
public partial class Employee
{
//some code here
}
You can add a new Employee class, also partial, and this one won't be autogenerated
[you can annotate here]
public partial class Employee
{
//somecode here
}
try it
As for the validation, you could use: http://fluentvalidation.codeplex.com/

MVC 3 - Entity Framework - Scaffolding - Validation issue

Im developing an MVC 3 application with Entity Framework and Im tring to use Scaffolding.
To solve "Type not mappedd issue" I've done the procedure found here. Everything now works fine.
Default validation is not working, required field are firing an exception instead of write something on ValidationSummary, so I want to add my custom validations using attributes.
The problem is that the solution about "type not mapped issue" has added 2 .tt files and a .cs file for each of my entities, these files are recreated each time my model (.edmx) is changed and saved so I cant put my Data Annotation Validator Attributes in those classes and either I cant create a new partial class with some properties because thay are already defined.
How can I do? May I have to move validation client-side using jquery? Or maybe there a workaround to add Data Annotation Validator Attributes to my entities, I prefer this way to have more visibility of my validations.
Thanks in advance
I've not used the DbContext generator, but have had similar issues with the POCO Generator. Assuming that the solution is similar:
Modify the T4 template that creates the entity classes to add an extra attribute to the class:
[MetadataType(typeof(CustomerMetaData))]
where "Customer" is the name of the entity.
Then, manually create MetaData classes for each of your entities. You can actually use a T4 template for that, too, if you want, but not have it run all the time.
The Metadata classes look like this...
public class CustomerMetaData
{
[StringLength(150, ErrorMessage="Maximum length is 150 characters.")]
[Required(ErrorMessage="CustomerName is required.")]
public virtual string CustomerName
{
get;
set;
}
public virtual Nullable<int> Type
{
get;
set;
}
// ... etc ...
}
As you can see, you attach the rules to the MetaData class, thus abstracting it from the generated entity class.

ASP MVC3 Database-first

I use the entity framework for application ASP MVC3. At first I using code-first approach. I created the classes and used attributes to validate the data field
public class Person
{
public int ID { get; set; }
[Required(ErrorMessage = "Name can not be empty")]
public string Name { get; set; }
}
But when using database-fitst, I do not know how to validate the datafields.
In this case class Person is automatically created. How to do validate of its data fields?
Here's my $0.02 worth. If you want to validate your model which has been generated by entity framework using the Database first approach then you have to make use of a concept called 'Buddy' class. I believe Scottgu has a great article on that. As you can see the model classes generated by Entity Framework are partial classes meaning to say you can also create your own partial class to hold the so called attributes or to describe the metadata of the generated model. These partial classes will then be combined to form one class at runtime. Please do check out ScottGu's blog
here: http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx
Hope this answers your question.
Hard to understand what exactly you mean, but I can recommend reading this.
The concept of Code First is simple:
You create the classes. In your classes you can use the Required attribute just like you would with the normal Entity Framework
EFCodeFirst creates the database tables for you.

Custom Validation with MVC2 and EF4

on ScottGu's Blog is an Example how to use MVC2 Custom Validation with EF4:
http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx
So here the Problem:
When the Designer in VS2010 creates the Objects for the DB, along to the example you have to add [MetadataType(typeof(Person_validation))] Annotation to that class.
But when i change anything in the Designer all these Annotations are lost.
Is it possible to keep self made changes to the edmx file, or is there any better way of applying System.ComponentModel.DataAnnotations to the generated Entities?
Thanks.
You do it with a pattern loosely called "buddy classes". Basically what you do is create a separate class with your metadata, and create a partial class that couples the generated entities to your buddy class.
For a simple example, let's say you have a Person entity, and you want to set the FirstName property to be required. This is what you'd do outside of your generated files:
[MedadataType(typeof(PersonMetadata))]
partial class Person { } // the other part is generated by EF4
public class PersonMetadata
{
// All attributes here will be merged into the generated class,
// thanks to the partial class above. Just apply attributes as usual.
[Required]
public string FirstName { get; set; }
}
You can find more details on this approach here. And ScottGu actually talks about it too, in the article you linked to. Look under the headline "Step 5: Persisting to a database" ;)

ASP.NET MVC 2 validation using DTOs instead of domain entities

I'm struggling to mesh two best practices together:
Using DataAnnotations + ModelBinding for validation in ASP.NET MVC 2
Using DTOs instead of domain entities when passing data via the ViewModel
If I want to pass over DTOs instead of domain entities, then leveraging DataAnnotations + ModelBinding for validation would require me to specify validation attributes on my DTO classes. This results in a lot of duplicated work since multiple DTOs may hold overlapping fields with the same validation restrictions. This means that any time I change a validation rule in my domain, I have to go find all DTOs that correspond with that value and update their validation attributes.
You shouldn't have more than one DTO per entity, so you should only have to apply the validation attributes once per DTO. If you need multiple entities for a View, include multiple DTO's as properties of your ViewModel.
You might find useful this.
And keep in mind that validation lives everywhere. There is nothing wrong if DTOs applies UI validation (like getting necessary fields filled, datetime in correct format etc.) and domain objects - domain validation (e.g. account has money before withdrawn operation).
You can't create validation universal. Best thing You can do - put it in appropriate places.
And weed that feeling about duplication out. Usage of DTOs usually means applying single responsibility principle. There is no duplication if you got 2 customer objects where one is responsible for carrying business logic and second that is responsible for displaying it.
Maybe you could use meta annotations, which puts the attributes on a separate class:
namespace MvcApplication1.Models
{
[MetadataType(typeof(MovieMetaData))]
public partial class Movie
{
}
public class MovieMetaData
{
[Required]
public object Title { get; set; }
[Required]
[StringLength(5)]
public object Director { get; set; }
[DisplayName("Date Released")]
[Required]
public object DateReleased { get; set; }
}
}
Code sample was borrowed from this article.

Resources