I am working on a number of WCF services which will be accessed over named pipes (for the first release anyway) and be consumed by a number of internal applications. The operations on the services process graphs of Data Transfer Objects (DTOs). Both the request and the response of the operation may involve either a shallow or a deep graph of objects from my library of (currently) forty types. For these services to work, not only do I need to ensure that each DTO is marked up with the appropriate DataContract and DataMember attributes, but also I need to register each of the forty types for each of WCF services. Now I could do this:
But clearly, this violates the DRY principle. And every time I add a new DTO, as I presume I will need to do for subsequent releases, I will need to remember to add the new type to the list of service known types in each of my WCF service definitions.
Instead, I have opted for the following approach:
[ServiceKnownType(typeof(Type1))]
...
[ServiceKnownType(typeof(Type40))]
[ServiceContract]
public interface IService
{
[OperationContract]
OperationResponse DoSomething(OperationRequest request);
}
...
[ServiceKnownType(typeof(Type40))]
[ServiceContract]
public interface IService
{
[OperationContract]
OperationResponse DoSomething(OperationRequest request);
}
But clearly, this violates the DRY principle. And every time I add a new DTO, as I presume I will need to do for subsequent releases, I will need to remember to add the new type to the list of service known types in each of my WCF service definitions.
Instead, I have opted for the following approach:
[ServiceContract]
public interface IService
{
[OperationContract]
[ServiceKnownType("ListKnownTypes", typeof(KnownTypesRegister))]
OperationResponse DoSomething(OperationRequest request);
}
static class KnownTypesRegister
{
public static IEnumerable ListKnownTypes(ICustomAttributeProvider provider)
{
Assembly dtoDefinitions = Assembly.Load("assemblyname, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
var query = from t in dtoDefinitions.GetTypes() where t.IsClass && t.Namespace == "namespace" select t;
return query.ToList();
}
}
With essentially only three lines of code I have a much more extensible solution, far less prone to defect injection during maintenance and subsequent releases.
Comments
Post a Comment