WCF客户端读取JSONP响应

WCF客户端读取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字符串

我正在使用WCF为web服务编写一个简单的客户端。不幸的是,web服务只回答JSONP消息,而不是简单的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括号++;
计数--;
//现在需要