ASP.NET MVCのWebApiへのAjax呼び出しで、500 Internal Server Errorが返される。
ASP.NET MVCで導入されたWebApiは、ajaxのインタラクションニーズに自然かつうまく対応していますが、jQuery ajaxでWebApiを呼び出すと、500 Internal Server Errorを返してしまうというエラーを見つけるのは簡単ではありません。実際のプロジェクトでは、WebApiのメソッドはすべてtry-catchで例外をキャッチし、独自のエラーメッセージを返しており、エラーがあればキャッチできることが当然と考えられています。しかし、最近、サイトが常に500エラーで動作するようになり、何が問題なのかを見つけるのに苦労しました。
<スパン デバッグを重ねた結果、このエラーは WebApi メソッドの外部で発生させるべきものであることが判明しました(メソッドは try-catch で内部的にキャッチする必要があります)。当初は、ASP.NET MVC フレームワークの JSON シリアライズがオブジェクトを返したときに発生するランタイム エラーでした。返されるオブジェクトをシリアライズする JsonConvert.SerializeObject() メソッドで、クラスオブジェクトの get プロパティ(派生値)がゼロで割られているというエラーが発覚しました。一般に、オブジェクトのgetプロパティは、そのプロパティにアクセスしたときだけ、その中のコードが実行されます。どうやら、オブジェクトのJSONシリアライズは、オブジェクトのgetプロパティのコードをすべて呼び出し、永続的なプロパティ値を取得するようです。
結論から言うと
- JSONデータを返す際にWebApiのシリアライズ操作で発生する例外は、WebApiメソッド外の例外であり、当面はキャッチできない(作者以下の.NET Framework 4.0では当面はキャッチする方法が見つかっていない)、その場合、500 Internal Server Errorエラーを返すことになります。
- JSONがオブジェクトをシリアライズするとき、そのオブジェクトのすべてのgetプロパティ値(つまり、getプロパティを実行するコード)を取得することになります。
- 例外が直接スローされ、キャッチされるように、JSONシリアライズ操作をプログラム的にエミュレートすることが可能である。
この記事で紹介した方法は、Visual Studio Community 2015、.NET 4.0、ASP.NET MVC4でデバッグを通過させます。
追記です。
何日もかけてWebを調査しデバッグした結果、WebApiメソッドのJsonシリアライズによって発生する例外をキャッチする汎用的な方法を発見しました。基本的なアイデアは、ASP.NET MVCのデフォルトのJsonシリアライゼーションコンバータJsonConverter(このクラスはNewtonsoftのダイナミックライブラリで提供されています)をカスタマイズして、シリアライズストリームを読み書きするときに例外をキャッチするようにすることです。
書き換えたJsonConverterコンバータクラスのコードは以下の通りである。
using System;
Net.Http.Formatting;
Tasks;
Tasks; using Newtonsoft;
Http; using System;
Http; using System;
Http; using System;
namespace CSUST.Kyz
Kyz
public class TJsonConverter : MediaTypeFormatter
Kyz {
public TJsonConverter()
{
SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
public override bool CanWriteType(Type type)
{
return true;
}
public override bool CanReadType(Type type)
{
return true;
}
public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
var task = Task<object>.Factory.StartNew(() =>
StartNew() => {
StartNew() => { try
{
string json;
using (var sr = new StreamReader(readStream, System.Text.Encoding.UTF8))
{
json = sr.ReadToEnd();
sr.Close();
}
return JsonConvert.DeserializeObject(json);
}
catch(Exception err)
{
TLogs.Save("read except:" + err.StackTrace); // Save the exception message
throw err;
}
});
return task;
}
public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
var task = Task.Factory.StartNew(() =>
StartNew() => {
StartNew() => { try
{ try
var json = JsonConvert.SerializeObject(value);
GetBytes(json). byte[] buf = System.Text;
WriteStream.Write(buf, 0, buf;)
WriteStream.Flush();
}
catch(Exception err)
{
TLogs.Save("write except:" + err.StackTrace); // Save the exception message
throw err;
}
});
return task;
}
}
}
また、上記のカスタムJsonシリアライゼーションコンバータを、以下のコードでグローバル設定ファイルに登録する必要があります(global.asax.csの関数)。
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable;)
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); // Clear all data formats
GlobalConfiguration.Configuration.Formatters.Insert(0, new TJsonConverter()); // Only the serializer and Json format are defined
}
関連
-
RuntimeWarning: double_scalars で無効な値が発生しました precision.append(tp[i] * 1.0 / (tp[i])
-
undefined[エラー] 'delete' の前に未修飾の ID が必要です。
-
unity build when エラー
-
エラーです。Cannot find module '@vue/cli-plugin-babel'.
-
javaは起動したが、終了コード=-805306369を返した。
-
JAVA の小さな問題を解決する
-
id 'com.android.library' を持つプラグインが見つかりません。
-
C/C++学習メモ-アクティブな例外なしで呼び出されるterminate
-
Python がエラー TypeError: write() 引数はバイトではなく str でなければならない
-
AndroidのタッチイベントonScrollとonFlingは、特に区別が重要です。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Xcode has Expected unqualified-id エラー
-
DataTableプラグインエラーです。Uncaught TypeError: 未定義のプロパティ 'style' を読み取ることができません。
-
ダブルフリーまたはコラプション(Fasttop)生成
-
MySql ERROR 1046(3D000): 選択されたデータベースがない場合の解決策
-
プログラム ld の解決策の 1 つが 1 の終了ステータスを返した
-
リソースの読み込みに失敗しました:サーバーは403(Forbidden)のステータスで応答しました。
-
Bluetooth接続のタイムアウト現象
-
ModuleNotFoundError: scipy'という名前のモジュールがない ソリューション
-
Eclipse いくつかのプロジェクトは、ワークスペースにすでに存在するため、インポートできません ソリューション
-
Baiduマップの呼び出しでエラーが報告された Uncaught TypeError:Cannot read property 'fc' of undefined