SOA architecture for ASP.NET with Entity Framework
I am redesigning a solution's architecture to implement SOA.
After doing the design changes I have come up with:
- MySolution.Client.MyProject.Web ...... //ASP.NET WebSite
- MySolution.Client.MyProject.Proxy .... //Service Proxy C# Library Project *1
- MySolution.Service ................... //Service.cs for Service.svc is here
- MySolution.Service.DataContract ...... //IService.cs for Service.cs is here *[2]
- MySolution.Service.HttpHost .......... //Service.svc is here
- MySolution.Model ..................... //All custom data classes and EDMX model is here *[3]
- MySolution.Repository ................ //Repository queries the DB using LINQ and ADO.NET queries
*1 MySolution.Client.MyProject.Proxy: This project contains service proxy and contains presentation classes
*[2]MySolution.Service.DataContract:
- This project contains IService and Request/Response Classes
- All methods in Service.cs takes the Request classes as input and return Response classes as output
- Therefore this project is referenced by the 2 Client Projects(Web and Proxy), as it contains the IService and a开发者_运维知识库ll of the Request/Response classes that will be required to communicate with Service.cs
*[3]MySolution.Model: This project contains the .edmx that is the Data Model of Entity Framework and some custom classes that are used in the project.
PROBLEM:
Because I only use request/response classes to communicate between service and client, the MySolution.Service.DataContract project is only used by Service.cs and Repository.cs
And due to that all responses that Repository generates I have to map them to the properties of its respective response class (which make both the original returned entity, and the response class almost identical). But I am OKAY with it...
For example:
- The GetCustomer() in Repository.cs method is called by Service.cs
- The GetCustomer() method in repository performs the LINQ query and returns a "Customer" object
- Service.cs then maps all the properties of "Customer" object to the "CustomerResponse" object
- Service.cs then returns the "CustomerResponse" to the caller.
In this case, most of the properties will repeat in both classes. If there is a solution to this, it's good, otherwise, I am fine with it.
However, when Repository.cs's method GetCustomers() (Notice it's not GetCustomer()) is called, it will return a list of Customer objects, and mapping this for return purposes would mean a "for loop" that iterates the collection and do the mapping... This is NOT OKAY...
Is there a better way of doing this, considering I do not want to return "Customer" object without "CustomerResponse" as first of all it violates the SOA architecture, and secondly I don't want my client projects to have any reference to the Model or Repository projects?
So is it just the mapping that you're having trouble with? If so, you could look at some open source mapping libraries like Mapper Extensions or AutoMapper that will automate the task.
If you don't like separate mapping between entities and DTOs expose IQueryable
in your repository and use direct projections to DTOs. The disadvantage is that such solution can't be effectively unit tested. Mocking repository in such scenario doesn't make sense because query agains mock is Linq-to-objects whereas query against real repository is Linq-to-entities (different set of features where difference can be seen only at runtime).
Btw. I don't see too much SOA in your application - I see just multi tier application. It is like planting a tree in a garden and saying that you have a forest. Moreover it sounds like you are building CRUD interface (entities almost 1:1 to DTOs). I have a bad feeling that you are investing too big effort to architecture which you don't need. If your main intention is to build CRUD operations exposed as services on top of database you can expose entities directly moreover you can use tools like WCF Data services.
It sounds like your main point of grief is the tedious mapping of data objects to data transfer objects (DTOs). I haven't used this myself, but it seems like AutoMapper is made for doing automatic object-to-object mappings declaratively.
I would definitely stick to having your data objects separate from the data contracts in your services.
精彩评论