2013-05-11 71 views
0

我試圖使用WCF消耗與URL編碼的數據來響應第三方REST服務:WCF REST讀取URL編碼的響應

a=1&b=2&c=3 

我有現在這樣:

[DataContract] 
class Response { 
    [DataMember(Name="a")] 
    public int A { get;set;} 
    [DataMember(Name="b")] 
    public int B { get;set;} 
    [DataMember(Name="c")] 
    public int C { get;set;} 
} 

[ServiceContract] 
interface IService 
{ 
    [OperationContract] 
    Response Foo(); 
} 

但它回來:

There was an error checking start element of object of type Response. The data at the root level is invalid. Line 1, position 1. 

回答

1

WCF不「理解」形式的數據內容類型(應用程序/ X WWW的形式進行了urlencoded),所以它不是b能夠直接讀取該響應。你可以實現一個message formatter,它可以將該格式轉換成你的合同,或者你可以收到回覆作爲Stream(它會給你答覆的全部字節),你可以解碼到你的課堂。

下面的代碼顯示瞭如何爲此操作實現格式化程序。這不是通用的,但你應該瞭解需要完成的事情。

public class StackOverflow_16493746 
{ 
    [ServiceContract] 
    public class Service 
    { 
     [WebGet(UriTemplate = "*")] 
     public Stream GetData() 
     { 
      WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-www-form-urlencoded"; 
      return new MemoryStream(Encoding.UTF8.GetBytes("a=1&b=2&c=3")); 
     } 
    } 
    [ServiceContract] 
    interface IService 
    { 
     [WebGet] 
     Response Foo(); 
    } 
    [DataContract] 
    class Response 
    { 
     [DataMember(Name = "a")] 
     public int A { get; set; } 
     [DataMember(Name = "b")] 
     public int B { get; set; } 
     [DataMember(Name = "c")] 
     public int C { get; set; } 
    } 
    public class MyResponseFormatter : IClientMessageFormatter 
    { 
     private IClientMessageFormatter originalFormatter; 

     public MyResponseFormatter(IClientMessageFormatter originalFormatter) 
     { 
      this.originalFormatter = originalFormatter; 
     } 

     public object DeserializeReply(Message message, object[] parameters) 
     { 
      HttpResponseMessageProperty httpResp = (HttpResponseMessageProperty) 
       message.Properties[HttpResponseMessageProperty.Name]; 
      if (httpResp.Headers[HttpResponseHeader.ContentType] == "application/x-www-form-urlencoded") 
      { 
       if (parameters.Length > 0) 
       { 
        throw new InvalidOperationException("out/ref parameters not supported in this formatter"); 
       } 

       byte[] bodyBytes = message.GetReaderAtBodyContents().ReadElementContentAsBase64(); 
       NameValueCollection pairs = HttpUtility.ParseQueryString(Encoding.UTF8.GetString(bodyBytes)); 
       Response result = new Response(); 
       foreach (var key in pairs.AllKeys) 
       { 
        string value = pairs[key]; 
        switch (key) 
        { 
         case "a": 
          result.A = int.Parse(value); 
          break; 
         case "b": 
          result.B = int.Parse(value); 
          break; 
         case "c": 
          result.C = int.Parse(value); 
          break; 
        } 
       } 

       return result; 
      } 
      else 
      { 
       return this.originalFormatter.DeserializeReply(message, parameters); 
      } 
     } 

     public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) 
     { 
      throw new NotSupportedException("This is a reply-only formatter"); 
     } 
    } 
    public class MyClientBehavior : WebHttpBehavior 
    { 
     protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint) 
     { 
      return new MyResponseFormatter(base.GetReplyClientFormatter(operationDescription, endpoint)); 
     } 
    } 
    public static void Test() 
    { 
     string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress)); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     ChannelFactory<IService> factory = new ChannelFactory<IService>(new WebHttpBinding(), new EndpointAddress(baseAddress)); 
     factory.Endpoint.Behaviors.Add(new MyClientBehavior()); 
     IService proxy = factory.CreateChannel(); 
     Response resp = proxy.Foo(); 
     Console.WriteLine("a={0},b={1},c={2}", resp.A, resp.B, resp.C); 

     ((IClientChannel)proxy).Close(); 
     factory.Close(); 

     Console.Write("Press ENTER to close the host"); 
     Console.ReadLine(); 
     host.Close(); 
    } 
} 
+0

謝謝。我有一個問題,'ReadElementContentAsBase64'調用拋出'在根級別的數據是無效的。第1行,位置1.'另外,你可以指向一個'流'樣本? – 2013-05-11 23:45:16

+0

沒關係,在您的博客文章中找到答案:http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/03/wcf-extensibility-message-formatters.aspx – 2013-05-11 23:59:45