WCF protobuf 端点 400 错误请求 [英] WCF protobuf endpoint 400 bad request

查看:66
本文介绍了WCF protobuf 端点 400 错误请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有带有 DataContract json 序列化的 WCF 服务.我想添加服务端点以使用 Protobuf 数据消息.

I have WCF service with DataContract json serialization. I would like to add service endpoints to consume Protobuf data messages.

我尝试使用 nugget 包 ProtoBuf.Services.WCF.通过 web.config 配置添加端点.但是,地址为proto"的 protobuf 端点上的每个请求都会返回 400 Bad request.Web.config 示例写在下面.默认地址为"的端点正常工作.

I tried to use nugget package ProtoBuf.Services.WCF. Added endpoint via web.config configuration. However, every request on protobuf endpoint with address "proto" returns 400 Bad request. Web.config sample is written bellow. Endpoint with default address "" works properly.

获取方法:

HTTP 200 OK http://localhost:65460/BeaconService.svc/GetData

HTTP 200 OK http://localhost:65460/BeaconService.svc/GetData

HTTP 400 错误请求:http://localhost:65460/BeaconService.svc/proto/获取数据

HTTP 400 BAD REQUEST: http://localhost:65460/BeaconService.svc/proto/GetData

<system.serviceModel>
   <bindings>
      <webHttpBinding>
         <binding transferMode="Streamed">
            <security mode="None" />
         </binding>
      </webHttpBinding>
      <basicHttpBinding>
         <binding messageEncoding="Mtom">
            <security mode="None" />
         </binding>
      </basicHttpBinding>
   </bindings>
   <extensions>
      <behaviorExtensions>
         <add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net" />
      </behaviorExtensions>
   </extensions>
   <services>
      <service behaviorConfiguration="DefaultServiceBehavior" name="Services.BeaconService">
         <endpoint address="" behaviorConfiguration="httpBehavior" binding="webHttpBinding" contract="Services.IBeaconService" />
         <endpoint address="proto" behaviorConfiguration="protoBehavior" binding="basicHttpBinding" contract="Services.IBeaconService" />
      </service>
   </services>
   <behaviors>
      <endpointBehaviors>
         <behavior name="protoBehavior">
            <protobuf />
         </behavior>
         <behavior name="httpBehavior">
            <webHttp />
         </behavior>
      </endpointBehaviors>
   </system.serviceModel>

请问,哪部分配置有问题.最终,在原型"WCF 端点上调用 Get 方法以避免 HTTP 400 错误请求消息的正确方法是什么?

Please, which part of configuration is defective. Eventualy, what is proper way to call Get method on "proto" WCF endpoint to avoid HTTP 400 Bad request message?

推荐答案

很遗憾,我未能实现 ProtoBuf.Services.WCF 并决定使用另一种方法.一般来说,WCF 默认使用 DataContractSerializer.

Unfortunately, I have failed to implement ProtoBuf.Services.WCF and decided to use another approach. In general, WCF by default uses DataContractSerializer.

阅读这篇文章后,我意识到这是可能的用另一个序列化器替换这个序列化器,fe这个中的protobuf序列化器.所以我创建了行为扩展,它用我的自定义 ProtobufSerializer 替换了 DataContractSerializer.在配置中添加了另一个端点,它设置了行为扩展以使用我的自定义 ProtobufSerializer.

After reading this article, I realized It is possible to replace this serializer with another one, f.e. protobuf serializer in this library. So I created behavior extension, which replaces DataContractSerializer with my custom ProtobufSerializer. In configuration added another endpoint, which has set behavior extension to use my custom ProtobufSerializer.

WebHttpBehavior:

WebHttpBehavior:

public class ProtobufBehavior : WebHttpBehavior
    {
        protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
        {
            return new ProtobufDispatchFormatter(operationDescription);
        }

        protected override IDispatchMessageFormatter GetReplyDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
        {
            return new ProtobufDispatchFormatter(operationDescription);
        }
    }

调度格式化程序:

namespace Services.Extension.ProtobufSerializationExtension
{
    public class ProtobufDispatchFormatter : IDispatchMessageFormatter
    {
        OperationDescription operation;
        bool isVoidInput;
        bool isVoidOutput;

        public ProtobufDispatchFormatter(OperationDescription operation)
        {
            this.operation = operation;
            this.isVoidInput = operation.Messages[0].Body.Parts.Count == 0;
            this.isVoidOutput = operation.Messages.Count == 1 || operation.Messages[1].Body.ReturnValue.Type == typeof(void);
        }

        public void DeserializeRequest(Message message, object[] parameters)
        {
            if (!message.IsEmpty)
            {
                XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();
                bodyReader.ReadStartElement("Binary");
                byte[] rawBody = bodyReader.ReadContentAsBase64();
                MemoryStream ms = new MemoryStream(rawBody);

                using (StreamReader sr = new StreamReader(ms))
                    for (int i = 0; i < parameters.Length; i++)
                        parameters[i] = Serializer.Deserialize(operation.Messages[i].Body.Parts[i].Type, sr.BaseStream);
            }
        }

        public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {
            byte[] body;

            using (MemoryStream ms = new MemoryStream())
            using (StreamWriter sw = new StreamWriter(ms))
            {
                Serializer.Serialize(sw.BaseStream, result);
                sw.Flush();
                body = ms.ToArray();
            }

            Message replyMessage = Message.CreateMessage(messageVersion, operation.Messages[1].Action, new RawBodyWriter(body));
            replyMessage.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
            return replyMessage;
        }

        class RawBodyWriter : BodyWriter
        {
            internal static readonly byte[] EmptyByteArray = new byte[0];
            byte[] content;
            public RawBodyWriter(byte[] content)
              : base(true)
            {
                this.content = content;
            }

            protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
            {
                writer.WriteStartElement("Binary");
                writer.WriteBase64(content, 0, content.Length);
                writer.WriteEndElement();
            }
        }
    }
}

扩展元素:

namespace Services.Extension.ProtobufSerializationExtension
{
    public class ProtobufSerializationServiceElement : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(ProtobufBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new ProtobufBehavior();
        }
    }
}

网页配置:

<system.serviceModel>
   <bindings>
      <webHttpBinding>
         <binding transferMode="Streamed">
            <security mode="None" />
         </binding>
      </webHttpBinding>
   </bindings>
   <extensions>
      <behaviorExtensions>
          <add name="protobufExtension" type="Services.Extension.ProtobufSerializationExtension.ProtobufSerializationServiceElement, Services" />
      </behaviorExtensions>
   </extensions>
   <services>
      <service behaviorConfiguration="DefaultServiceBehavior" name="Services.BeaconService">
         <endpoint address="" behaviorConfiguration="httpBehavior" binding="webHttpBinding" contract="Services.IBeaconService" />
         <endpoint address="proto" behaviorConfiguration="protoBehavior" binding="webHttpBinding" contract="Services.IBeaconService" />
      </service>
   </services>
   <behaviors>
      <endpointBehaviors>
         <behavior name="protoBehavior">
            <webHttp/>
            <protobufExtension/>
         </behavior>
         <behavior name="httpBehavior">
            <webHttp />
         </behavior>
      </endpointBehaviors>
   </system.serviceModel>

Services.Extension.ProtobufSerializationExtension 是我在应用程序结构中的自定义命名空间的名称.希望这对某人有所帮助.

Services.Extension.ProtobufSerializationExtension is name of my custom namespace inside application structure. Hope this helps someone.

这篇关于WCF protobuf 端点 400 错误请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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