I have a WCF service hosted in IIS. The intention is for clients to make a call and receive a custom class that is defined in another project/dll. I have generated a service client using the svcutil.exe. The problem is this autogenerated client contains a new partial / proxy definition for the class I am trying to return from the service. It now throws a conversion error between my original custom class and the new partial definition at compile time. So how do you return user defined types from a WCF service? Advice appreciated.
One of the things that will need to happen is that the user must configure the service reference to use your types from the DLL rather than the class defined by the proxy - http://msdn.microsoft.com/en-us/library/bb628653.aspx
We have walked down that path in the past, and indeed the problem is that, of course, these are two different classes, so you will have to follow the link provided by @Rich Reuter;
We have, though, learnt the hard way why this is bad practice as it goes agains the 3rd tenet of SOA- "Services share schema and contract, not class".
Of course the problem is not just not following a "rule" set by someone at some point, but that there were great reasons for this to be suggested - we have learnt that the price of such tight coupling between the service and the client means it is very hard to release either - if the service needs to add another field to that class, to service another client - the first client might be affected; if the service than needs to change something in that class definition (to service another client) - the first client will again be affected, and vice versa - the client may affect the life cycle of the service.
In large projects this quickly becomes a huge maintenance burden.
Just to second Yossi's/Rich's thoughts:
- yes, you can add a reference to the shared dll (rather than using the generated proxy class)
- yes, it defeats a lot of the intent of data-contracts, and if any kind of custom serialization is happening, you may have issues extending your service
I have gone down this road before, and in some ways wish I hadn't. Re extensibility / custom serialization - you have to be very careful. A bit easier if you use a pre-rolled serializer such as protobuf-net (which can integrate directly into WCF, and which is designed with extensibility in mind), but not easy.
Actually, one advantage of sharing the classes is that it makes it a bit easier to test: since you have the same IFoo
everywhere, you can mock that IFoo
with reasonable chance of success. It is harder to mock when the proxy gets involved (as you change more moving parts between the test code and the production code).
If the type that you want to return from your service call is not marked as a DataContract
then you will not be able to return it from WCF without providing a copy of that same assembly to your client application.
using System;
using System.ServiceModel;
[ServiceContract]
interface IService
{
[OperationContract]
TimeSpan GetTimeSpan();
}
class Service : IService
{
public TimeSpan GetTimeSpan() { return DateTime.Now.TimeOfDay; }
}
Why does the previous code work then? It works because both sides of the service call have System.dll
so they both know about the System.TimeSpan
type which is the return type of the OperationContract GetTimeSpan()
.
Here is an example using a DataContract
:
using System;
using System.ServiceModel;
using System.Runtime.Serialization;
[ServiceContract]
interface IService
{
[OperationContract]
Contract GetContract();
}
[DataContract]
class Contract
{
[DataMember]
public String MyProperty { get; set; }
}
class Service : IService
{
public Contract GetContract() { return new Contract(); }
}
Now you have provided serialization attributes to a class you have defined (Contract
) - this will allow you to use svcutil.exe
to create proxy classes in your client application that will be serialized and sent to the WCF service.
Now if you want to return a type that is not a DataContract
you must provide a copy of the assembly containing that type to your client application.