【问题标题】:Modify JSON Before it is Converted to Message在 JSON 转换为消息之前修改它
【发布时间】:2011-12-29 17:14:21
【问题描述】:

如何将传入的 JSON 修改为 WCF REST 服务将其转换为 Message

例如,如果我提交以下内容:

{
    "Name": "Joe Bloggs",
    "Age": 30
}

我希望去掉所有空格,以便将数据包正文转换为:

{"Name":"Joe Bloggs","Age":30}

我正在尝试解决a problem in System.Runtime.Serialization.Json.XmlJsonReader,我发现如果数据包中有任何空格,JSON 不会正确转换为 XML。因为我不能保证我的所有客户都会发送无空格的 JSON,所以我想要某种预处理器,它会在 JSON 传递给 XmlJsonReader 之前从 JSON 中去除空格。

我研究过使用AfterReceiveRequest 方法实现自定义IDispatchMessageInspector。但这为时已晚,因为 JSON 已经转换为包含不正确 XML 的 Message。我需要在此阶段之前修改 JSON,但在此过程中我找不到任何可扩展点。

【问题讨论】:

    标签: c# wcf json rest


    【解决方案1】:

    如果您想在消息被解码之前对其进行处理,您将需要一个自定义消息编码器(这是在线路中的字节和消息对象之间进行转换的组件)。您可以在http://blogs.msdn.com/b/carlosfigueira/archive/2011/11/09/wcf-extensibility-message-encoders.aspx 找到有关自定义编码器的更多信息。

    下面的自定义编码器会从 JSON 文档中去除空格。 JsonReaderWriterFactory.CreateJsonWriter 创建的默认编写器不会进行任何漂亮的打印,所以这基本上就是您所需要的。

    public class StackOverflow_8670954
    {
        [DataContract(Name = "Person", Namespace = "MyNamespace")]
        public class Person
        {
            [DataMember]
            public string Name { get; set; }
            [DataMember]
            public int Age { get; set; }
    
            public override string ToString()
            {
                return string.Format("Person[Name={0},Age={1}]", Name, Age);
            }
        }
        [DataContract(Name = "Employee", Namespace = "MyNamespace")]
        public class Employee : Person
        {
            [DataMember]
            public int EmployeeId { get; set; }
    
            public override string ToString()
            {
                return string.Format("Employee[Id={0},Name={1}]", EmployeeId, Name);
            }
        }
        [ServiceContract]
        public interface ITest
        {
            [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
            [ServiceKnownType(typeof(Employee))]
            string PrintPerson(Person person);
        }
        public class Service : ITest
        {
            public string PrintPerson(Person person)
            {
                return person.ToString();
            }
        }
        static Binding GetBinding()
        {
            var result = new CustomBinding(new WebHttpBinding());
            for (int i = 0; i < result.Elements.Count; i++)
            {
                MessageEncodingBindingElement mebe = result.Elements[i] as MessageEncodingBindingElement;
                if (mebe != null)
                {
                    result.Elements[i] = new MyEncodingBindingElement(mebe);
                    break;
                }
            }
            return result;
        }
        class MyEncodingBindingElement : MessageEncodingBindingElement
        {
            MessageEncodingBindingElement inner;
            public MyEncodingBindingElement(MessageEncodingBindingElement inner)
            {
                this.inner = inner;
            }
    
            public override MessageEncoderFactory CreateMessageEncoderFactory()
            {
                return new MyEncoderFactory(this.inner.CreateMessageEncoderFactory());
            }
    
            public override MessageVersion MessageVersion
            {
                get { return this.inner.MessageVersion; }
                set { this.inner.MessageVersion = value; }
            }
    
            public override BindingElement Clone()
            {
                return new MyEncodingBindingElement(this.inner);
            }
    
            public override bool CanBuildChannelListener<TChannel>(BindingContext context)
            {
                return context.CanBuildInnerChannelListener<TChannel>();
            }
    
            public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
            {
                context.BindingParameters.Add(this);
                return context.BuildInnerChannelListener<TChannel>();
            }
    
            class MyEncoderFactory : MessageEncoderFactory
            {
                private MessageEncoderFactory inner;
    
                public MyEncoderFactory(MessageEncoderFactory inner)
                {
                    this.inner = inner;
                }
    
                public override MessageEncoder Encoder
                {
                    get { return new MyEncoder(this.inner.Encoder); }
                }
    
                public override MessageVersion MessageVersion
                {
                    get { return this.inner.MessageVersion; }
                }
            }
    
            class MyEncoder : MessageEncoder
            {
                private MessageEncoder inner;
    
                public MyEncoder(MessageEncoder inner)
                {
                    this.inner = inner;
                }
    
                public override string ContentType
                {
                    get { throw new NotImplementedException(); }
                }
    
                public override string MediaType
                {
                    get { throw new NotImplementedException(); }
                }
    
                public override MessageVersion MessageVersion
                {
                    get { throw new NotImplementedException(); }
                }
    
                public override bool IsContentTypeSupported(string contentType)
                {
                    return this.inner.IsContentTypeSupported(contentType);
                }
    
                public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
                {
                    if (IsJsonContentType(contentType))
                    {
                        // the encoder can also support other types of content (raw, xml), so we don't want to deal with those
    
                        MemoryStream writeStream = new MemoryStream();
                        XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(writeStream, Encoding.UTF8, false);
                        XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader(buffer.Array, buffer.Offset, buffer.Count, XmlDictionaryReaderQuotas.Max);
                        jsonWriter.WriteNode(jsonReader, true);
                        jsonWriter.Flush();
    
                        byte[] newBuffer = bufferManager.TakeBuffer(buffer.Offset + (int)writeStream.Position);
                        Array.Copy(writeStream.GetBuffer(), 0, newBuffer, buffer.Offset, (int)writeStream.Position);
                        bufferManager.ReturnBuffer(buffer.Array);
                        buffer = new ArraySegment<byte>(newBuffer, buffer.Offset, (int)writeStream.Position);
                        writeStream.Dispose();
                        jsonReader.Close();
                        jsonWriter.Close();
                    }
    
                    return this.inner.ReadMessage(buffer, bufferManager, contentType);
                }
    
                static bool IsJsonContentType(string contentType)
                {
                    return contentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase) ||
                        contentType.StartsWith("text/json", StringComparison.OrdinalIgnoreCase);
                }
    
                public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
                {
                    throw new NotSupportedException("Streamed transfer not supported");
                }
    
                public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
                {
                    return this.inner.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
                }
    
                public override void WriteMessage(Message message, Stream stream)
                {
                    throw new NotSupportedException("Streamed transfer not supported");
                }
            }
        }
        public static void Test()
        {
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
            host.AddServiceEndpoint(typeof(ITest), GetBinding(), "").Behaviors.Add(new WebHttpBehavior());
            host.Open();
            Console.WriteLine("Host opened");
    
            string[] inputs = new string[]
            {
                "{\"__type\":\"Employee:MyNamespace\",\"Age\":33,\"Name\":\"John\",\"EmployeeId\":123}",
                "{  \"__type\":\"Employee:MyNamespace\",\"Age\":33,\"Name\":\"John\",\"EmployeeId\":123}",
            };
    
            foreach (string input in inputs)
            {
                WebClient c = new WebClient();
                c.Headers[HttpRequestHeader.ContentType] = "application/json";
                Console.WriteLine(c.UploadString(baseAddress + "/PrintPerson", input));
            }
    
            Console.Write("Press ENTER to close the host");
            Console.ReadLine();
            host.Close();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-08
      • 1970-01-01
      • 2016-07-08
      • 2019-02-25
      • 2015-06-14
      • 1970-01-01
      相关资源
      最近更新 更多