您的位置:首页 > 编程语言 > ASP

通过扩展让ASP.NET Web API支持JSONP

2013-12-06 12:33 447 查看

通过扩展让ASP.NET Web API支持JSONP

[code] public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter

{

 public string Callback{ get; private set;}


 public JsonpMediaTypeFormatter(string callback = null)

{

 this.Callback = callback;

}


 public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)

{

 if (string.IsNullOrEmpty(this.Callback))

{

 return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);

}

 try

{

 this.WriteToStream(type, value, writeStream, content);

 return Task.FromResult<AsyncVoid>(new AsyncVoid());

}

 catch (Exception exception)

{

 TaskCompletionSource<AsyncVoid> source = new TaskCompletionSource<AsyncVoid>();

 source.SetException(exception);

 return source.Task;

}

}


 private void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)

{

 JsonSerializer serializer = JsonSerializer.Create(this.SerializerSettings);

 using(StreamWriter streamWriter = new StreamWriter(writeStream, this.SupportedEncodings.First()))

 using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter){ CloseOutput = false})

{

 jsonTextWriter.WriteRaw(this.Callback + "(");

 serializer.Serialize(jsonTextWriter, value);

 jsonTextWriter.WriteRaw(")");

}

}


 public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)

{

 if (request.Method != HttpMethod.Get)

{

 return this;

}

 string callback;

 if (request.GetQueryNameValuePairs().ToDictionary(pair => pair.Key, 

pair => pair.Value).TryGetValue("callback", out callback))

{

 return new JsonpMediaTypeFormatter(callback);

}

 return this;

}


 [StructLayout(LayoutKind.Sequential, Size = 1)]

 private struct AsyncVoid

{}

}

[/code]
[/code]
我们重写了GetPerRequestFormatterInstance方法,在默认情况下,当ASP.NET Web API采用内容协商机制选择出与当前请求相匹配的MediaTypeFormatter后,会调用此方法来创建真正用于序列化响应结果的MediaTypeFormatter对象。在重写的这个GetPerRequestFormatterInstance方法中,我们尝试从请求的URL中得到携带的JavaScript回调函数名称,即一个名为“callback”的查询字符串。如果回调函数名不存在,则直接返回自身,否则返回据此创建的JsonpMediaTypeFormatter对象。

[code]public class ContactsController : ApiController

{

 public IEnumerable<Contact> GetAllContacts()

{

 Contact[] contacts = new Contact[]

{

 new Contact{ Name="张三", PhoneNo="123", EmailAddress="zhangsan@gmail.com"},

 new Contact{ Name="李四", PhoneNo="456", EmailAddress="lisi@gmail.com"},

 new Contact{ Name="王五", PhoneNo="789", EmailAddress="wangwu@gmail.com"},

};

 return contacts;

}

}


public class Contact

{

 public string Name{ get; set;}

 public string PhoneNo{ get; set;}

 public string EmailAddress{ get; set;}

}

[/code]
[/code]
现在我们在WebApi应用的Global.asax中利用如下的程序创建这个JsonpMediaTypeFormatter对象并添加当前注册的MediaTypeFormatter列表中。为了让它被优先选择,我们将这个JsonpMediaTypeFormatter对象放在此列表的最前端。

[code]
[code] public class WebApiApplication : System.Web.HttpApplication

{

 protected void Application_Start()

{

 GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter ());

 //其他操作

}

}

[/code]
[/code]
接下来们在MvcApp应用中定义如下一个HomeController,默认的Action方法Index会将对应的View呈现出来。

[code]
[code] public class HomeController : Controller

{

 public ActionResult Index()

{

 return View();

}

}

[/code]
[/code]
如下所示的是Action方法Index对应View的定义。我们的目的在于:当页面成功加载之后以Ajax请求的形式调用上面定义的Web API获取联系人列表,并将自呈现在页面上。如下面的代码片断所示,我们直接调用$.ajax方法并将dataType参数设置为“jsonp”。

[code]
[code] <html>

<head>

 <title>联系人列表</title>

 <script type="text/javascript" src="@Url.Content("~/scripts/jquery-1.10.2.js")"></script>

</head>

<body>

 <ul id="contacts"></ul>

 <script type="text/javascript">

 $(function ()

{

 $.ajax({

 Type : "GET",

 url: "http://localhost:3721/api/contacts",

 dataType : "jsonp",

 success: listContacts

});

});


 function listContacts(contacts){

 $.each(contacts, function (index, contact){

 var html = "<li><ul>";

 html += "<li>Name: " + contact.Name + "</li>";

 html += "<li>Phone No:" + contact.PhoneNo + "</li>";

 html += "<li>Email Address: " + contact.EmailAddress + "</li>";

 html += "</ul>";

 $("#contacts").append($(html));

});

}

 </script>

</body>

</html>

[/code]
[/code]
直接运行该ASP.NET MVC程序之后,会得到如下图所示的输出结果,通过跨域调用Web API获得的联系人列表正常地显示出来。

[code] GET http://localhost:3721/api/contacts?callback=jQuery110205729522893670946_1386232694513 &_=1386232694514 HTTP/1.1

Host: localhost:3721

Connection: keep-alive

Accept: */*

User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36

Referer: http://localhost:9527/[/code] 
Accept-Encoding: gzip,deflate,sdch


HTTP/1.1 200 OK

Cache-Control: no-cache

Pragma: no-cache

Content-Type: application/json; charset=utf-8

Expires: -1

Server: Microsoft-IIS/8.0

X-AspNet-Version: 4.0.30319

X-SourceFiles: =?UTF-8?B?RTpc5oiR55qE6JGX5L2cXEFTUC5ORVQgV2ViIEFQSeahhuaetuaPreenmFxOZXcgU2FtcGxlc1xDaGFwdGVyIDE0XFMxNDAzXFdlYkFwaVxhcGlcY29ud?=

X-Powered-By: ASP.NET

Date: Thu, 05 Dec 2013 08:38:15 GMT

Content-Length: 248


jQuery110205729522893670946_1386232694513([{"Name":"张三","PhoneNo":"123","EmailAddress":"zhangsan@gmail.com"},{"Name":"李四","PhoneNo":"456","EmailAddress":"lisi@gmail.com"},{"Name":"王五","PhoneNo":"789","EmailAddress":"wangwu@gmail.com"}])

[/code]
[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: