ASP.NET Web API用のJSONP Formatter

ASP.NET Web APIには、JSONP Formatterは含まれていませんが、自分で作成するのは非常に簡単です。



JSONPが必要な理由



JSONPは、アプリケーションがダウンロードされたサーバー以外のサーバーからデータを受信する際の制限を回避するjavascriptアプリケーションの機能の1つです。 JSONPは、サーバーからデータを受信したときに実行される関数でJSONデータをラップします。 たとえば、リソースがあるとします。 RemoteDomain/aspnetWebApi/albums



RemoteDomain/aspnetWebApi/albums



リクエストでアルバムのリストを提供し、このリストをJSONP形式で提供する方法を認識しています。 jQueryを使用すると、次のようになります。



 function getAlbums() { $.getJSON("http://remotedomain/aspnetWebApi/albums?callback=?", null, function (albums) { alert(albums.length); }); }
      
      





JSONPはどのように見えるか



JSONPはかなり単純な「プロトコル」です。 彼がしていることは、データをJSON形式で関数にラップすることだけです。 上記のクエリの結果は次のようになります。



Query17103401925975181569_1333408916499( [{"Id":"34043957","AlbumName":"Dirty Deeds Done Dirt Cheap",…},{…}] )







jQueryはリクエストを送信し、レスポンスを受信して​​「実行」し、JSONデータをパラメーターとして受け取ります。



JSONPの仕組み



JSONPの仕組みを理解するために、純粋なjavascriptで次の例を示します。



 function jsonp(url, callback) { //    var id = "_" + (new Date()).getTime(); //    window[id] = function (result) { //    if (callback) callback(result); // :     var sc = document.getElementById(id); sc.parentNode.removeChild(sc); window[id] = null; } url = url.replace("callback=?", "callback=" + id); //   <script>,   JSONP- //   ,   window[id] var script = document.createElement("script"); script.setAttribute("id", id); script.setAttribute("src", url); script.setAttribute("type", "text/javascript"); document.body.appendChild(script); }
      
      





前のjQueryの例と同様に、この関数を使用してアルバムのリストを取得します。



 function getAlbumsManual() { jsonp("http://remotedomain/aspnetWebApi/albums?callback=?", function (albums) { alert(albums.length); }); }
      
      





JSONPおよびASP.NET Web API



記事の冒頭で述べたように、ASP.NET Web APIはそのままでJSONPをサポートしていません。 ただし、独自のJSONPフォーマッターを作成してプロジェクトに接続するのは非常に簡単です。



以下のコードは、Christian Weyerに基づいています。 コードは、最新のWeb API RTMとの互換性のために変更されました。



 using System; using System.IO; using System.Net; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Threading.Tasks; using System.Web; using System.Net.Http; using Newtonsoft.Json.Converters; using System.Web.Http; namespace Westwind.Web.WebApi { /// <summary> /// Handles JsonP requests when requests are fired with text/javascript /// </summary> public class JsonpFormatter : JsonMediaTypeFormatter { public JsonpFormatter() { SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript")); JsonpParameterName = "callback"; } /// <summary> /// Name of the query string parameter to look for /// the jsonp function name /// </summary> public string JsonpParameterName {get; set; } /// <summary> /// Captured name of the Jsonp function that the JSON call /// is wrapped in. Set in GetPerRequestFormatter Instance /// </summary> private string JsonpCallbackFunction; public override bool CanWriteType(Type type) { return true; } /// <summary> /// Override this method to capture the Request object /// </summary> /// <param name="type"></param> /// <param name="request"></param> /// <param name="mediaType"></param> /// <returns></returns> public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, System.Net.Http.HttpRequestMessage request, MediaTypeHeaderValue mediaType) { var formatter = new JsonpFormatter() { JsonpCallbackFunction = GetJsonCallbackFunction(request) }; // this doesn't work unfortunately //formatter.SerializerSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings; // You have to reapply any JSON.NET default serializer Customizations here formatter.SerializerSettings.Converters.Add(new StringEnumConverter()); formatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; return formatter; } public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext) { if (string.IsNullOrEmpty(JsonpCallbackFunction)) return base.WriteToStreamAsync(type, value, stream, content, transportContext); StreamWriter writer = null; // write the pre-amble try { writer = new StreamWriter(stream); writer.Write(JsonpCallbackFunction + "("); writer.Flush(); } catch (Exception ex) { try { if (writer != null) writer.Dispose(); } catch { } var tcs = new TaskCompletionSource<object>(); tcs.SetException(ex); return tcs.Task; } return base.WriteToStreamAsync(type, value, stream, content, transportContext) .ContinueWith( innerTask => { if (innerTask.Status == TaskStatus.RanToCompletion) { writer.Write(")"); writer.Flush(); } },TaskContinuationOptions.ExecuteSynchronously) .ContinueWith( innerTask => { writer.Dispose(); return innerTask; },TaskContinuationOptions.ExecuteSynchronously) .Unwrap(); } /// <summary> /// Retrieves the Jsonp Callback function /// from the query string /// </summary> /// <returns></returns> private string GetJsonCallbackFunction(HttpRequestMessage request) { if (request.Method != HttpMethod.Get) return null; var query = HttpUtility.ParseQueryString(request.RequestUri.Query); var queryVal = query[this.JsonpParameterName]; if (string.IsNullOrEmpty(queryVal)) return null; return queryVal; } } }
      
      





このコードはWeb APIのベータ版では動作せず、RTMバージョンでのみ動作することに再度注意します。



また、このJSONPフォーマッターを接続すると、実際には同じJSONタイプを処理するため、ストックJSONフォーマッターを置き換えることに注意してください。 このコードはまだ標準のJSONフォーマッターを使用していますが、初期化はしませんが、JSONまたはJSONPリクエストごとに新しいインスタンスを作成します。 これは、一部の画像に対してJSONフォーマッターを構成する必要がある場合、このコードでGetPerRequestFormatterInstance()



オーバーライドしてこれを行う必要があることをGetPerRequestFormatterInstance()



します。



JSONPフォーマッター接続



JSONPフォーマッターは、Global.asax.csファイルのApplication_Start()



セクションのFormatterコレクションに追加することで接続されます



 protected void Application_Start(object sender, EventArgs e) { //   GlobalConfiguration .Configuration .Formatters .Insert(0, new Westwind.Web.WebApi.JsonpFormatter()); }
      
      





以上です。



ご注意 JSONPフォーマッターを他の全員の前に追加しました。 JSONフォーマッタは、標準のJSONフォーマッタの前に指定する必要があります。指定しないと、呼び出されません。



GitHubソースコード



翻訳者から



一般に、これは非常に無料の翻訳ですので、耳をすませてください。 本質を伝える上で重要な役割を果たさなかったため、多くの部分は省略されています。 いずれにしても、オリジナルを参照してください。



Web API RTMでは、 WriteToStreamAsync()



メソッドは、1つのパラメーターがWeb API RCのメソッドと異なります。最初のHttpContent



、2番目のパラメーターHttpContentHeader



です。



ApiConfig.cs



ファイルにJSON Formatterを含めました。



Apiconfig.cs



 public static void RegisterApiConfigure(HttpConfiguration config) { // Remove the JSON formatter //config.Formatters.Remove(config.Formatters.JsonFormatter); // Remove the XML formatter config.Formatters.Remove(config.Formatters.XmlFormatter); // Indenting //config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; // Add a custom JsopFormatter config.Formatters.Insert(0, new JsonpFormatter()); }
      
      





Global.asax.cs



 protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); ApiConfig.RegisterApiConfigure(GlobalConfiguration.Configuration); }
      
      






All Articles