Passing data between layers in SOA model / smart client application
Hello there,
We are developing an application in .NET Smart Client application which connects to a WCF service and then to the data access layer. The issue we have here is on the type of data which can be passed between the client side and web service.
1. Can it be a dataset (No!), custom entity or XML or anything else ?
Which is the best one ?
2. Ofcourse , a dataset can't be used coz it can't be used in non-.NET environment?
3. If we go for custom-entity or XML how do we ensure the changes happen to the data during client-side actions ? For example, binding the XML or custom entity to a data grid can be done. But if user makes any changes to the same, how do we identify ?
4. If we use custom entities / XM L, the same can not be passed to the Data Access Application Block which invokes the data objects.
Note : All the above are based on assumptionwithout using a translator in between any of the layers.
Please provide a better solution if you have come across any.
NellaiMani wrote: |
| 2. Ofcourse , a dataset can't be used coz it can't be used in non-.NET environment? | |
Basically for non-.Net environment the will looks like XML
.
NellaiMani wrote: |
| 3. If we go for custom-entity or XML how do we ensure the changes happen to the data during client-side actions ? For example, binding the XML or custom entity to a data grid can be done. But if user makes any changes to the same, how do we identify ? | |
1) Keep versions;
2) Mark changed entities, I prefer list of changes;
Both of these solutions gives something like unit-of-work, however have issues in form of management of the concurrency and server side errors.
Sometimes this is better to explicitly save changes of the entity. This can give real time server processing, however violate offline support.
NellaiMani wrote: |
| 4. If we use custom entities / XM L, the same can not be passed to the Data Access Application Block which invokes the data objects. Note : All the above are based on assumption without using a translator in between any of the layers. | |
This is true. However you can try some kind of Entity to relational data mapping tool or generators this can be generators. Microsoft provides Data Access Software Factory that can generate complete Data Access Layer in terms of the DDD.
| NellaiMani wrote: |
| 2. Ofcourse , a dataset can't be used coz it can't be used in non-.NET environment? | |
Basically for non-.Net environment the will looks like XML .
What if when you have DataSet as argument to a WebMethod ? How does it look when non-.net environment. Have you come across a best data entity can be used across web service ?
Typed datasets has some issues with the format which it serializes and uses external references to the XSD files, you can tweak this to be more interopable but I've found them to be more headache then anything else in interop scenarios.
In WCF you really should go the DataContract path and have specified contracts, which you control, what data should be communicated and how. Data contracts has the benefit of giving you alot of options so you can explicitly define your intent.
I would also argue that the data contracts that defines the data that is communicated should be separate from the model you use for accessing data. The Data Contract should define the information flow between services and consumers and not the model used to implement the service itself.
Creating specific data contracts will allow for better service designs and helps you design around the UoW / Versioning issues and will also streamline the information sent over the wire.
For example,
I have a model with questions and answers. To the consumer I want to send complete question informtion for presentation. But when answering the question there is actually no point in sending full question information back from the consumer to the service to add the answers.
the contracts I use for this scenario looks similar to this:
To get the questions ( public GetSurveyResponse GetDefaultSurvey() {} ):
[DataContract(Namespace = "http://schemas.cornerstone.se/SurveyCollector/GetSurvey")]
public class GetSurveyResponse {
[DataMember]
public Guid Id;
[DataMember]
public string Title;
[DataMember]
public List<SurveyQuestionItem> Questions = new List<SurveyQuestionItem>();
}
[DataContract(Namespace = "http://schemas.cornerstone.se/SurveyCollector/GetSurvey")]
public class SurveyQuestionItem {
[DataMember]
public string Text;
[DataMember]
public int Weight;
[DataMember]
public QuestionTypes Type;
[DataMember]
public Guid Id;
}
To send the answers ( public void AnswerSurvey(SurveyAnswerRequest request) {} )
[DataContract(Namespace = "http://schemas.cornerstone.se/SurveyCollector/AnswerSurvey")]
public class SurveyAnswerRequest {
[DataMember(IsRequired = true)]
public string StudentEmail;
[DataMember(IsRequired = true)]
public string ClassNo;
[DataMember]
public List<SurveyAnswerItem> Answers;
}
[DataContract(Namespace = "http://schemas.cornerstone.se/SurveyCollector/AnswerSurvey")]
public class SurveyAnswerItem {
[DataMember]
public Guid QuestionId;
[DataMember]
public object Value;
}
This guarantees that I just send the information neccessary to complete the operation I'm calling.
Thanks, If we use custom entity / Data contract, how do I save the data in the database ? I mean how do I pass this to the Data Access Application Block ? Any Idea ?
You will have to move it out of the DataContract objects either by hand or with some nifty O/DataSet mapping code. It's very much the same principles that you apply to your GUI, you don't create a NameTextBox control, you keep the datamodel and the UI controls separate. The idea is to keep the contracts and the implementation separate to ensure that the implementation don't influence the contracts to much.
This is how it's done in one of the methods of the example contracts in the post earlier (I don't use DAAB for this project, instead the implementation is built in a DDDish style with NHibernate as persistence layer)
Code Snippet
public void AnswerSurvey(SurveyAnswerRequest surveyAnswer) {
using(SessionScope scope = new SessionScope()) {
ISurveyRepository repository = new SurveyRepository(scope);
ISurveyFactory factory = new SurveyFactory(repository);
Survey answeredSurvey = factory.CreateFor(surveyAnswer.StudentEmail, surveyAnswer.ClassNo);
foreach (SurveyAnswerItem answerItem in surveyAnswer.Answers) {
answeredSurvey.AnswerQuestion(answerItem.QuestionId)
.With(answerItem.Value.ToString());
}
repository.Save(answeredSurvey);
}
}
Congratulations - your post has been selected for an ARCast.TV Rapid Response!
To listen to C# MVP Patrik L?wendahl and Ron Jacobs address your question click here
Hope this helps,
Ron Jacobs
What you have here is not only layers, but tiers - client, app server, and database.
Translation code is good for you. It decouples your layers.
Personally we use a custom code generator based on templates. Here is what we do:
1. We read the database schema and gather metadata in an xml file.
2. We pass this file to a template and generate code creating entities and entity collections from the database.
As collections are serliaizable, they can move between the layers over http. Another feature of collections is that you can easily bind them to a grid or any other control and they are more light weight that the dataset.
If you want to identify changes to an entity, I advise using flags for each field or for each entity (if you generate it won't cost you a thing to implement).
If you are not already using code generators, I suggest you start researching the possiblility as it has already saved us a ton of time.
Another good piece of advise is to use MS patterns and practices as your base framework, as this will ensure better performance (we tested this through a performance tool), and proper handling of connections.