【问题标题】:Space disappears on transferring via wcf (xml)通过 wcf (xml) 传输时空间消失
【发布时间】:2017-04-26 16:00:50
【问题描述】:

我有一个对象 A 和属性 Name,我在 WCF 中使用它来传输模型(通信)。

[DataMember(IsRequired = false, EmitDefaultValue = false, Name = "p0", Order = 0)]
public string Name { get; set; }

我发现当Name 以空格“123”开头时,在另一侧反序列化后,它丢失了空格,变成了“123”。

WCF 服务使用 MTOM 消息编码。

这对于 xml 或 wcf 来说是一种已知的影响吗?

在提供的答案的帮助下,我发现由于 Mtom 编码,前导空格被删除。事实上,当我删除 Mtom 时,前导空格会正确传输。

安全配置在我的场景中没有发挥任何作用。

有什么办法可以避免吗?

【问题讨论】:

  • 您必须对名称进行 XML 编码。 stackoverflow.com/questions/1091945/…
  • 从来没有听说过这样的事情,如果这不是一个错误的话,会感到震惊。客户端和服务器实际上都是使用 WCF 的 .NET 吗?
  • @KevinRaffay 当然不是。 (Net)DataContractSerializer ("WCF") 会为你做这件事。
  • This MSDN 论坛帖子似乎相关。根据那篇文章,这是反序列化方面的一个问题,他们通过在序列化之前添加多余的字符然后在反序列化时手动查找并删除它们来解决这个问题。类似信息here,大致是“.NET 4.5 的问题,使用特殊空白字符的解决方法”。
  • 你使用 XmlSerializer 吗?默认情况下,WCF 使用 DataContractSerializer。

标签: c# xml wcf


【解决方案1】:

更新:替换答案,因为很明显您正在使用 MTOM。

显然这是 WCF 中的 bug,根据 this,它被标记为“延迟”。所以很难说,什么时候能修好。最后一个链接还提到了一些解决方法,我将在此处复制它们,以免它们丢失。

  1. 不要使用 MTOM
  2. 添加一些发送者和接收者都知道的前缀字符,然后接收者可以去掉(如引号等)。
  3. 使用消息检查器并缓冲消息

下面的代码显示了此问题的第三个解决方法:

public class Post_4cfd1cd6_a038_420d_8cb5_ec5a2628df1a
{
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        string Echo(string text);
    }
    public class Service : ITest
    {
        public string Echo(string text)
        {
            Console.WriteLine("In service, text = {0}", ReplaceControl(text));
            return text;
        }
    }
    static Binding GetBinding()
    {
        //var result = new WSHttpBinding(SecurityMode.None) { MessageEncoding = WSMessageEncoding.Text };
        var result = new BasicHttpBinding() { MessageEncoding = WSMessageEncoding.Mtom };
        return result;
    }
    static string ReplaceControl(string text)
    {
        StringBuilder sb = new StringBuilder();
        foreach (var c in text)
        {
            if ((' ' <= c && c <= '~') && c != '\\')
            {
                sb.Append(c);
            }
            else
            {
                sb.AppendFormat("\\u{0:X4}", (int)c);
            }
        }

        return sb.ToString();
    }
    public class MyInspector : IEndpointBehavior, IDispatchMessageInspector, IClientMessageInspector
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(this);
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            request = request.CreateBufferedCopy(int.MaxValue).CreateMessage();
            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            reply = reply.CreateBufferedCopy(int.MaxValue).CreateMessage();
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            return null;
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        var endpoint = host.AddServiceEndpoint(typeof(ITest), GetBinding(), "");
        endpoint.Behaviors.Add(new MyInspector());
        host.Open();
        Console.WriteLine("Host opened");

        ChannelFactory<ITest> factory = new ChannelFactory<ITest>(GetBinding(), new EndpointAddress(baseAddress));
        factory.Endpoint.Behaviors.Add(new MyInspector());
        ITest proxy = factory.CreateChannel();

        string input = "\t\tDoc1\tCase1\tActive";
        string output = proxy.Echo(input);
        Console.WriteLine("Input = {0}, Output = {1}", ReplaceControl(input), ReplaceControl(output));
        Console.WriteLine("input == output: {0}", input == output);

        ((IClientChannel)proxy).Close();
        factory.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}

同样,真正的答案和代码来自here

【讨论】:

  • 它是 HTTP 与 MTOM binding name="BasicHttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:01:00" sendTimeout="00:01:00" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" transferMode="Streamed" useDefaultWebProxy="true" messageEncoding="Mtom"
  • 还有security mode="None",在您的第二个链接中提到。
  • 那么,你有它;-)
  • 然而,它是一个确认的错误的链接已经死了。
  • 是的,微软的连接站点... :-(
猜你喜欢
  • 2013-04-27
  • 2015-09-07
  • 2015-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
  • 2011-11-22
  • 2012-07-30
相关资源
最近更新 更多