2012-06-29 2 views
0

Я пишу простой клиент для веб-службы с использованием WCF. К сожалению, веб-служба отвечает только сообщениями JSONP, а не просто JSON.WCF Клиент читает ответы JSONP

Возможно ли использовать встроенные функции .NET 4.0 для этого или мне нужно расширить что-то еще, чтобы удалить имя функции, {и} из ответа, полученного с сервера? Я знаю, как читать ответы JSON, но не JSONP.

ответ

1

Что вам нужно - это специальный кодер сообщений. На стороне сервера это кодер, который добавляет отладку (вызов функции) к ответу, так что вам нужно что-то подобное на стороне клиента, чтобы удалить это дополнение перед обработкой сообщения (вероятно, делегируя его другому кодеру). Другая вещь, о которой вам нужно беспокоиться в кодере, заключается в том, что часто используемый тип содержимого, используемый для JSONP (application/x-javascript), не распознается как тип содержимого JSON (потому что это не так, это вызов функции) поэтому кодер должен также «переводить» этот тип контента в тот, который понимается кодером, которому делегирован вызов.

В приведенном ниже примере показан пример такого кодировщика. Служба была изменена, чтобы всегда обернуть результат, как вы упомянули о своей службе.

public class StackOverflow_11255528 
{ 
    [ServiceContract] 
    public interface ICalculator 
    { 
     [WebGet(ResponseFormat = WebMessageFormat.Json)] 
     int Add(int x, int y); 
     [WebGet(ResponseFormat = WebMessageFormat.Json)] 
     int Subtract(int x, int y); 
    } 
    [ServiceContract] 
    public class CalculatorService 
    { 
     [WebGet(ResponseFormat = WebMessageFormat.Json)] 
     public Stream Add(int x, int y) 
     { 
      return ReturnWrapped(x + y); 
     } 

     [WebGet(ResponseFormat = WebMessageFormat.Json)] 
     public Stream Subtract(int x, int y) 
     { 
      return ReturnWrapped(x - y); 
     } 

     private Stream ReturnWrapped(int result) 
     { 
      string callback = "Something"; 
      string response = string.Format("{0}({1});", callback, result); 
      WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-javascript"; 
      return new MemoryStream(Encoding.UTF8.GetBytes(response)); 
     } 
    } 
    public class JsonpAwareClientMessageEncodingBindingElement : MessageEncodingBindingElement 
    { 
     WebMessageEncodingBindingElement webEncoding; 

     public JsonpAwareClientMessageEncodingBindingElement() 
     { 
      this.webEncoding = new WebMessageEncodingBindingElement(); 
     } 

     public override MessageEncoderFactory CreateMessageEncoderFactory() 
     { 
      return new JsonpAwareClientMessageEncoderFactory(this.webEncoding.CreateMessageEncoderFactory()); 
     } 

     public override MessageVersion MessageVersion 
     { 
      get { return this.webEncoding.MessageVersion; } 
      set { this.webEncoding.MessageVersion = value; } 
     } 

     public override BindingElement Clone() 
     { 
      return new JsonpAwareClientMessageEncodingBindingElement(); 
     } 

     public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context) 
     { 
      context.BindingParameters.Add(this); 
      return context.BuildInnerChannelFactory<TChannel>(); 
     } 

     class JsonpAwareClientMessageEncoderFactory : MessageEncoderFactory 
     { 
      private MessageEncoderFactory factory; 

      public JsonpAwareClientMessageEncoderFactory(MessageEncoderFactory factory) 
      { 
       this.factory = factory; 
      } 

      public override MessageEncoder Encoder 
      { 
       get { return new JsonpAwareClientMessageEncoder(this.factory.Encoder); } 
      } 

      public override MessageVersion MessageVersion 
      { 
       get { return this.factory.MessageVersion; } 
      } 
     } 

     class JsonpAwareClientMessageEncoder : MessageEncoder 
     { 
      private MessageEncoder encoder; 

      public JsonpAwareClientMessageEncoder(MessageEncoder encoder) 
      { 
       this.encoder = encoder; 
      } 

      public override string ContentType 
      { 
       get { return this.encoder.ContentType; } 
      } 

      public override string MediaType 
      { 
       get { return this.encoder.MediaType; } 
      } 

      public override MessageVersion MessageVersion 
      { 
       get { return this.encoder.MessageVersion; } 
      } 

      public override bool IsContentTypeSupported(string contentType) 
      { 
       if (contentType == "application/x-javascript") 
       { 
        contentType = "application/json"; 
       } 

       return this.encoder.IsContentTypeSupported(contentType); 
      } 

      public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType) 
      { 
       if (contentType == "application/x-javascript") 
       { 
        contentType = "application/json"; 
       } 

       byte openParenthesis = (byte)'('; 
       byte closeParenthesis = (byte)')'; 
       int startOfParenthesis = buffer.Offset; 
       int count = buffer.Count; 
       while (buffer.Array[startOfParenthesis] != openParenthesis) 
       { 
        startOfParenthesis++; 
        count--; 
       } 

       // Skipped 'Func', now skipping '(' 
       startOfParenthesis++; 
       count--; 

       // Now need to trim the closing parenthesis and semicolon, if any 
       int endOfParenthesis = buffer.Offset + buffer.Count - 1; 
       while (buffer.Array[endOfParenthesis] != closeParenthesis) 
       { 
        endOfParenthesis--; 
        count--; 
       } 

       // Skipped back to ')', now remove it 
       endOfParenthesis--; 
       count--; 

       return this.encoder.ReadMessage(new ArraySegment<byte>(buffer.Array, startOfParenthesis, count), bufferManager, contentType); 
      } 

      public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType) 
      { 
       throw new NotSupportedException("Streamed mode not supported"); 
      } 

      public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset) 
      { 
       return this.encoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset); 
      } 

      public override void WriteMessage(Message message, Stream stream) 
      { 
       throw new NotSupportedException("Streamed mode not supported"); 
      } 
     } 
    } 
    public static void Test() 
    { 
     string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     ServiceHost host = new ServiceHost(typeof(CalculatorService), new Uri(baseAddress)); 
     WebHttpBinding binding = new WebHttpBinding { CrossDomainScriptAccessEnabled = true }; 
     host.AddServiceEndpoint(typeof(CalculatorService), binding, "").Behaviors.Add(new WebHttpBehavior()); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     WebClient c = new WebClient(); 
     Console.WriteLine(c.DownloadString(baseAddress + "/Add?x=5&y=8&callback=Func")); 

     CustomBinding clientBinding = new CustomBinding(
      new JsonpAwareClientMessageEncodingBindingElement(), 
      new HttpTransportBindingElement { ManualAddressing = true }); 
     ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>(clientBinding, new EndpointAddress(baseAddress)); 
     factory.Endpoint.Behaviors.Add(new WebHttpBehavior()); 
     ICalculator proxy = factory.CreateChannel(); 
     Console.WriteLine(proxy.Subtract(456, 432)); 

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

Там нет прямого пути, который я знаю, но давайте сначала попытаться понять разницу между JSON и JSONP

//JSON 
{"prop":"val"} 
//JSONP 
func({"prop":"val"}); 

Чтобы получить строку JSON можно просто раздеть каждую вещь в между «(» и ") ", а затем использовать разные библиотеки JSON для преобразования в объекты.

string jsonString = Regex.Match(jsonpString, @"\(([^)]*)\)").Groups[1].Value 
+0

Я знаю ... но какую часть WCF мне нужно расширить, чтобы реализовать мой собственный класс десериализации? –

Смежные вопросы