WCF를 사용하는 웹 서비스에 대한 간단한 클라이언트를 작성하고 있습니다. 불행히도 웹 서비스는 JSONP 메시지 만 사용하여 응답하고 일반 JSON은 응답하지 않습니다.WCF JSONP 응답을 읽는 클라이언트
이렇게하려면 .NET 4.0의 기본 제공 기능을 사용할 수 있습니까? 아니면 서버에서 가져온 응답에서 함수 이름을 제거하기 위해 뭔가를 확장해야합니까? JSONP는 읽지 않지만 JSONP는 읽는 방법을 알고 있습니다.
WCF를 사용하는 웹 서비스에 대한 간단한 클라이언트를 작성하고 있습니다. 불행히도 웹 서비스는 JSONP 메시지 만 사용하여 응답하고 일반 JSON은 응답하지 않습니다.WCF JSONP 응답을 읽는 클라이언트
이렇게하려면 .NET 4.0의 기본 제공 기능을 사용할 수 있습니까? 아니면 서버에서 가져온 응답에서 함수 이름을 제거하기 위해 뭔가를 확장해야합니까? JSONP는 읽지 않지만 JSONP는 읽는 방법을 알고 있습니다.
사용자 정의 메시지 인코더가 필요합니다. 서버 측에서는 패딩 (함수 호출)을 응답에 추가하는 인코더이므로 메시지를 처리하기 전에 패딩을 제거하기 위해 클라이언트 측에서 비슷한 것을 필요로합니다 (다른 인코더로 위임 할 가능성이 있음). 인코더에서 걱정할 필요가있는 다른 사항은 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();
}
}
내가 알고 있지만 먼저 단순히 사이에 모든 것을 제거 할 수있는 JSON 문자열을 얻으려면
//JSON
{"prop":"val"}
//JSONP
func({"prop":"val"});
JSON과 JSONP의 차이를 이해하려고 노력하자 직접적인 방법이없는 "("와 ") "중괄호를 사용하고 다른 JSON 라이브러리를 사용하여 객체로 변환합니다.
string jsonString = Regex.Match(jsonpString, @"\(([^)]*)\)").Groups[1].Value
알아요.하지만 내 자체 역 직렬화 클래스를 구현하려면 WCF의 어느 부분을 확장해야합니까? –