Использование JSON.NET как сериализатор JSON по умолчанию внутри ASP.NET MVC 3-это возможно?
можно ли использовать JSON.NET как сериализатор JSON по умолчанию в ASP.NET MVC 3?
согласно моим исследованиям, кажется, что единственный способ сделать это -extend ActionResult как JsonResult в MVC3 не является виртуальным...
Я надеялся, что с ASP.NET MVC 3, что будет способ указать подключаемый поставщик для сериализации в JSON.
мысли?
7 ответов:
Я считаю, что лучший способ сделать это - как описано в ваших ссылках - расширить 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); }
EDIT 2: Я удалил проверку на то, что данные являются нулевыми в соответствии с приведенными ниже предложениями. Это должно сделать более новые версии JQuery счастливы и кажутся разумной вещью, так как ответ может быть безоговорочно десериализован. Однако имейте в виду, что это не поведение по умолчанию для ответов JSON от ASP.NET MVC, который скорее отвечает пустой строкой, когда нет данных.
я реализовал это без необходимости базового контроллера или инъекции.
я использовал фильтры действий для замены 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); } }
в мировой.асакс.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); } }
используйте конвертер JSON от Newtonsoft:
public ActionResult DoSomething() { dynamic cResponse = new ExpandoObject(); cResponse.Property1 = "value1"; cResponse.Property2 = "value2"; return Content(JsonConvert.SerializeObject(cResponse)); }
Я знаю, что это хорошо после ответа на вопрос, но я использую другой подход, поскольку я использую инъекцию зависимостей для создания экземпляров моих контроллеров.
Я заменил IActionInvoker (путем введения свойства ControllerActionInvoker контроллера ) с версией, которая переопределяет метод InvokeActionMethod.
Это означает отсутствие изменений в наследовании контроллера, и его можно легко удалить при обновлении до MVC4 путем изменения контейнера DI регистрация для всех контроллеров
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 ); } } } }
- - - EDIT-обновлено, чтобы показать регистрацию контейнера для контроллеров. Я использую 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"); }
Я сделал версию, которая делает действия веб-службы безопасными и простыми. Вы используете его так:
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); } }
мой пост может кому-то помочь.
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); } }