From what I can see I have to create a \"special\" datatype for each kind of data I want to transfer over WCF, so if I have a shared class like
public class
First, you are not strictly required to provide a DataContract; WCF will serialize Plain Old Class Objects (POCO) correctly as long as you are on .Net 3.5 SP1 or later.
Second, you can share the same physical class file in projects on both the server and client side; we have projects that have hundreds of classes (and code) that are directly shared this way and it saves a tremendous amount of time and effort in development and testing.
There are a couple of steps required to get this up and running (doing this from memory so I may need adjust the answer):
1) In the client side, if you are using VB, create a project in the same default namespace as the classes that you want to use in the client side (for C#, this isn't important since the namespace is embedded in the classes).
2) Add the class files to the project as links so that you have one physical copy of the class.
3) Add a dataContractSerializer to your WCF configuration if you don't have one already.
4) In the client-side, right-click on the service and choose Configure Service Reference... In the resulting dialog, ensure that Reuse types in all referenced assemblies
is checked and that the Reuse types in all referenced assemblies
option is chosen.
5) The trickiest part to getting this working is for collections.
a) Decorate the collection with the CollectionDataContract attribute.
b) Add an entry for this collection to the reference.svcmap
's CollectionMappings
table. To find the reference.svcmap, show all files in the project and then expand the service. To edit it, just double-click on the file. You will add an entry in here for each specific collection that you are serializing and you need to differentiate between those items that have a List<> base and those that have a Dictionary<> base. If you don't take this step, WCF will automatically serialize these classes to the underlying generic signature and you will lose the use of your classes.
The entries in this table look something like this:
<CollectionMappings>
<CollectionMapping TypeName="System.Collections.Generic.Dictionary`2" Category="Dictionary" />
<CollectionMapping TypeName="System.Collections.Generic.List`1" Category="List" />
<CollectionMapping TypeName="System.Collections.Specialized.StringCollection" Category="List" />
<CollectionMapping TypeName="My.Namespace.MyDictionaryCollection" Category="Dictionary" />
When you add these entries and save the file, the WCF client-side generator will rebuild the reference.cs or reference.vb file depending on what language you are using. You can tell if you don't have the references configured correctly by looking at the generated code: if that code contains class definitions, then the WCF code generator was not able to map into your copied classes for some reason.
One final note: sometimes the WCF code generator completely fails to generate the code and this is always due to a problem in the service (usually a class isn't unique enough or a type was not able to be serialized for one reason or another).
In order to debug this type of problem, the easiest thing to do is add WCF diagnostic logging, which will generate a file that can be opened by a special tool (forget the name of it) that allows you to drill into the error messages and discover exactly what went wrong. This has saved us untold hours of work. To configure this logging, add the following to your web.config anywhere in the <configuration>
section:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\log\WcfTrace.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
Once you have added this and saved web.config, attempt to update the service reference in the client, then double-click on the log file you specified and the tool will open.
You're gonna need those attributes. To make you're life easier you can use a tool like AutoMapper
to do the wiring up of the data transfer objects as the manual setting of all the properties can be tedious.
It is good practice anyway to keep your model classes separate from your data contracts so that changes to your model does not have to directly impact your data contracts.