ASP.NET MVC 3でデフォルトのJSON シリアライザーとしてJSON.NETを使用することは可能ですか?
私の研究によれば、これを実現する唯一の方法はしているようだのActionResultを延ばすようMVC3にするJsonResult仮想ではありません ...
ASP.NET MVC 3では、JSONにシリアル化するためのプラグ可能なプロバイダーを指定する方法があることを期待していました。
考え?
ASP.NET MVC 3でデフォルトのJSON シリアライザーとしてJSON.NETを使用することは可能ですか?
私の研究によれば、これを実現する唯一の方法はしているようだのActionResultを延ばすようMVC3にするJsonResult仮想ではありません ...
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:以下の提案に従って、データがnullかどうかのチェックを削除しました。これにより、JQueryの新しいバージョンが幸せになり、無条件に逆シリアル化できるようになるため、正気なことのように思えます。ただし、これはASP.NET MVCからのJSON応答のデフォルトの動作ではなく、データがない場合は空の文字列で応答することに注意してください。
if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException(MvcResources.JsonRequest_GetNotAllowed);
ですか?私はこのチェックを答えに追加する必要があると思います(内部はありMvcResources.JsonRequest_GetNotAllowed
ませんが、いくつかのカスタムメッセージがあります)また、他の2つのデフォルトのasp.net mvcチェック-MaxJsonLengthとRecursionLimitはどうですか?json.netを使用する場合、それらは必要ですか?
ベースコントローラーやインジェクションを必要とせずにこれを実装しました。
アクションフィルターを使用して、JsonResultをJsonNetResultに置き換えました。
public class JsonHandlerAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var jsonResult = filterContext.Result as JsonResult;
if (jsonResult != null)
{
filterContext.Result = new JsonNetResult
{
ContentEncoding = jsonResult.ContentEncoding,
ContentType = jsonResult.ContentType,
Data = jsonResult.Data,
JsonRequestBehavior = jsonResult.JsonRequestBehavior
};
}
base.OnActionExecuted(filterContext);
}
}
Global.asax.cs Application_Start()で、次を追加する必要があります。
GlobalFilters.Filters.Add(new JsonHandlerAttribute());
完了のために、私が他の場所から取得したJsonNetResult拡張クラスを以下に示します。これは、正しいスチーミングサポートを得るために少し変更したものです。
public class JsonNetResult : JsonResult
{
public JsonNetResult()
{
Settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Error
};
}
public JsonSerializerSettings Settings { get; private set; }
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))
throw new InvalidOperationException("JSON GET is not allowed");
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;
if (this.ContentEncoding != null)
response.ContentEncoding = this.ContentEncoding;
if (this.Data == null)
return;
var scriptSerializer = JsonSerializer.Create(this.Settings);
scriptSerializer.Serialize(response.Output, this.Data);
}
}
return Json()
実際にネイティブがJson.Netを使用するようにします。
JsonResult
from Json()
をインターセプトしてに変換しJsonNetResult
ます。これはas
、変換が不可能な場合にnullを返すキーワードを使用して行われます。とても気の利いた。グリフィンドールが10ポイント!
[BetterJsonHandler]
:-)。
NewtonsoftのJSONコンバーターを使用します。
public ActionResult DoSomething()
{
dynamic cResponse = new ExpandoObject();
cResponse.Property1 = "value1";
cResponse.Property2 = "value2";
return Content(JsonConvert.SerializeObject(cResponse), "application/json");
}
これは質問への回答が得られた後もよくわかりますが、依存関係注入を使用してコントローラーをインスタンス化しているため、別のアプローチを使用しています。
IActionInvokerを(コントローラーのControllerActionInvokerプロパティを挿入することにより)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");
}
JObject jo = GetJSON(); return Content(jo.ToString(), "application/json");
私の投稿は誰かを助けるかもしれません。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
namespace MultipleSubmit.Service
{
public abstract class BaseController : Controller
{
protected override JsonResult Json(object data, string contentType,
Encoding contentEncoding, JsonRequestBehavior behavior)
{
return new JsonNetResult
{
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior
};
}
}
}
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MultipleSubmit.Service
{
public class JsonNetResult : JsonResult
{
public JsonNetResult()
{
Settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Error
};
}
public JsonSerializerSettings Settings { get; private set; }
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))
throw new InvalidOperationException("JSON GET is not allowed");
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(this.ContentType) ?
"application/json" : this.ContentType;
if (this.ContentEncoding != null)
response.ContentEncoding = this.ContentEncoding;
if (this.Data == null)
return;
var scriptSerializer = JsonSerializer.Create(this.Settings);
using (var sw = new StringWriter())
{
scriptSerializer.Serialize(sw, this.Data);
response.Write(sw.ToString());
}
}
}
}
public class MultipleSubmitController : BaseController
{
public JsonResult Index()
{
var data = obj1; // obj1 contains the Json data
return Json(data, JsonRequestBehavior.AllowGet);
}
}
BaseController
で実装しているので、これは変更の影響が最も少なかったので、クラスを追加して更新するだけで済みましたBaseController
。
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);
}
}