WCF client is receiving a Date value from a Java web service where the date sent to the client in XML is :
<sampleDate>2010-05-10+14:00</sampleDate>
Now the WCF client receiving this date is in timezone (+08:00) and when the client deserialises the Date value it is converted into the following DateTime value :
2010-05-09 18:00 +08:00
However we would like to ignore the +14:00 being sent from the server so that the serialised Date value in the client is :
2010-05-10
Note that the +14:00 is not consistent and may be +10:00, +11:00 etc so it is not possible to use DateTime conversions on the client side to get the desired date value.
How can this be easily achieved in WCF?
Thanks in advance.
UPDATE
Would the correct WCF solution to this be to implement IClientMessageFormatter?
SOLUTION
The cleanest solution for me was to implement the IClientMessageFormatter as suggested above. Here is an example :
C# code
public class ClientMessageFormatter : IClientMessageFormatter
{
IClientMessageFormatter original;
public ClientMessageFormatter(IClientMessageFormatter actual)
{
this.original = actual;
}
public void RemoveTimeZone(XmlNodeList nodeList)
{
if (nodeList != null)
{
foreach (XmlNode node in nodeList)
{
node.InnerText = Regex.Replace(node.InnerText, @"[\+\-]\d\d:\d\d", "");
}
}
}
#region IDispatchMessageFormatter Members
public object DeserializeReply(Message message, object[] parameters)
{
Message newMessage = null;
Message tempMessage;
MessageBuffer buffer;
MemoryStream ms;
XmlDocument doc;
XmlDictionaryReader reader;
XmlReader xr;
XmlWriter xw;
try
{
buffer = message.CreateBufferedCopy(int.MaxValue);
tempMessage = buffer.CreateMessage();
reader = tempMessage.GetReaderAtBodyContents();
if (reader != null)
{
doc = new XmlDocument();
doc.Load(reader);
reader.Close();
if (doc.DocumentElement != null)
{
/* enables switching between responses */
switch (doc.DocumentElement.LocalName)
{
case "sampleRootElement":
RemoveTimeZone(doc.DocumentElement.SelectNodes("childElement1/childElement2"));
break;
}
}
ms = new MemoryStream();
xw = XmlWriter.Create(ms);
doc.Save(xw);
xw.Flush();
xw.Close();
ms.Position = 0;
xr = XmlReader.Create(ms);
newMessage = Message.CreateMessage(message.Version, null, xr);
newMessage.Headers.CopyHeadersFrom(message);
newMessage.Properties.CopyProperties(message.Properties);
}
}
catch (Exception ex)
{
throw ex;
}
return original.DeserializeReply((newMessage != null) ? newMessage : message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
return original.SerializeRequest(messageVersion, parameters);
}
#endregion
}
public class ClientOperationBehavior : IOperationBehavior
{
public void AddBindingParameters(OperationDescription description, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
IClientMessageFormatter currentFormatter = proxy.Formatter;
proxy.Formatter = new ClientMessageFormatter(currentFormatter);
}
public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation operation)
{
}
public void Validate(OperationDescription description)
{
}
}
public class ClientEndpointBehavior : IEndpointBehavior
{
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
operation.Behaviors.Add(new ClientOperationBehavior());
}
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
#endregion
}
public class ClientBehaviorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get
{
return typeof(ClientEndpointBehavior);
}
}
protected override object CreateBehavior()
{
return new ClientEndpointBehavior();
}
}
App.config/Web.config
The client configuration file would then use the above formatter as follows :
<system.serviceModel>
....
....
<extensions>
<behaviorExtensions>
<add name="clientMessageFormatterBehavior" type="..." />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="clientMessageFormatterBehavior">
<clientMessageFormatterBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="https://www.domain.com/service" behaviorConfiguration="clientMessageFormatterBehavior" .... />
</client>
....
....
</system.serviceModel>
References
Hi my improved and more universal solution
Try this
Coding Best Practices Using DateTime in the .NET Framework
Related links
http://daveonsoftware.blogspot.com/2008/07/wcf-datetime-field-adjusted.html
http://social.msdn.microsoft.com/forums/en-US/wcf/thread/36ae825a-ffc6-4ac3-9981-c82692039d58
Best practices for DateTime serialization in .NET 3.5