Friday, February 5, 2010

WCF does not support the use of generic methods for service operation. In other words, only concrete types can be used for service operations. Open generic types cannot be used. Now, it is important to clarify this is not a limitation of WCF. Rather, it is a limitation of WSDL, which is used to expose service metadata to consumers. There is no construct within WSDL to define a generic type. Generally speaking, I agree with this behavior since it decreases the coupling between a client and service.
Although generic methods are not supported, it is possible to expose generic objects for the purpose of exchanging data. However, there are some limitations. Let's take a closer look:

Bounded Generics
In his book Programming WCF Services , Juval Lowy points out that it is possible to use "bounded generics." This is sometimes referred to as closed generics. Basically, it refers to defining a generic class for your data contract, but it is restricted to a specific type in the service operation. This may sound somewhat vague. So, here is an example to provide a better illustration:

[DataContract]
public class MyGenericObject
{
private T _id;
private string _description;

public MyGenericObject()
{
}

[DataMember]
public T ID
{
get { return _id; }
set { _id = value; }
}

[DataMember]
public string Description
{
get { return _description; }
set { _description = value; }
}
}

[ServiceContract(Namespace = "http://jeffbarnes.net/2007/05/boundedgenerics/")]
public interface IBoundedGenerics
{
[OperationContract]
MyGenericObject GetGenericObject(int id);
}

As you can see, a generic object (MyGenericObject) is exposed to the client. However, the service operation restricts the usage to being of type integer. This is what Juval Lowy means by "bounded generics." However, it should be noted the client will not see the object as a generic. When the metadata is generated to describe the service operation, the data contract and service operation will appear as a normal non-generic class.

[DataContract]
public class MyGenericObjectOfint
{
private int _id;
private string _description;

public MyGenericObjectOfint()
{
}

[DataMember]
public int ID
{
get { return _id; }
set { _id = value; }
}

[DataMember]
public string Description
{
get { return _description; }
set { _description = value; }
}
}
The resulting name is due to an applied naming pattern that consists of:
Generic Class Name + "Of" + Type Parameter Name + Hash
The hash is added under certain conditions to reduce the risk of a name collision. However, you should be aware the hash can create a really ugly class name. It could be something like: MyGenericObjectOfSomeTypegDh87uV. Obviously, this isn't an ideal name for the client to use. Fortunately, you can override the use of the hash by specifying the Name property of the DataContract. It supports parameters that correspond to the generic type parameters.

For example:
[DataContract(Name = "MyGenericObjectUsing{0}"]
public class MyGenericObject
Using this approach, it is still possible to leverage generics from within the service implementation, but there is nothing special going on from the client's perspective.
You can download the sample code from here.
http://jeffbarnes.net/download/blog/200705/genericserialization.rar