Использование JSON.NET в качестве стандартного JSON-сериализатора в ASP.NET MVC 3 – возможно ли это?

Можно ли использовать JSON.NET в качестве сериализатора JSON по умолчанию в ASP.NET MVC 3?

Согласно моим исследованиям, кажется, что единственный способ добиться этого – расширить ActionResult, поскольку JsonResult в MVC3 не является виртуальным …

Я надеялся, что с ASP.NET MVC 3 будет возможность указать подключаемый провайдер для сериализации в JSON.

Мысли?

    Я считаю, что лучший способ сделать это – как описано в ваших ссылках – расширить ActionResult или расширить JsonResult напрямую.

    Что касается метода JsonResult, который не является виртуальным на controllerе, это не так, просто выберите правильную перегрузку. Это хорошо работает:

    protected override JsonResult Json(object data, string contentType, Encoding contentEncoding) 

    EDIT 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); } 

    EDIT 2 : я удалил чек, чтобы данные были пустыми в соответствии с приведенными ниже рекомендациями. Это должно привести к тому, что новые версии JQuery будут счастливыми и, похоже, станут разумными, поскольку ответ можно безоговорочно десериализовать. Помните, однако, что это не поведение по умолчанию для ответов JSON от ASP.NET MVC, которое скорее отвечает пустой строкой, когда нет данных.

    Я реализовал это без использования базового controllerа или инъекции.

    Я использовал фильтры действий, чтобы заменить 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()); 

    Для завершения, вот мой class расширения 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); } } 

    Используйте конвертер JSON от Newtonsoft:

     public ActionResult DoSomething() { dynamic cResponse = new ExpandoObject(); cResponse.Property1 = "value1"; cResponse.Property2 = "value2"; return Content(JsonConvert.SerializeObject(cResponse)); } 

    Я знаю, что это хорошо после ответа на вопрос, но я использую другой подход, поскольку я использую инъекцию зависимостей для создания экземпляров моих controllerов.

    Я заменил IActionInvoker (путем ввода свойства ControllerActionInvoker controllerа) версией, которая переопределяет метод InvokeActionMethod.

    Это означает отсутствие изменений в наследовании controllerа и его можно легко удалить при обновлении до MVC4, изменив регистрацию контейнера DI для ВСЕХ controllerов

     public class JsonNetActionInvoker : ControllerActionInvoker { protected override ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary 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 ); } } } } 

    — EDIT – Обновлен, чтобы показать регистрацию контейнера для controllerов. Я использую Unity здесь.

     private void RegisterAllControllers(List exportedTypes) { this.rootContainer.RegisterType(); Func isIController = typeof(IController).IsAssignableFrom; Func 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(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(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"); } 

    Я сделал версию, которая делает действия веб-сервиса безопасными и простыми. Вы используете его следующим образом:

     public JsonResult MyAction() { return new MyDataContract(); } 

    Класс:

     public class JsonResult : 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 d) { return new JsonResult(d); } } 

    Мой пост может помочь кому-то.

     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); } } 
    Давайте будем гением компьютера.