I am eating myself up at this moment. It is like Entity Framework isn't testable. I've read alot of posts and threads where they use unit of work or moq or the repo pattern.
I am in a phase that i can't change alot of my architechture of my application. The application fully works at this moment but to be sure I need to have a high code coverage, so testing it is.
For testing, I am using the 'fake context' method where I can use the fake one for mocking and the real one for connection to the database.
I used this as an example.
http://romiller.com/2010/09/07/ef-ctp4-tips-tricks-testing-with-fake-dbcontext/
There, you can see that the context is splitted and used as an interface. Like:
public interface IEmployeeContext
{
IDbSet Department Departments { get; }
IDbSet Employee Employees { get; }
int SaveChanges();
}
public class EmployeeContext : DbContext, IEmployeeContext
{
public IDbSet Department Departments { get; set; }
public IDbSet Employee Employees { get; set; }
}
public class FakeEmployeeContext : IEmployeeContext
{
public FakeEmployeeContext()
{
this.Departments = new FakeDepartmentSet();
this.Employees = new FakeEmployeeSet();
}
public IDbSet Department Departments { get; private set; }
public IDbSet Employee Employees { get; private set; }
public int SaveChanges()
{
return 0;
}
}
}
So tesing and everything works. The only thing i can't seem to do, is test a controller with .State in it where i check whether it's changed Like:
EntityState.Modified
Because this uses an interface I need to add that into the interface context. And create a new one. Or am I missing something ? It is likely not the intention that I create the whole method in that context.. How can I manage to get this to work
Have you considered performing integration tests instead?
You can have integration tests against a real EF DBContext,
just give it a different connection string in the App.config of the unit-tests project.
Read this and all of the answers to it.
Just add the property in the context interface. Btw, you don't need the FakeContext, you can just create a mock of the interface, and setup the properties to return your fake datasets. That way, you can add/remove as many methods and properties in the interface, as you need.
Thanks to #Liel I managed to get this work. creating a 'test' db for integration testing.. instead of using unnecesary code in my opinion. My project is now fully independend by using this method.
[TestInitialize]
public void InitializBeforeTests()
{
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ""));
Database.SetInitializer<DataAccess.DataContext>(new DropCreateDatabaseAlways<DataAccess.DataContext>());
var context = new DataAccess.DataContext();
context.Database.Initialize(force: true);
}
and creating a new connection string in my test project in APP.Config.
Thanks all for your answers !
Related
I just stumbled onto Audit.Net and I'm hooked. I went through the Audit.Net Entity Framework (6) documentation and am a bit lost in the output part.
My solution is a bit many-layers design:
Mvc 5 website
Wcf Client
Using WcfClientProxyGenerator
Wcf Service
Separate IService Contracts Library
All interfaces expose BDOs
Business Logic
Seperate BDO Library
Data Access
Reference EF6
Reference Audit.Net
DTOs
Entity Framwework Library
Has EDMX only
Reference Audit.Net
Reference: My EDMX is named Focus
Usage
I manage to modify the FocusModel.Context.tt from:
partial class <#=code.Escape(container)#> : DbContext
To:
partial class <#=code.Escape(container)#> : Audit.EntityFramework.AuditDbContext
Configuration
I found the default setting for Mode, IncludeEntityObjects, & AuditEventType were to my liking. the attribute for Include/Ignore entities/properties were straightforward as well.
Output
This is where I'm confused. I need to audit to the same database preferably to Audit tables for selected entities. Every entity in my database has composite PKs. How do I set the output mode in this scenario? Also, in my solution setup, the starting point for all projects that are behind the WCF Service is the WCF service itself. Does this mean that the point to Fluent-API-configure Audit.Net is here?
Have you seen the main Audit.NET documentation, specifically the output data providers?
I need to audit to the same database preferably to Audit tables for selected entities. Every entity in my database has composite PKs.
So you can use the EF data provider. It works with any kind of primary key.
How do I set the output mode in this scenario?
I'm not sure what do you mean by output mode, but I'm guessing you ask about OptIn/OptOut to ignore your audit entities to be audited. If that's the case you have multiple options, like using AuditIgnore attribute on your audit POCO classes, or via the fluent-api OptIn()/OptOut() methods. See example below.
The starting point for all projects that are behind the WCF Service is the WCF service itself. Does this mean that the point to Fluent-API-configure Audit.Net is here?
You can configure the Audit.NET library in any place, but you must do it before any audit event creation, so it is recommended to be on your startup code, as soon as your app or service starts.
Sample code
The following is a minimal example showing how you can configure the Audit.NET and Audit.EntityFramework libraries.
Suppose you have the following schema:
public class Student
{
public int PK_1 { get; set; }
public string PK_2 { get; set; }
public string Name { get; set; }
}
public class Student_Audit
{
public int PK_1 { get; set; }
public string PK_2 { get; set; }
public string Name { get; set; }
public DateTime AuditDate { get; set; }
public string AuditAction { get; set; }
}
public class SchoolContext : AuditDbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder) //<--Tip: its not DbModelBuilder, its Microsoft.EntityFrameworkCore.ModelBuilder
{
modelBuilder.Entity<Student>().HasKey(c => new { c.PK_1, c.PK_2 });
modelBuilder.Entity<Student_Audit>().HasKey(c => new { c.PK_1, c.PK_2, c.AuditDate });
}
public DbSet<Student> Students { get; set; }
public DbSet<Student_Audit> Students_Audit { get; set; }
}
You can configure the library on your startup code as follows:
// Setup audit to use the EF data provider
Audit.Core.Configuration.Setup()
.UseEntityFramework(_ => _
.AuditTypeExplicitMapper(m => m
// Map Student to Student_Audit
.Map<Student, Student_Audit>((ev, ent, studentAudit) =>
{
//add the action name and the date to the audit entity
studentAudit.AuditAction = ent.Action;
studentAudit.AuditDate = DateTime.UtcNow;
})));
// Configure the EF audit behavior
Audit.EntityFramework.Configuration.Setup()
.ForContext<SchoolContext>(_ => _.IncludeEntityObjects())
.UseOptOut()
.Ignore<Student_Audit>(); // Do not audit the audit tables
And a test case:
using (var db = new SchoolContext())
{
db.Database.EnsureCreated();
var st = new Student() { PK_1 = 1, PK_2 = "one", Name = "John" };
db.Students.Add(st);
db.SaveChanges();
}
Will generate the following:
I am a bit lost right now... I've never seen this much divergent information regarding solution to the problem. But let us start from the beginning.
I am using ASP.NET MVC with Repositories injected to Controllers, thanks to the Ninject. I have 2 simple Entities: Admin with a list of created blog entries and Entries with one virtual Admin field.
Admin:
public class Admin
{
[Key, ScaffoldColumn(false)]
public int Id { get; set; }
[Required(ErrorMessage = "Zły login.")]
[StringLength(20), MinLength(3)]
[RegularExpression(#"^[a-zA-Z0-9]*$", ErrorMessage = "Special characters are not allowed.")]
public string Login { get; set; }
[Required(ErrorMessage = "Złe hasło.")]
[StringLength(20, MinimumLength = 3)]
[DataType(DataType.Password)]
[Display(Name = "Hasło")]
public string Password { get; set; }
public virtual List<Entry> CreatedEntries { get; set; } // napisane aktualności przez danego admina
}
Entry:
public class Entry
{
[Key, ScaffoldColumn(false)]
public int Id { get; set; }
[StringLength(200, MinimumLength = 2)]
[DataType(DataType.Text)]
[Display(Name = "Tytuł")]
public string Title { get; set; }
[Required, StringLength(2000), MinLength(3)]
[Display(Name = "Treść")]
[UIHint("tinymce_jquery_full"), AllowHtml]
public string Text { get; set; }
public virtual Admin Admin { get; set; }
}
You probably know where it is going, since this problem is... "classic" on stackoverflow.
In the Controller I want to bind one object to another:
entry.Admin = repAdmins.GetAdmin(User.Identity.Name);
repEntries.AddEntry(entry);
In the repository:
public void AddEntry(Entry entry)
{
db.Entries.Add(entry);
db.SaveChanges();
}
Of course I can't do that, because of famous "An entity object cannot be referenced by multiple instances of IEntityChangeTracker", which is a result of having separate database contexts in each repository.
When I was searching for a solution I already knew that probably the best way to solve it is to use one common context. And then I discovered Unit Of Work pattern. But here's when the real problems starts.
On many sites the solution to this is a bit different.
The repositories must have common generic interface (which I don't want to use, because I don't need to have each CRUD operation on each Entity, plus sometimes I need to have extra methods like "IfExists", etc.)
On few sites I've read that this whole abstraction is not needed, since abstraction is already provided with Entity Framework and UoW is implemented in DbContext (whatever that means)
The Unit Of Work pattern (at least from examples on the internet) seems to be a real pain for me...
I need some guidance... I learn ASP.NET MVC for only a year. For me it seems like it's a "triumph of form over content". Because... What I simply need is to bind one object to another. I'm starting to think that it was better when I simply had a context object in the Controller and I didn't need to build Eiffel Tower to achieve what's mentioned above :\ However I like idea of repositories...
I'll open by simply answering the question straight-out. Simply, your repository should take the context as a dependency (it should have a constructor that accepts a param of type DbContext). Your context should be managed by Ninject, and then injected into your repository and/or your controller. That way, everything always uses the same context. You should do all this in "request" scope, so that the context is specific to the current request.
That said, I'd like to hit some of your other points. First, a repository is just a method of access. It really shouldn't be dependent on the entity. It's okay to have methods that you don't intend to use on a particular entity: just don't use them. However, if you do want to enforce this, you can always use generic constraints and interfaces. For example, let's say you don't want update available on a particular entity. You could have interfaces like:
public interface ICreateable
{
}
public interface IUpdateable : ICreateable
{
}
Then, your entity that should not be updated will implement only ICreateable while other entities (which allow update) would implement IUpdateable (which by interface inheritance, also implement ICreateable). Finally, you would add constraints on your repository methods:
public void Create<TEntity>(TEntity entity)
where TEntity : class, ICreateable
public void Update<TEntity>(TEntity entity>)
where TEntity : class, IUpdateable
Since, the entity in question only implements ICreatable, it will not be eligible to be used as a type param to Update, so there's then no way to utilize that method.
Next, the advice to not use the repository/UoW patterns with Entity Framework is indeed because Entity Framework already implements these patterns. The repository pattern exists as a way to contain all the database querying logic (constructing SQL statements and such) in one place. That is the "abstraction" we're talking about here. In other words, instead of directly constructing SQL statements in your application code, that code is abstracted away into a repository. However, this is exactly what Entity Framework does, which is why you don't need to do it again. The Unit of Work pattern exists as a method to orchestrate the work of multiple repositories, allowing things like transactions. However, again, Entity Framework does all this.
The only reason to add any further abstraction is if you want to abstract the actual provider, i.e. Entity Framework itself. For example, you could have an interface like IRepository and then create implementations like EntityFrameworkRepository, NHibernateRepository, WebApiRepository, etc. Your application would only ever depend on IRepository, and you could then sub in different implementations as needed. If you're not going to do this, or you will always be using Entity Framework, then you might as well just use your context directly. Any further abstraction is just something else to maintain with no benefit at all to your application.
Finally, yes, the Unit of Work pattern is a real pain to everyone, not just you. Which is why I forgo it entirely. I use what I call a "truly generic repository", which utilizes generic methods and interfaces to handle any entity I want to throw at it. That means it acts not only as a repository but also a unit of work as well. You only need one instance per context and it's provider-agnostic. For more information check out the article I wrote on the subject over on my website.
The following example shows how to use the same context within multiple repositories. To simplify it, I did not use interfaces and nor did I use a container to inject dependencies.
Controller class:
public class HomeController : Controller
{
Context context;
AdminRepository adminRepository;
EntryRepository entryRepository;
public HomeController()
{
context = new Context();
adminRepository = new AdminRepository(context);
entryRepository = new EntryRepository(context);
}
// GET: Home
public ActionResult Index()
{
string login = "MyLogin";
Admin admin = adminRepository.GetAdmin(login);
Entry entry = new Entry() { Admin = admin};
entryRepository.AddEntry(entry);
return View(entry);
}
}
Repositories:
public class AdminRepository
{
Context context;
public AdminRepository(Context context)
{
this.context = context;
// This seeds the database
Admin admin = new Admin() { Login = "MyLogin" };
this.context.Admins.Add(admin);
this.context.SaveChanges();
}
public Admin GetAdmin(string login)
{
return context.Admins.Where(a => a.Login == login).FirstOrDefault();
}
}
public class EntryRepository
{
Context context;
public EntryRepository(Context context)
{
this.context = context;
}
public void AddEntry(Entry entry){
context.Entrys.Add(entry);
context.SaveChanges();
}
}
Context class:
public class Context : DbContext
{
public Context()
{
Database.SetInitializer<Context>(new DropCreateDatabaseAlways<Context>());
Database.Initialize(true);
}
public DbSet<Admin> Admins { get; set; }
public DbSet<Entry> Entrys { get; set; }
}
Modified Models:
public class Admin
{
public int Id { get; set; }
public string Login { get; set; }
}
public class Entry
{
public int Id { get; set; }
public virtual Admin Admin { get; set; }
}
Lately, I have invested my efforts into learning and understanding DI. Now that I'm growing more fluent with it, some other concerns come up.
Shall list members be injected into domain model?
In the famous example of Ninject, the idea as I see it is:
public class Warrior {
public Warrior(IWeapon weapon) { this.weapon = weapon; }
public void Attack() { weapon.Hit(); }
}
public Archer : Warrior {
// Here, the weapon would be bound to a bow.
public Archer(IWeapon weapon) : base(weapon) { }
}
public Ninja : Warrior {
// On the contrary, the weapon would here be bound to a katana.
public Ninja(IWeapon weapon) : base(weapon) { }
}
Hence contextual binding to define what weapon should be created depending on what the IWeapon is injected into.
I understand that injecting a DAO into my model would be implementing the Active Record design pattern, which is considered somehow an anti-pattern by some people. Others would prefer POCOs as domain objects, simple data representation, which is not following the rules of DDD.
Back to my concern, I would say that Warrior, Archer and Ninja are all part of my domain model.
Now, what if my model has an IList<T> instead of a IWeapon? Would DI be of any use, or would it become useless?
public class MyClass {
public MyClass(IList<MyOtherClass> myOtherClasses) {
MyOtherClassesA = myOtherClasses.OfType<MyOtherClassA>().ToList();
MyOtherClassesB = myOtherClasses.OfType<MyOtherClassB>().ToList();
}
public IList<MyOtherClassA> MyOtherClassesA { get; protected set; }
public IList<MyOtherClassB> MyOtherClassesB { get; protected set; }
}
Am I pushing it too far?
Am I missing something?
EDIT
No, do inject them! But don't inject one list of a base type, which you then split by derived types.
Let's put ourselves in the context of Scrum and a Sprint.
In a Sprint, the Development Team may have Bugs, Impediments, Tasks and UserStories.
All of these have a Title and a Description, plus some other properties specific to each type. Let's make an abstract class called Artifact (not ScrumArtifact).
Artifact
public abstract class Artifact {
public string Description { get; set; }
public string Title { get; set; }
}
Bug
public class Bug : Artifact {
public string Resolution { get; set; }
}
Impediment
public class Impediment : Artifact {
}
Task
public class Task : Artifact {
public float EstimatedTime { get; set; }
public float RealTime { get; set; }
}
UserStory
public class UserStory : Artifact {
public string AcceptanceCriteria { get; set; }
public int BusinessValue { get; set; }
public int Complexity { get; set; }
public IList<Impediment> Impediments { get; protected set; }
public IList<Task> Tasks { get; protected set; }
}
Here, I have a UserStory which "depends" on two lists: Impediments and Tasks.
So I should have the constructor of UserStory taking two lists as follows.
public UserStory(IList<Impediment> impediments, IList<Task> tasks) {
Impediments = impediments;
Tasks = tasks;
}
And my unit test:
[TestFixture]
public class UserStoryTests {
[Test]
public void ImpedimentsShouldBeInitializedByDefault() {
userStory.Impediments.Should().NotBeNull().And.BeOfType<IList<Impediment>>();
}
public void TasksShouldBeInitializedByDefault() {
userStory.Tasks.Should().NotBeNull().And.BeOfType<IList<Task>>();
}
[TestFixtureSetUp]
public void UserStorySetUp() {
impediments = new Mock<IList<Impediment>>();
tasks = new Mock<IList<Task>>();
userStory = new UserStory(impediments.Object, tasks.Object);
}
private Mock<IList<Impediment>> impediments;
private Mock<IList<Task>> tasks;
private UserStory userStory;
}
The problem comes with the Sprint. The Sprint rather require four lists, and I find it too much of objects to inject for clarity and readability. It is said, if I'm not mistaken, that a class with too much dependencies might break the Single Responsibility Principle. Though I'm not breaking the SRP even with the Sprint class, I feel quite uncomfortable with injecting four different lists. I thought I could use polymorphism to inject one list which would contain them all, since after all they are all basically Artifacts.
Perhaps shall I simply consider using the AbstractFactory pattern so that my four lists get initialized properly as expected, and I would only have to inject one single factory class which single responsibility consist of creating lists?
I think you misinterpreted the Ninject example a little bit. It doesn't involve different warrior classes, which are tied to a specific subtype of IWeapon. There's only a Samurai, who can use any type of IWeapon. So an Archer, who can only use a specific kind of weapon is not accounted for and wouldn't fit in well. Instead just inject a Bow into a Samurai.
Injecting lists is totally OK. Some DI containers even allow for autowiring lists. I.e. you can tell the container to inject all implementations of your interface found in a given assembly as a list.
But that only really works if you can treat all members in the same way, i.e. you don't have to differentiate by subtype. If you want to separate your warrior's melee weapons from his collection of bows, it's better to inject two different lists of two different types.
If you want to learn more about proper DI patterns, I can very much recommend Dependency Injection in .NET by Mark Seemann.
This has been addressed in multiple other questions, but alas, I have tried all the solutions posted there with no success. I'm developing an ASP.NET MVC application, using Code-First EF. I am trying to take advantage of the scaffolding built in so that it can automatically create a Controller for me based off my Model and DbContext. However, I am getting the following error when I try to create a Controller in this way:
'Unable to retrieve metadata for Employer.' Using the same DbCompiledModel to create contexts against different types of database servers is not supported. Instead, create a separate DbCompiledModel for each type of server being used.
The code for my model, Employer, my DbContext, MyDataContext, and my web.config file follow:
//Employer.cs
public class Employer : Organization, IEmployer
{
public virtual PhysicalAddress Address { get; set; }
public virtual ICollection<ContactMethod> ContactMethods { get; set; }
public int FederalTaxID { get; set; }
public virtual Client Client { get; set; }
}
-
//MyDataContext.cs
[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class MyDataContext : IdentityDbContext<ApplicationUser>
{
public MyDataContext()
: base("DataConnection")
{
}
static MyDataContext()
{
Database.SetInitializer(new DataInitializer());
}
public DbSet<Client> Clients { get; set; }
public DbSet<Organization> Organizations { get; set; } // Store Employer and OrgEntity
/// <summary>
/// Sets up unclear relationships between entities before the models are constructued in a database.
/// For example, models which extend other models must have their Ids mapped (because it is an
/// inherited member, and so is not found by Entity Framework by default)
/// </summary>
/// <param name="modelBuilder">the object responsible for constructing the database from code-first</param>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//set up parent organization relationship
modelBuilder.Entity<Organization>()
.HasOptional(n => n.ParentOrganization)
.WithMany(o => o.ChildOrganizations)
.Map(m => m.MapKey("ParentOrganization_Id"));
//set up the organization-employee assignment
modelBuilder.Entity<Employee>()
.HasOptional(a => a.OrganizationAssignment)
.WithMany(a => a.Employees);
//used to integrate Identity stuff into same db as Clients, etc.
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
}
}
-
<!--web.config-->
.
.
.
<connectionStrings>
<add name="DataConnection"
providerName="Mysql.Data.MysqlClient"
connectionString="server=localhost;user id=myid;password=mypass;persistsecurityinfo=True;database=app_db"/>
</connectionStrings>
.
.
.
From various other posts like this one , this one , and this one . I have tried many different things to get it to work. This includes commenting out my constructor for MyDbContext, changing the providerName attribute of my connection string to be "System.Data.SqlClient", changing the connection string name to be "DefaultConnection", removing my connection strings altogether, and combinations of all of these things. I make sure to rebuild between trying to add the Controller. However, after performing these different changes, I still receive the same error when I try to add a new Controller.
Generally, I can find all my questions already answered, but the answers don't seem to be working for me on this one. I think what might separate my case from the ones linked is that my DbContext is actually an instance of IdentityDbContext. I believe the constructor for IdentityDbContext just calls the base constructor for it, anyway, so I don't see how this could be much of an issue.
Any help is much appreciated. Thank you!
You didn't map your Employer entity to the model. That's why compiler is unable to retrieve metadata for Employer. Firstly, add DbSet as below and let me know, if does it work.
public DbSet<Client> Clients { get; set; }
public DbSet<Organization> Organizations { get; set; }
public DbSet<Employer> Employers { get; set; }
I'm starting to use AutoMapper and some doubts arose.
Where is the correct way to map a dto into a domain model?
I'm doing this:
DTO:
public class PersonInsert
{
[Required]
public string Name { get; set; }
public string LastName { get; set; }
}
Action:
[HttpPost]
public ActionResult Insert(PersonInsert personInsert)
{
if (ModelState.IsValid)
{
new PersonService().Insert(personInsert);
return RedirectToAction("Insert");
}
return View("Insert");
}
Service:
public class PersonService
{
public int Insert(PersonInsert personInsert)
{
var person = Mapper.Map<PersonInsert, Person>(personInsert);
return new PersonRepository().Insert(person);
}
}
Repository:
public class PersonRepository
{
internal int Insert(Person person)
{
_db.Person.Add(person);
_db.SaveChanges();
return person.Id;
}
}
So, is this correct? should my service knows about domain? or should I make the bind in repository only? is correct to use [Required] in DTO?
I would almost never create an entity from a DTO - I explain why below. I would use a request object to allow a factory method to build the entity:
Request:
public class InsertPersonRequest
{
[Required]
public string Name { get; set; }
public string LastName { get; set; }
}
Action:
[HttpPost]
public ActionResult Insert(InsertPersonViewModel viewModel)
{
if (ModelState.IsValid)
{
InsertPersonRequest request = InsertPersonViewModelMapper.CreateRequestFrom(viewModel);
new PersonService().Insert(request );
return RedirectToAction("Insert");
}
return View("Insert");
}
Service:
public class PersonService
{
public int Insert(InsertPersonRequest request)
{
var person = Person.Create(request.name, request.LastName);
return new PersonRepository().Insert(person);
}
}
Repository stays the same.
This way all logic for creating the Person are located in the Factory method of the person, and so business logic is encapsulated in the domain - derived fields, default fields etc.
The problem with what you are doing is that the DTO has to be created in the UI, then all fields are mapped to the entity - this is a sure fire way for business logic to seep into the service layer, UI, or anywhere it is not supposed to be.
PLease read that again - This is a very serious mistake I see made time and time again.
I would however, use AutoMapper in the service layer to return a DTO:
Service:
public class PersonService
{
public PersonDto GetById(intid)
{
var person = new PersonRepository().GetById(id);
var personDto = Mapper.Map<Person, PersonDto>(person);
return personDto
}
}
Is this correct?
I personally don't see anything wrong with having your service do the mapping
Is it correct to use [Required] in DTO
No, DTOs should have no business logic whatsoever. They should be used purely for transmitting data across different tiers/layers of your application.
DataAnnotations are typically used on ViewModels for client/server side validation, therefore, I would add another separation into your model and introduce a ViewModel for your Insert action e.g.
public class PersonViewModel
{
[Required]
public string Name { get; set; }
public string LastName { get; set; }
}
public class PersonDto
{
public string Name { get; set; }
public string LastName { get; set; }
}
Action:
[HttpPost]
public ActionResult Insert(PersonViewModel personViewModel)
{
if (ModelState.IsValid)
{
var personDto = Mapper.Map<PersonViewModel, PersonDto>(personViewModel);
new PersonService().Insert(personDto);
...
}
...
}
}
Service:
public class PersonService
{
public int Insert(PersonDto personDto)
{
var person = Mapper.Map<PersonDto, Person>(personDto);
return new PersonRepository().Insert(person);
}
}
It may seem overkill in this scenario (considering the only difference is the [Required] attribute). However, in a typical MVC application you would want to ensure a clean separation between your ViewModels and your business models.
I would say that your PersonService could be seen as part of the domain layer (or Application layer directly above the domain) of your architecture and the controller and DTO is in a layer above that. That means you shouldn't have a reference to the DTO in your PersonService signatures and instead use the domain Person class here. So the Mapping code should go into the Controller. This ensures that your domain logic is not affected by changes to the webservice contract which could really be just one way to use your PersonService.
I would also introduce an interface for your repository which is injected into your PersonService because the PersonService again shouldn't need to know about concrete data access implementations.
As for the [Required] attribute, I don't see a problem with having this on the DTO because it just states the data contract of your webservice method. Anybody calling your webservice should adhere to this data contract. Of course this requirement will typically also be reflected somewhere in your domain code, maybe by throwing an exception etc.
In ASP.NET MVC the typical use of DTO is being part of something called viewmodel. Viewmodel is a class that will combine one to several DTOs into one class tailored for view presentation and posting values back to server.
What you doing is correct, no issues with that, but data annotations should reside on view models, rather than DTOs. Unless you call your DTO a view model, then its fine.
Please read the following posting about model (Domain Model) vs ViewModel in ASP.NET MVC world:
ASP.NET MVC Model vs ViewModel
Confused with Model vs ViewModel
Hope this helps
I think it is fine to have annotations on the DTOs, such as [Required], MaxLength, Range etc.
Your DTO can come in from any (possibly untrusted) source (Not just your website, but from another endpoint, WCF service, etc). All requests will be funneled to your Service/Business Layers, so you will need to validate the input before performing your business logic (simple guard checks). Having the annotations on the DTO simply describe the needed input to perform the task at hand. Passing an object with annotations is not peforming validation.
However, I believe you should be validating the DTO information is correct in the service/business layer (and annotations are a nice way to check this).
Just my thoughts on the situation :)