如何在.NET WCF客户端中忽略DateTime的时区? [英] How to ignore timezone of DateTime in .NET WCF client?

查看:138
本文介绍了如何在.NET WCF客户端中忽略DateTime的时区?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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>

现在收到这个日期的WCF客户端是时区(+08:00),当客户端反序列出Date值被转换成以下DateTime值:

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

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

但是,我们想忽略从服务器发送的+14: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

2010-05-10

请注意,+14:00不一致,可能是+10:00,+11:00等,所以不可能在客户端获取所需的日期值。

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.

如何在WCF中轻松实现?

How can this be easily achieved in WCF?

感谢

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

Would the correct WCF solution to this be to implement IClientMessageFormatter?

对我来说,最干净的解决方案是实现如上所述的IClientMessageFormatter。这是一个例子:

The cleanest solution for me was to implement the IClientMessageFormatter as suggested above. Here is an example :

C#代码

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>

参考

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

推荐答案

我的改进和更普遍的解决方案

Hi my improved and more universal solution

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();
    }
}\

这篇关于如何在.NET WCF客户端中忽略DateTime的时区?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆