WCF客户端读取JSONP响应
我正在使用WCF为web服务编写一个简单的客户端。不幸的是,web服务只回答JSONP消息,而不是简单的JSONWCF客户端读取JSONP响应,wcf,jsonp,Wcf,Jsonp,我正在使用WCF为web服务编写一个简单的客户端。不幸的是,web服务只回答JSONP消息,而不是简单的JSON 是否可以使用.NET4.0中的内置功能来实现这一点,或者是否需要扩展其他功能以从服务器上得到的答案中去掉函数名{和}?我知道如何读取JSON响应,但还不知道如何读取JSONP。我不知道如何直接读取JSON响应,但让我们先尝试理解JSON和JSONP之间的区别 //JSON {"prop":"val"} //JSONP func({"prop":"val"}); 要获取JSON字符串
是否可以使用.NET4.0中的内置功能来实现这一点,或者是否需要扩展其他功能以从服务器上得到的答案中去掉函数名{和}?我知道如何读取JSON响应,但还不知道如何读取JSONP。我不知道如何直接读取JSON响应,但让我们先尝试理解JSON和JSONP之间的区别
//JSON
{"prop":"val"}
//JSONP
func({"prop":"val"});
要获取JSON字符串,只需去掉“(“和”)”大括号之间的所有内容,然后使用不同的JSON库将其转换为对象
string jsonString = Regex.Match(jsonpString, @"\(([^)]*)\)").Groups[1].Value
您需要的是一个定制的消息编码器。在服务器端,是编码器将填充(函数调用)添加到响应中,因此在处理消息(可能将其委托给另一个编码器)之前,客户端需要类似的东西来删除填充。在编码器中,您需要担心的另一件事是,用于JSONP(应用程序/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();
}
}
公共类堆栈溢出\u 11255528
{
[服务合同]
公共接口计算器
{
[WebGet(ResponseFormat=WebMessageFormat.Json)]
整数加(整数x,整数y);
[WebGet(ResponseFormat=WebMessageFormat.Json)]
整数减去(整数x,整数y);
}
[服务合同]
公共类计算器服务
{
[WebGet(ResponseFormat=WebMessageFormat.Json)]
公共流添加(整数x,整数y)
{
退货包装(x+y);
}
[WebGet(ResponseFormat=WebMessageFormat.Json)]
公共流减法(整数x,整数y)
{
返回包装(x-y);
}
私有流ReturnWrapped(int结果)
{
字符串callback=“Something”;
字符串响应=string.Format(“{0}({1});”,回调,结果);
WebOperationContext.Current.OutgoingResponse.ContentType=“应用程序/x-javascript”;
返回新的MemoryStream(Encoding.UTF8.GetBytes(response));
}
}
公共类JsonpAwareClientMessageEncodingBindingElement:MessageEncodingBindingElement
{
WebMessageEncodingBindingElement webEncoding;
公共JsonpAwareClientMessageEncodingBindingElement()
{
this.webEncoding=新的WebMessageEncodingBindingElement();
}
公共重写MessageEncoderFactory CreateMessageEncoderFactory()
{
返回新的JsonpAwareClientMessageEncoderFactory(this.webEncoding.CreateMessageEncoderFactory());
}
公共覆盖消息版本消息版本
{
获取{返回this.webEncoding.MessageVersion;}
设置{this.webEncoding.MessageVersion=value;}
}
公共重写BindingElement克隆()
{
返回新的JsonpAwareClientMessageEncodingBindingElement();
}
公共重写IChannelFactory BuildChannelFactory(BindingContext上下文)
{
context.BindingParameters.Add(此);
返回context.BuildInnerChannelFactory();
}
类JsonpAwareClientMessageEncoderFactory:MessageEncoderFactory
{
私营工厂;
公共JsonpAwareClientMessageEncoderFactory(MessageEncoderFactory工厂)
{
这个工厂=工厂;
}
公共覆盖消息编码器
{
获取{返回新的JsonpAwareClientMessageEncoder(this.factory.Encoder);}
}
公共覆盖消息版本消息版本
{
获取{返回this.factory.MessageVersion;}
}
}
类JsonpAwareClientMessageEncoder:MessageEncoder
{
私有消息编码器;
公共JsonpAwareClientMessageEncoder(MessageEncoder编码器)
{
this.encoder=编码器;
}
公共重写字符串ContentType
{
获取{返回this.encoder.ContentType;}
}
公共重写字符串MediaType
{
获取{返回this.encoder.MediaType;}
}
公共覆盖消息版本消息版本
{
获取{返回this.encoder.MessageVersion;}
}
支持公共覆盖布尔IsContentTypeSupported(字符串contentType)
{
if(contentType==“应用程序/x-javascript”)
{
contentType=“应用程序/json”;
}
返回此.encoder.IsContentTypeSupported(contentType);
}
公共重写消息ReadMessage(ArraySegment buffer、BufferManager、BufferManager、string contentType)
{
if(contentType==“应用程序/x-javascript”)
{
contentType=“应用程序/json”;
}
字节圆括号=(字节)“(”;
字节右括号=(字节)'”;
int startof括号=buffer.Offset;
int count=buffer.count;
while(buffer.Array[StartOfBranchers]!=OpenBranchers)
{
startof括号++;
计数--;
}
//跳过“Func”,现在跳过“(”
startof括号++;
计数--;
//现在需要