如何在.NET WCF客户端中忽略DateTime的时区?

时间:2010-06-18 06:37:17

标签: wcf datetime timezone

WCF客户端从Java Web服务接收Date值,其中以XML格式发送给客户端的日期为:

<sampleDate>2010-05-10+14:00</sampleDate>

现在接收此日期的WCF客户端在时区(+08:00),当客户端反序列化Date值时,它将转换为以下DateTime值:

2010-05-09 18:00 +08:00

但是我们想忽略从服务器发送的+14:00,以便客户端中的序列化日期值为:

2010-05-10

请注意,+ 14:00不一致,可能是+10:00,+ 11:00等,因此无法在客户端使用DateTime转换来获取所需的日期值。

如何在WCF中轻松实现这一目标?

提前致谢。

更新

正确的WCF解决方案是实现IClientMessageFormatter吗?

对我来说最干净的解决方案是按照上面的建议实现IClientMessageFormatter。这是一个例子:

C#代码

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中

然后,客户端配置文件将使用上述格式化程序,如下所示:

<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>

参考

http://blogs.msdn.com/b/stcheng/archive/2009/02/21/wcf-how-to-inspect-and-modify-wcf-message-via-custom-messageinspector.aspx

2 个答案:

答案 0 :(得分:4)

您的改进和更通用的解决方案

public static class TimeZoneMessageHelper
{
    public static Message RemoveTimeZone(this Message message)
    {
        try
        {
            using (XmlDictionaryReader messageBodyReader = message.GetReaderAtBodyContents())
            {
                XmlDocument xmlDocument = new XmlDocument();
                Message returnMessage = null;
                xmlDocument.Load(messageBodyReader);

                RemoveTimeZone(xmlDocument);

                StringBuilder stringBuilder = new StringBuilder();
                using(XmlWriter xmlWriter = XmlWriter.Create(stringBuilder))
                {
                    xmlDocument.Save(xmlWriter);
                }

                // do not dispose to early
                XmlReader resultMessageBodyReader = XmlReader.Create(new StringReader(stringBuilder.ToString()));

                returnMessage = Message.CreateMessage(message.Version, null, resultMessageBodyReader);
                returnMessage.Headers.CopyHeadersFrom(message);
                returnMessage.Properties.CopyProperties(message.Properties);

                return returnMessage;
            }
        }
    }

    private static void RemoveTimeZone(XmlNode xmlNode)
    {            
        if (xmlNode.ChildNodes.Count == 0)
        {
            RemoveTimeZoneCore(xmlNode);
        }
        else
        {
            foreach(XmlNode node in xmlNode.ChildNodes)
                RemoveTimeZone(node);
        }            
    }

    public static void RemoveTimeZoneCore(XmlNode xmlNode)
    {
        if (xmlNode != null)
        {
            if (Regex.IsMatch(xmlNode.InnerText, @"^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d\d)?(\+|-)\d\d:\d\d$", RegexOptions.Compiled))
            {
                xmlNode.InnerText = xmlNode.InnerText.Substring(0, xmlNode.InnerText.Length - 6);                    
            }                
        }            
    }
}

public class RemoveTimeZoneClientMessageFormatter : IClientMessageFormatter
{
    private readonly IClientMessageFormatter original;

    public RemoveTimeZoneClientMessageFormatter(IClientMessageFormatter original)
    {
        this.original = original;
    }

    #region Implementation of IClientMessageFormatter

    public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
    {
        return original.SerializeRequest(messageVersion, parameters).RemoveTimeZone();
    }

    public object DeserializeReply(Message message, object[] parameters)
    {
        return original.DeserializeReply(message.RemoveTimeZone() ?? message, parameters);
    }

    #endregion
}

public class RemoveTimeZoneDispatchMessageFormatter : IDispatchMessageFormatter
{
    private readonly IDispatchMessageFormatter original;

    public RemoveTimeZoneDispatchMessageFormatter(IDispatchMessageFormatter original)
    {
        this.original = original;
    }

    #region Implementation of IDispatchMessageFormatter

    public void DeserializeRequest(Message message, object[] parameters)
    {            
        original.DeserializeRequest(message.RemoveTimeZone() ?? message, parameters);
    }  

    public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
    {
        return original.SerializeReply(messageVersion, parameters, result).RemoveTimeZone();
    }

    #endregion
}

public class RemoveTimeZoneEndpointBehavior : 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 RemoveTimeZoneOperationBehavior());
        }
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        foreach(OperationDescription operation in endpoint.Contract.Operations)
        {
            operation.Behaviors.Add(new RemoveTimeZoneOperationBehavior());
        }
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
    #endregion
}

public class RemoveTimeZoneOperationBehavior : IOperationBehavior
{

    public void AddBindingParameters(OperationDescription description, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
    {            
        proxy.Formatter = new RemoveTimeZoneClientMessageFormatter(proxy.Formatter);
    }

    public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation operation)
    {
        operation.Formatter = new RemoveTimeZoneDispatchMessageFormatter(operation.Formatter);
    }

    public void Validate(OperationDescription description)
    {
    }
}

public class RemoveTimeZoneExtensionElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get
        {
            return typeof(RemoveTimeZoneEndpointBehavior);
        }
    }

    protected override object CreateBehavior()
    {
        return new RemoveTimeZoneEndpointBehavior();
    }
}\

答案 1 :(得分:2)