WCF XML&使用单个OperationContract方法支持JSON?

时间:2013-04-02 06:33:13

标签: wcf

我试图按照以下要求工作几天。我希望我的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结构,我必须做出哪些更改/添加?有没有办法使用Code和XML和JSON设置这个BodyStyle(P.S.API应该是它的方式,不应该传递任何参数,如getvalue / {xml})?

提前谢谢。

更新:下面是我的OperationContract:

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

这是DataContract:

 [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);
        }
    }

这是我的webconfig:

<?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”如何&amp;我在哪里这样做?

1 个答案:

答案 0 :(得分: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));
}