Json在WCF中缩进格式

时间:2016-01-29 18:20:13

标签: json wcf odata

我们使用最新的ODATALib(5.6)提供WCF数据服务。我们从服务中获取的JSON结果不会缩进。它们是单行字符串。有没有办法将JSON格式化为缩进(即漂亮的格式)?

1 个答案:

答案 0 :(得分:0)

好的,所以这不是最简单的事情,但它适用于我(从其他各种帖子拼凑而成)。基本计划包括自己实现IDispatchMessageFormatter接口。然后将此实现作为配置文件中的服务行为扩展进行编译。因此,进入/退出该服务的WCF将被截获到该类,这可以修改服务和客户端之间的HTML内容。

接口只有两个需要实现的方法。我不会为DeserializeRequest方法烦恼,因为我不关心传入。因此,在这种情况下,我只需调用原始/默认格式化程序(通过格式化程序本身)。对于到客户端的传出数据,我必须检查原始WCF消息以查看它是否是JSON格式。然后我继续检索正文,缩进它并用新消息替换传出的WCF消息。

public class NewtonsoftJsonDispatchFormatter : IDispatchMessageFormatter
{ 
    OperationDescription operation;
    private IDispatchMessageFormatter originalFormatter;

    public NewtonsoftJsonDispatchFormatter(IDispatchMessageFormatter formatter, OperationDescription operation)
        {
            this.originalFormatter = formatter;
            this.operation = operation;
        }

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

    public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {            
            var message = result as Message;
            if (message == null) return message;

            if (IsJsonContentType(message))
            {
                byte[] messageBody;
                var httpResponseBody = ReadResponseBody(message);
                var jObj = JObject.Parse(httpResponseBody);
                messageBody = Encoding.UTF8.GetBytes(jObj.ToString(Newtonsoft.Json.Formatting.Indented));
                return ReplaceMessage(messageBody,messageVersion);
            }           
            else
            {
                return message;
            }         
       }

    private string ReadResponseBody(Message message)
        {
            var bodyReader = message.GetReaderAtBodyContents();
            bodyReader.ReadStartElement("Binary");
            byte[] rawBody = bodyReader.ReadContentAsBase64();

            string httpResponseBody;
            using (var ms = new MemoryStream(rawBody))
            {
                using (var sr = new StreamReader(ms))
                {
                    httpResponseBody = sr.ReadToEnd();
                }
            }
            return httpResponseBody;
        }

        private bool IsJsonContentType(Message message)
        {
           bool isMatch;
           object responseHeader;
           if (message.Properties.TryGetValue("httpResponse", out responseHeader) && responseHeader is HttpResponseMessageProperty)
           {
               var contentTypeVals = ((HttpResponseMessageProperty) responseHeader).Headers.GetValues("Content-Type");
               isMatch = contentTypeVals != null && contentTypeVals.Any(v => v.Contains("application/json"));
           }
           else
           {
               isMatch = false;
           }
           return isMatch;
        }

      private Message ReplaceMessage(byte[] messageBody, MessageVersion messageVersion)
       {
             var replyMessage = Message.CreateMessage(messageVersion, operation.Messages[1].Action, new RawBodyWriter(messageBody));
            replyMessage.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
            var respProp = new HttpResponseMessageProperty();
            respProp.Headers[HttpResponseHeader.ContentType] = "application/json";
            replyMessage.Properties.Add(HttpResponseMessageProperty.Name, respProp);
            return replyMessage;

    }
}

public class RawBodyWriter : BodyWriter
{
    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();
    }
}

配置文件随着相应的服务和操作行为而变化,这些行为将拦截我服务的WCF消息:



 <system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="newtonsoftJsonBehaviorExtension" type="WCFProject.NewtonsoftJsonServiceBehavior, WCFProject, Version=1.0.0.0, Culture=neutral"/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <serviceBehaviors>       
        <behavior name="newtonsoftJsonBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>          
          <newtonsoftJsonBehaviorExtension />
        </behavior>
      </serviceBehaviors>   
    </behaviors>    
    <services>
      <service name="Myservice" behaviorConfiguration="newtonsoftJsonBehavior">
        <endpoint bindingConfiguration="msgSize" address="" binding="webHttpBinding" contract="System.Data.Services.IRequestHandler"/>
      </service>
    </services>
</system.serviceModel>
&#13;
&#13;
&#13;

 public class NewtonsoftJsonServiceBehavior : BehaviorExtensionElement, IServiceBehavior
{
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints,
        BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
        {
            foreach (OperationDescription operation in endpoint.Contract.Operations)
            {
                operation.Behaviors.Add(new NewtonsoftJsonOperationBehavior());
            }
        }
    }

    protected override object CreateBehavior()
    {
        return this;
    }

    public override Type BehaviorType
    {
        get { return typeof(NewtonsoftJsonServiceBehavior); }
    }
}

 public class NewtonsoftJsonOperationBehavior : IOperationBehavior
{
    public void Validate(OperationDescription operationDescription)
    {
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        var originalFormatter = dispatchOperation.Formatter;
        dispatchOperation.Formatter = new NewtonsoftJsonDispatchFormatter(originalFormatter, operationDescription);
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }

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

最后说明:结果OData有一个批处理概念,其中请求/回复可以是多部分http。这意味着必须修改上面的代码以处理单独检查消息的每个部分并且如果JSON格式化则缩进的情况。我把它作为练习让读者实现这种增强。