If you have missed part one of this tutorial, you can find it here. You will need to have completed the first part of the tutorial in order to complete this one. In this part you will create the data contracts for this service, the business entities, and the translators to go between them. Just like with classic web services, your data contracts and business entities are essentially different objects as far as .Net is concerned, so you have to create something to map their properties to one another. To get started, you need to have the project loaded up.
Right click on the MyCryptographyService.model project and select Add –> New Model
Opt to create a new “Data Contract Model”. Fill in the Mode name as CryptographyService.DataContracts and the XML Namespace as https://peteonsoftware.com (or whatever you’d like).
You should now have a blank visual designer canvas. Click on the canvas and then view your Properties window (you can’t right click and get properties). Click in the “Implementation Technology” property and choose “WCF Extension”.
You also need to choose the Project Mapping table for the contracts. This is the XML document (found by default in ProjectMapping.xml) that tells the WSSF which role each project will play and where to auto generate the code. This file can be edited and changes are not overwritten. Set the Project Mapping Table property to MyCryptographyService.
Your toolbox will give you context sensitive tools depending on what part of the project that you are working on. While building data contracts, you will see the tools shown below. A Data Contract represents your serializable objects. The Data Contract Enumeration represents your serializable enumerations. Primitive Data Type Collections and Data Contract Collections represent collections of .Net Data Types and your own custom contracts respectively. You can choose what form these collections take, but most often, I could recommend List
Next you need to drag a “Data Contract Enumeration” out of your toolbox and onto the visual designer. Click the name on the top (most likely DataContractEnum1) and change its name to HashType. Right click on the contract and choose Add–>Value. Add values of MD5 and SHA256 to the enumeration.
Drag another Data Contract Enumeration onto the surface and name it EncryptionAlgorithm. Add two values, called DES and Rijndael to the enumeration. When you are finished, your surface should look something like this.
Now, drag a “Data Contract” from the toolbox onto the designer. Change its name to HashObject in the same way that you renamed the enumeration. Right click on the contract and select Add–>Primitive Data Type. Name this property “StringToHash”.
Let’s now take a look at the properties of this Primitive Data Type that you just added. It has a type of System.String and an order of 0. For any future Primitive Data Types you add, you may need to change the data type here. You also need to set the order here, as well. For now, we can accept the defaults.
Now, select the Aggregation tool from the toolbox and click on the HashType enumeration, hold down your mouse button, and drag the connection over to the HashObject. This will create a new member on the contract. Set its order to 1.
Your HashObject and HashType should look like this on the designer.
You should also create an EncryptionObject by dragging another “Data Contract” onto the designer and setting a Text member and an EncryptionType member in the exact same manner as you did with the Hash Object. When you are finished, you should have these four entities on your designer.
Right click on any area of whitespace on the designer and click “Validate”. You should have no errors. If you do, make sure that you properly followed all of the steps in this tutorial.
Next, right click on some whitespace again and click “Generate Code”.
If you inspect your MyCryptographyService.DataContracts project’s “Generated Code” folder you will find that some classes have been generated for you. Keep in mind that whenever you make changes to your data contracts, you must regenerate the code and these classes will be overwritten. Fortunately, these classes are created as partial classes, so you can make another .cs file and extend these contracts if you really need to.
Right click on the project MyCryptographyService.BusinessEntities and choose Add–>Class. Name the .cs file CryptographicEntities.cs. Inside this file, we will define all of our business entities that the data contracts model so that they can be used elsewhere in our solution. Normally, you would define each of these in their own file, or group them in some other way, but for the purposes of this tutorial we will put all of the code in this file. Replace all of the contents of CryptographicEntities.cs (except the using statements) with the following code.
namespace MyCryptographyService.BusinessEntities
{
public enum EncryptionAlgorithm
{
DES = 0,
Rijndael = 1
}
public enum HashType
{
MD5 = 0,
SHA256 = 1
}
public class EncryptionObject
{
public string Text { get; set; }
public EncryptionAlgorithm EncryptionAlgorithm { get; set; }
}
public class HashObject
{
public string StringToHash { get; set; }
public HashType HashType { get; set; }
}
}
Now, right click on the MyCryptographyService.ServiceImplemenation project and choose “Create Translator”.
In the First Class to map, choose the DataContracts.EncryptionObject. For the Second Class to map, choose the BusinessEntities.EncryptionObject. Name the mapping class “EncryptionObjectTranslator” and set the namespace to MyCryptographyService.ServiceImplementation.
Choose the Text Property in each of the boxes and click map. Then click finish. You can’t map the enumerations from this dialog and will have to edit the code manually. As long as you don’t regenerate this translator, you don’t have to worry about overwriting the manual changes. In fact, I recommend doing this once to get your guidelines and maintaining it manually anyway.
Repeat this process for our HashObjects. Name the translator HashObjectTranslator and only use the wizard to map the StringToHash properties. Next, open up the translators and make the code look like the following: (Note, I aliased the namespaces to make them shorter and easier to work with).
HashObjectTranslator:
using System;
using MyCryptographyService.DataContracts;
using MyCryptographyService.BusinessEntities;
using Contract = MyCryptographyService.DataContracts;
using Entity = MyCryptographyService.BusinessEntities;
namespace MyCryptographyService.ServiceImplementation
{
public static class HashObjectTranslator
{
public static Contract.HashObject TranslateHashObjectToHashObject(
Entity.HashObject from)
{
Contract.HashObject to =
new Contract.HashObject();
to.StringToHash = from.StringToHash;
to.HashType =
(Contract.HashType)from.HashType;
return to;
}
public static Entity.HashObject TranslateHashObjectToHashObject(
Contract.HashObject from)
{
Entity.HashObject to = new Entity.HashObject();
to.StringToHash = from.StringToHash;
to.HashType = (Entity.HashType)from.HashType;
return to;
}
}
}
EncryptionObjectTranslator:
using System;
using MyCryptographyService.DataContracts;
using MyCryptographyService.BusinessEntities;
using Contract = MyCryptographyService.DataContracts;
using Entity = MyCryptographyService.BusinessEntities;
namespace MyCryptographyService.ServiceImplementation
{
public static class EncryptionObjectTranslator
{
public static Contract.EncryptionObject TranslateEncryptionObjectToEncryptionObject(
Entity.EncryptionObject from)
{
Contract.EncryptionObject to =
new Contract.EncryptionObject();
to.Text = from.Text;
to.EncryptionAlgorithm =
(Contract.EncryptionAlgorithm)from.EncryptionAlgorithm;
return to;
}
public static Entity.EncryptionObject TranslateEncryptionObjectToEncryptionObject(
Contract.EncryptionObject from)
{
Entity.EncryptionObject to =
new Entity.EncryptionObject();
to.Text = from.Text;
to.EncryptionAlgorithm =
(Entity.EncryptionAlgorithm)from.EncryptionAlgorithm;
return to;
}
}
}
That’s it. You should be able to successfully build your project now and you are now ready for Part 3. If you have any problems, please feel free to leave them in the comments and I will try to get back to you as quickly as I can. Next time, we will create and implement our service contracts. Until then.
[…] you missed the beginning of the series, you should check out Part 1 and Part 2 before beginning this part if you want to follow […]
[…] in the home stretch. If you haven’t already, you may want to take a look at tutorial parts 1, 2, and 3 before beginning this […]
hi, i need to do it with a linq connection, do i have to use data contract in the data contract tools?, and the values have to be the same as my db table?
its hard to find a web service factory example with wcf and linq, do you know where i can find any examples?
thank youuuuu =D
liliana,
Your data contracts are strictly for what will be sent back from the service to the caller. Your business entities are what any ORM tool would be mapping (LINQ to Sql included). You have LINQ fetch your data into its entities (which will most often look like your DB), and then you use the translators to map what properties of your LINQ entities map to what properties of your data contracts.
I’ve had several requests to get the source of this tutorial up and online, so maybe I’ll see if I can find it (or just redo the tutorial myself) and maybe I’ll make a LINQ to Sql version as well.
ok =] ill be waiting for your examples, im totally new to this wssf thing so i get confused haha but thanks for your answer =]
Hi.
I need some help with these translators. Im using the Service Factory to make a Golfing service ( for school ), and i have a problem.
So, i have golf courses, and each golf course has 9 or 18 holes. In the Data Contract Model, i have a Data Contract for courses ( Name, Par, CourseRating, etc. ) and one for holes ( HoleNo, Distance, Handicap, etc. ). All i want, is for the Course class to have an array of HoleData objects, and the problem is i dont know how o properly connect these two contracts.
I tried setting the collection type of the HoleData member that appears in the Course contrat, but no matter what i do, when i try to generate the translator and to map the DataContracts.Course HoleData(HoleData[]) with the BusinessEntities.Course HoleData(HoleData[]) i get an “Invalid Property Mapping” error, saying it can’t map, and possible reasons being incopatible types or unavailable getter/setter pairs.
I hope you understood my problem, and you can help me fix this problem.
And thank you for the tutorial, it helped a lot!
Cheers!
Darko,
You need to create a HoleData translator class and then call that from within your Course translator class. Inside that HoleData translator, create 4 static methods: TranslateToEntity (takes a contract and returns an Entity), TranslateToContract (takes an Entity and returns a Contract), TranslateToEntities (takes an array of contracts and returns an array of Entities), and TranslateToContracts (takes an array of Entities and returns an array of Contracts).
The issue is one of the C# language. You can map simple types from one namespace to another without casting, but complex objects or collections need cast.
So inside the Course Translator, you would call the HoleData translator like this:
// assume I have a Course Contract Object foo
// and a Course Entity Object bar
foo.HoleData = HoleDataTranslator.TranslateToContracts(bar.HoleData);
Meanwhile, over in the HoleDataTranslator, you could implement the TranslateToContract method exactly like in my examples for each property of HoleData. For the TranslateToContracts method, you could then call it either like:
// Assuming a HoleData Entity Object of goog
var bing = new DataContract.HoleData[goog.Length];
for (var i = 0; i < goog.Length; i++) { bing[i] = TranslateToContract(goog[i]); } return bing; or in a shorter way available in .Net 3.5/C# 3 // I usually use generic lists for collections // because of methods like ConvertAll which are // very easy to use return goog.ToList().ConvertAll(g => TranslateToContract(g)).ToArray();
There is a lot there, but hopefully I’ve gotten you on the right track. The main thing to remember is that you need a new translator (HoleDataTranslator), whose static methods will be called from within the CourseTranslator to map those properties you are having trouble with.
Happy Coding.
Thank you for the quick reply.
I did everything you said ( hopefully it’s correct ), made the HoleData translator and all the methods. So far so good. Everything compiled like it should and when i finish the rest of the code, i’ll give it a try.. Shouldn’t be difficult from now on since i know what the problem was.
Thanks for your help!
Hello again.
I have another problem with my project. Working with strings is fine, but i get problems when i try to work with more complex types. For example, i would like my service to return a list of all players in the database. How do i aproach that? Can i just return a DataSet back to the client app? If so, how?
Even when trying to return a “Player” type, i get problems.
in the GolfImplementation.cs, where im supposed to call the translators, i have this code:
GetPlayerResponse response = new GetPlayerResponse();
response.PlayerPartResponse = businessLogic.GetPlayer(PlayerTranslator.TranslatePlayerToPlayer(request.PlayerPart));
return response;
GetPlayer method in the GolfBusinessLogic.cs is a “Player” type, and so is the one in GolfManager.cs, because i assumed im supposed to return a Player type back to the client app. Anyhow, i keep getting the “Cannot implicitly convert BusinessEntities.Player to DataContracts.Player” error in the code above and i cant get arround it. The Translator works only with strings and a integer, so that cant be the reason.
Sorry for bothering you with this, i know it’s getting a bit out of the whole Service Factory topic so i’d really appreciate your help!
Cheers!
Darko,
The issue is that your GetPlayer method of your businessLogic class is returning entities. You need to call the entity to contract translator on the results of that method before assigning it to response.PlayerPartResponse.
Using this style, it isn’t uncommon to have to translate coming in from the request and then have to translate back to send a response.
It is generally considered bad to return a dataset from a service. A common set of steps would look like this:
1. Request comes in with an id or search string, etc
2. Pass these (usually simple objects – string, int, etc) to the logic layer for validation. If they are complex objects themselves, they need translated from contract to entity before passing to Logic Layer.
3. Logic validations are performed by logic layer and parameters are passed in some form to the data access layer
4. Data access layer takes those parameters and through your chosen means (ado.net, linq to sql, nHibernate, etc) gets the data and creates business objects, passing them back to the logic layer.
5. Logic layer may or may not perform validations on these objects and then passes them back to the original calling layer.
6. Service implementation layer takes this business object or collection of business objects and translates them into data contracts, which are then assigned into the response object and returned back to the service’s caller.
If you are still having problems, you could always zip your code and email it to me at peter [dot] shearer [at] gmail [dot] com or put it in a public source repository and I can take a look at it and see if I can spot the problems.
Okay, i got the GetPlayer working, pretty straightforward actually, dont know how i missed it.
About the data:
i should use the Data Contract Collection to send the data back to the client? Or just use arrays and make a translator like the one for HoleData?
Thank you, you’ve been really helpful!
I use the data contract collection most often. When it gets to the client, it is either a List or an array (you configure that in properties) and can be treated as such. So, you would make a translator from the List of entities to the data contract collection and then return that collection.