同源策略(Same Origin Policy)的存在导致了“源”自A的脚本只能操作“同源”页面的DOM,“跨源”操作来源于B的页面将会被拒绝。同源策略以及跨域资源共享在大部分情况下针对的是Ajax请求。同源策略主要限制了通过XMLHttpRequest实现的Ajax请求,如果请求的是一个“异源”地址,浏览器将不允许读取返回的内容。JSONP是一种常用的解决跨域资源共享的解决方案,现在我们利用ASP.NET Web API自身的扩展性提供一种“通用”的JSONP实现方案。
在《[CORS:跨域资源共享] 同源策略与JSONP》,我们是在具体的Action方法中将返回的JSON对象“填充”到JavaScript回调函数中,现在我们通过自定义的MediaTypeFormatter来为JSONP提供一种更为通用的实现方式。
我们通过继承JsonMediaTypeFormatter定义了如下一个JsonpMediaTypeFormatter类型。它的只读属性Callback代表JavaScript回调函数名称,改属性在构造函数中指定。在重写的方法WriteToStreamAsync中,对于非JSONP调用(回调函数不存在),我们直接调用基类的同名方法对响应对象实施针对JSON的序列化,否则调用WriteToStream方法将对象序列化后的JSON字符串填充到JavaScript回调函数中。
class JsonpMediaTypeFormatter : JsonMediaTypeFormatter
2: {
private set; }
4:
null)
6: {
this.Callback = callback;
8: }
9:
object value, Stream writeStream, HttpContent content, TransportContext transportContext)
11: {
this.Callback))
13: {
base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
15: }
try
17: {
this.WriteToStream(type, value, writeStream, content);
new AsyncVoid());
20: }
catch (Exception exception)
22: {
new TaskCompletionSource<AsyncVoid>();
24: source.SetException(exception);
return source.Task;
26: }
27: }
28:
object value, Stream writeStream, HttpContent content)
30: {
this.SerializerSettings);
this.SupportedEncodings.First()))
false })
35: {
);
37: serializer.Serialize(jsonTextWriter, value);
);
39: }
40: }
41:
override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
43: {
if (request.Method != HttpMethod.Get)
45: {
this;
47: }
string callback;
if (request.GetQueryNameValuePairs().ToDictionary(pair => pair.Key,
out callback))
51: {
new JsonpMediaTypeFormatter(callback);
53: }
this;
55: }
56:
57: [StructLayout(LayoutKind.Sequential, Size = 1)]
struct AsyncVoid
59: {}
60: }