By default a WCF Service uses the QueryStringConverter to convert query parameter into typed objects. To the according MSDN Documentation (see link above) we can see, that it supports by default following parameter/object types:

  • Byte
  • SByte
  • Int16
  • Int32
  • Int64
  • UInt16
  • UInt32
  • UInt64
  • Single
  • Double
  • Char

  • Decimal
  • Boolean
  • String
  • DateTime
  • TimeSpan
  • Guid
  • Byte array
  • Uri
  • Object
  • DateTimeOffset
  • Enums
  • Types that have a TypeConverterAttribute that can convert the type to and from a string representation

Hell, these are really lot of types which can be converted - but what if we like to have additional? Let’s guess we like to have Nullable<T> types like DateTime? to make some sort of optional parameter. As the Nullable<T> type is a build in framework type we do not have a chance to decorate it with a TypeConverterAttribute.

Writing our own QueryStringConverter to the rescue… The task is really simple - derive from QueryStringConverter, override 3 functions and fill in some rules:

DateTime? QueryStringConverter
public sealed class ArchiveServiceQueryStringConverter : QueryStringConverter
{
public override bool CanConvert(Type type)
{
if (typeof(DateTime?).Equals(type))
{
return true;
}
return base.CanConvert(type);
}
public override object ConvertStringToValue(string parameter, Type parameterType)
{
if (typeof(DateTime?).Equals(parameterType))
{
if (!string.IsNullOrWhiteSpace(parameter))
{
DateTime dateTime;
//see: http://msdn.microsoft.com/en-us/library/az4se3k1.aspx#Roundtrip
if (DateTime.TryParse(parameter, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out dateTime))
{
return dateTime;
}
}
return null;
}
return base.ConvertStringToValue(parameter, parameterType);
}
public override string ConvertValueToString(object parameter, Type parameterType)
{
if (parameterType == typeof(DateTime?))
{
DateTime? @object = (DateTime?)parameter; string value = string.Empty;
if (@object.HasValue)
{
value = @object.ToString("r");
}
return value;
}
return base.ConvertValueToString(parameter, parameterType);
}
}

As you can see this isn’t such a big task. Noticeable (and this is why I chose DateTime) is the convention I used to convert DateTime into the RFC1123 pattern format. The client side has to do as well to circumvent any problems in converting from and to DateTime. You can read more about Standard Date and Time Format Strings at the MSDN Documentation.

As we have our very own QueryStringConverter (extending the default) supporting Nullable<DateTime> types now we need to tell our WCF Service to use this instead of the default. Therefore we need 2 additional classes to configure a custom behavior which uses our implementation. Theses two classes are a custom WebHttpBehavior and a custom BehaviorExtensionElement.

Custom WebHttpBehavior
public class ArchiveServiceBehavior : WebHttpBehavior
{
protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
{
return new ArchiveServiceQueryStringConverter();
}
}

As you can see the custom behavior wires the implementation of the QueryStringConverter to our service. Next is the extension element to extend the service to use the custom behavior.

Behavior-Extension
public class ArchiveServiceBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get
{
return typeof(ArchiveServiceBehavior);
}
}
protected override object CreateBehavior()
{
return new ArchiveServiceBehavior();
}
}

With that done, we finally need to update the service configuration Web.config. Beneath the <system.serviceModel> tag we must configure as follows:

Web.config configuration
<services>
<service name="ArchiveService">
<endpoint behaviorConfiguration="ArchiveServiceBehavior" binding="webHttpBinding" bindingConfiguration="ArchiveBinding" contract="ArchiveService" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="ArchiveServiceBehavior">
<archiveServiceBehaviorExtension />
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="archiveServiceBehaviorExtension" type="TDSKPro.Archive.Services.ArchiveServiceBehaviorExtensionElement, TDSKPro.Archive.Services" />
</behaviorExtensions>
</extensions>

There is a great article about Extending WCF with custom behaviors over at MSDN Magazine which covers a lot of other scenarios as well. And at least the MSDN documentation covers the extensibility as well: Configuring and Extending the Runtime with Behaviors