ASP.NET MVC 3 でJSON.NETをデフォルトの JSON シリアライザーとして使用することは可能ですか?
私の調査によると、これを達成する唯一の方法は、MVC3 の JsonResult が仮想ではないため、ActionResult を拡張することのようです ...
ASP.NET MVC 3 では、JSON にシリアル化するためのプラグ可能なプロバイダーを指定する方法があることを期待していました。
考え?
ASP.NET MVC 3 でJSON.NETをデフォルトの JSON シリアライザーとして使用することは可能ですか?
私の調査によると、これを達成する唯一の方法は、MVC3 の JsonResult が仮想ではないため、ActionResult を拡張することのようです ...
ASP.NET MVC 3 では、JSON にシリアル化するためのプラグ可能なプロバイダーを指定する方法があることを期待していました。
考え?
リンクで説明されているように、 ActionResult を拡張するか、 JsonResult を直接拡張するのが最善の方法だと思います。
真ではないコントローラー上の仮想ではないメソッド JsonResult については、適切なオーバーロードを選択してください。これはうまくいきます:
protected override JsonResult Json(object data, string contentType, Encoding contentEncoding)
編集 1 : JsonResult 拡張機能...
public class JsonNetResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !String.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
// If you need special handling, you can call another form of SerializeObject below
var serializedObject = JsonConvert.SerializeObject(Data, Formatting.Indented);
response.Write(serializedObject);
}
編集 2 : 以下の提案に従って、Data が null であることのチェックを削除しました。これは、新しいバージョンの JQuery を満足させるはずであり、応答を無条件に逆シリアル化できるため、適切な方法のように思えます。ただし、これは ASP.NET MVC からの JSON 応答の既定の動作ではなく、データがない場合は空の文字列で応答することに注意してください。
Newtonsoft の JSON コンバーターを使用します。
public ActionResult DoSomething()
{
dynamic cResponse = new ExpandoObject();
cResponse.Property1 = "value1";
cResponse.Property2 = "value2";
return Content(JsonConvert.SerializeObject(cResponse), "application/json");
}
これは質問に回答した後でも十分であることはわかっていますが、依存性注入を使用してコントローラーをインスタンス化しているため、別のアプローチを使用しています。
IActionInvoker を (コントローラーの ControllerActionInvoker Property を注入することにより) InvokeActionMethod メソッドをオーバーライドするバージョンに置き換えました。
これは、コントローラーの継承に変更がないことを意味し、すべてのコントローラーの DI コンテナーの登録を変更することにより、MVC4 にアップグレードするときに簡単に削除できます。
public class JsonNetActionInvoker : ControllerActionInvoker
{
protected override ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
ActionResult invokeActionMethod = base.InvokeActionMethod(controllerContext, actionDescriptor, parameters);
if ( invokeActionMethod.GetType() == typeof(JsonResult) )
{
return new JsonNetResult(invokeActionMethod as JsonResult);
}
return invokeActionMethod;
}
private class JsonNetResult : JsonResult
{
public JsonNetResult()
{
this.ContentType = "application/json";
}
public JsonNetResult( JsonResult existing )
{
this.ContentEncoding = existing.ContentEncoding;
this.ContentType = !string.IsNullOrWhiteSpace(existing.ContentType) ? existing.ContentType : "application/json";
this.Data = existing.Data;
this.JsonRequestBehavior = existing.JsonRequestBehavior;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if ((this.JsonRequestBehavior == JsonRequestBehavior.DenyGet) && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
base.ExecuteResult(context); // Delegate back to allow the default exception to be thrown
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = this.ContentType;
if (this.ContentEncoding != null)
{
response.ContentEncoding = this.ContentEncoding;
}
if (this.Data != null)
{
// Replace with your favourite serializer.
new Newtonsoft.Json.JsonSerializer().Serialize( response.Output, this.Data );
}
}
}
}
--- 編集 - コントローラーのコンテナー登録を表示するように更新しました。ここでは Unity を使用しています。
private void RegisterAllControllers(List<Type> exportedTypes)
{
this.rootContainer.RegisterType<IActionInvoker, JsonNetActionInvoker>();
Func<Type, bool> isIController = typeof(IController).IsAssignableFrom;
Func<Type, bool> isIHttpController = typeof(IHttpController).IsAssignableFrom;
foreach (Type controllerType in exportedTypes.Where(isIController))
{
this.rootContainer.RegisterType(
typeof(IController),
controllerType,
controllerType.Name.Replace("Controller", string.Empty),
new InjectionProperty("ActionInvoker")
);
}
foreach (Type controllerType in exportedTypes.Where(isIHttpController))
{
this.rootContainer.RegisterType(typeof(IHttpController), controllerType, controllerType.Name);
}
}
public class UnityControllerFactory : System.Web.Mvc.IControllerFactory, System.Web.Http.Dispatcher.IHttpControllerActivator
{
readonly IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
}
IController System.Web.Mvc.IControllerFactory.CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
return this.container.Resolve<IController>(controllerName);
}
SessionStateBehavior System.Web.Mvc.IControllerFactory.GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
{
return SessionStateBehavior.Required;
}
void System.Web.Mvc.IControllerFactory.ReleaseController(IController controller)
{
}
IHttpController IHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
return this.container.Resolve<IHttpController>(controllerType.Name);
}
}
https://stackoverflow.com/users/183056/sami-beyogluからの回答を拡張すると、コンテンツ タイプを設定すると、jQuery は返されたデータをオブジェクトに変換できます。
public ActionResult DoSomething()
{
dynamic cResponse = new ExpandoObject();
cResponse.Property1 = "value1";
cResponse.Property2 = "value2";
return Content(JsonConvert.SerializeObject(cResponse), "application/json");
}
Web サービス アクションをタイプ セーフかつシンプルにするバージョンを作成しました。次のように使用します。
public JsonResult<MyDataContract> MyAction()
{
return new MyDataContract();
}
クラス:
public class JsonResult<T> : JsonResult
{
public JsonResult(T data)
{
Data = data;
JsonRequestBehavior = JsonRequestBehavior.AllowGet;
}
public override void ExecuteResult(ControllerContext context)
{
// Use Json.Net rather than the default JavaScriptSerializer because it's faster and better
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !String.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
var serializedObject = JsonConvert.SerializeObject(Data, Formatting.Indented);
response.Write(serializedObject);
}
public static implicit operator JsonResult<T>(T d)
{
return new JsonResult<T>(d);
}
}