This is an interesting and essential trick for WCF and sharing types between server and client.
Here is the scenario: at the server service implementation: you define types, essentially data structures, that you will return through service methods:
Let say you define the following data type (don't forget the DataContract and DataMember attributes since this type will be passed through the WCF service)
namespace MyTypes { [DataContract] public class MyDataTransfertObject { [DataMember] public int Value1 { get; set; } [DataMember] public string Value2 { get; set; } } }
And the following service interface:
namespace MyService { [ServiceContract] [ServiceKnownType(typeof(MyDataTransfertObject))] public interface IMyService { [OperationContract] MyDataTransfertObject GetDataTransfertObject(); [OperationContract] void SaveDataTransfertObject(MyDataTransfertObject dataTransfertObjectToSave); } }
Next step if to implement your service, by creating a class implementing your IMyService interface, and then deploy your service.
You can now create a client application, and add a reference to your service, in order to consume your service methods. If you do so without any extra step, Visual studio will create for you a proxy and as part of the proxy, it will generate data structures to represent your data contracts, including your custom MyDataTransfertObject:
Here is your generate proxy;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")][System.ServiceModel.ServiceContractAttribute(ConfigurationName="MyServiceReference.IMyService")] public interface IMyService { [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService/GetDataTransfertObject",ReplyAction="http://tempuri.org/IMyService/GetDataTransfertObjectResponse")] MyTypes.MyServiceReference.MyDataTransfertObject GetDataTransfertObject(); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService/SaveDataTransfertObject", ReplyAction="http://tempuri.org/IMyService/SaveDataTransfertObjectResponse")] void SaveDataTransfertObject(MyTypes.MyServiceReference.MyDataTransfertObject dataTransfertObjectToSave); }
You see that Visual studio has generated for you a data type: MyTypes.MyServiceReference.MyDataTransfertObject, to represent the data structure you created on the service side. This is the proper behaviour since in a SOA world, your client should be independent from your service: no shared types should be involved (you could have a client that does not understand the service side technology. Example: a java client consuming a .NET Service).
However, in pure .NET environments (client and service being implemented in .NET), it can be very convenient to share data type between client and service. For instance if your create at service side a data structure that include behaviour (example: self-tracking entities), it will be essential that you can share this implementation with your clients. Here is the trick to do so with the Visual Studio wizard to add references to services:
First, it will be convenient to define your data structures you want to share in a separate assembly than the service implementation. This is to make sure you won't have to share your entire service implementation with your clients! Your service will therefore reference the assembly containing your data structures.
Then, in your client project, add a reference to your assembly containing your data structures BEFORE adding a reference to your service.
When you now add your service reference, no new types will be created, the data structures defined in your assembly are used and therefore properly shared between you service and client. Here is the generated proxy:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] [System.ServiceModel.ServiceContractAttribute(ConfigurationName="MyServiceReference.IMyService")] public interface IMyService { [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService/GetDataTransfertObject", ReplyAction="http://tempuri.org/IMyService/GetDataTransfertObjectResponse")] MyTypes.MyDataTransfertObject GetDataTransfertObject(); [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IMyService/SaveDataTransfertObject", ReplyAction="http://tempuri.org/IMyService/SaveDataTransfertObjectResponse")] void SaveDataTransfertObject(MyTypes.MyDataTransfertObject dataTransfertObjectToSave); }
You see that your own MyTypes.MyDataTransfertObject data structure is used instead of the generated MyTypes.MyServiceReference.MyDataTransfertObject
For more information about what happens under the hood: in the "add service reference" wizard windows, click on the "Advanced..." button. The following window is then displayed:
You see that by default, Visual Studio uses types defined in referenced assemblies.
That's it! Download here the full test project, Visual Studio 2010
Recent Comments