1

几天来,我一直在尝试满足以下要求。我希望我的 WCF API 使用单一方法处理 XML 和 JSON 请求/响应。我也知道 .net 4 支持自动格式选择,但它不像我希望的 XML 和 JSON 结构那样工作。这是我的结构:

JSON:

{
  "response": {
    "timestamp": "12.00AM",    
    "locations": {
      "location": [        
        {
          "id": "5",
          "name": "hello world",
          "statusid": "8"
        }
      ]
    },
    "errorcode": "444"
  }
}

XML:

<response>
    <timestamp>12.00AM</timestamp>
    <locations>
        <location>
            <id>5</id>
            <name>hello world</name>
            <statusid>8</statusid>
        </location>
    </locations>
    <errorcode>444</errorcode>
</response>

我尝试在我的 OperationContract 中切换“BodyStyle”的值,例如对于 JSON,我必须放置 WebMessageBodyStyle.Wrapped,对于 XML,我必须根据上述结构放置 WebMessageBodyStyle.Bare。由于我希望能够使用一个 OperationContract 并根据 Content-Type 自动使用 XML/JSON 结构进行响应,我必须进行哪些更改/添加?有没有办法使用 XML 和 JSON 的代码来设置这个 BodyStyle(PS API 应该是它的方式,并且不应该能够传递任何参数,如 getvalue/{xml})?

先感谢您。

更新:以下是我的 OperationContract:

[OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "PushNotify")]       
        ResponsePushNotify PushNotify(RequestPushNotifiy pushnotify);

这是数据合同:

 [DataContract]
    public class Test: ITest
    {
    responsePushNotify = new ResponsePushNotify();
       ResponsePushNotify PushNotify(RequestPushNotifiy pushnotify)
    {
        if (Content-Type == "application/json; charset=utf-8")  
            {  
                OperationContext.Current.OutgoingMessageProperties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json));  
            }  
    responsePushNotify.id = "1";
    responsePushNotify.value = "Hello World";

    return responsePushNotify ;
    }

这是建议的代码:

public class MyWebHttpBehavior : WebHttpBehavior
    {
        protected override IDispatchMessageFormatter GetReplyDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
        {
            WebGetAttribute webGet = operationDescription.Behaviors.Find<WebGetAttribute>();
            IDispatchMessageFormatter json = null, xml = null;
            WebMessageFormat originalFormat = webGet.ResponseFormat;
            webGet.ResponseFormat = WebMessageFormat.Json;
            json = base.GetReplyDispatchFormatter(operationDescription, endpoint);
            webGet.ResponseFormat = WebMessageFormat.Xml;
            xml = base.GetReplyDispatchFormatter(operationDescription, endpoint);
            webGet.ResponseFormat = originalFormat;
            return new MyReplyDispatchMessageFormatter(json, xml);
        }
    }
    public class MyReplyDispatchMessageFormatter : IDispatchMessageFormatter
    {
        IDispatchMessageFormatter jsonFormatter;
        IDispatchMessageFormatter xmlFormatter;
        public MyReplyDispatchMessageFormatter(IDispatchMessageFormatter jsonFormatter, IDispatchMessageFormatter xmlFormatter)
        {
            this.jsonFormatter = jsonFormatter;
            this.xmlFormatter = xmlFormatter;
        }
        public void DeserializeRequest(Message message, object[] parameters)
        {
            throw new NotSupportedException("Used for replies only");
        }

        public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
        {
            IDispatchMessageFormatter formatter = this.xmlFormatter;
            if (OperationContext.Current.OutgoingMessageProperties.ContainsKey(WebBodyFormatMessageProperty.Name))
            {
                WebBodyFormatMessageProperty webBody = (WebBodyFormatMessageProperty)OperationContext.Current.OutgoingMessageProperties[WebBodyFormatMessageProperty.Name];
                if (webBody != null && webBody.Format == WebContentFormat.Json)
                {
                    formatter = this.jsonFormatter;
                }
            }

            return formatter.SerializeReply(messageVersion, parameters, result);
        }
    }

这是我的网络配置:

<?xml version="1.0"?>
<configuration> 
  <system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
    <services>
      <service behaviorConfiguration="CustomBehavior" name="Service.Test">
        <endpoint address="" behaviorConfiguration="web" binding="webHttpBinding" contract="Services.ITest" bindingConfiguration="general"/>
      </service>      
    </services>  
    <bindings>
      <webHttpBinding>
        <binding name="general" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00"
                 receiveTimeout="00:10:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="4194304"
                 maxBufferSize="2147483647"  />
      </webHttpBinding>
    </bindings>     
    <behaviors>      
      <endpointBehaviors>
        <behavior name="web">
          <webHttp automaticFormatSelectionEnabled="true" />
        </behavior>         
      </endpointBehaviors>
      <serviceBehaviors>       
        <behavior name="CustomBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>       
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel> 
</configuration>

所以现在我的问题是,如何在代码中定义我的自定义行为并将其添加到 webconfig?我需要做什么改变?另外,如果我要设置“BodyStyle = WebMessageBodyStyle.Wrapped”,我该怎么做?在哪里做?

4

1 回答 1

0

我看到这个问题很久以前就发布了,但可能对某人有用。我在 overcoder.net 上找到了解决方案。您只需要为所需的输出格式生成对应的字符串,并使用 Stream 作为结果类型。

[OperationContract]
[WebGet(UriTemplate = "test?format={format}")]
System.IO.Stream test(string format);
public System.IO.Stream test(string format)
{
     ArrayList ar = new ArrayList() { 1, 2, 3 };
     if (format == "text")
         result = String.Join(",", ar.ToArray());
     if (format == "xml")
     { 
        result = @"<soapenv:Envelope>
   <soapenv:Header/>
   <soapenv:Body>
      <result>";
        foreach (int i in ar)
            result += String.Format("\r\n        <item>{0}</item>", i);
        result += @"
      </result>
   </soapenv:Body>
</soapenv:Envelope>";
     }
     if (format == "json")
         result = JsonConvert.SerializeObject(ar, Newtonsoft.Json.Formatting.Indented);

     OutgoingWebResponseContext context = WebOperationContext.Current.OutgoingResponse;
     context.ContentType = "text/plain";
     return new System.IO.MemoryStream(ASCIIEncoding.Default.GetBytes(result));
}
于 2020-09-18T09:03:04.230 回答