2011-07-30 9 views
17

Mam kontroler, który powraca do dużych obiektów JSON jQuery Flot i zastanawiałem się, jak łatwo byłoby zastąpić domyślny JavaScriptSerializer coś szybciej, jak ten z ServiceStack.Text.Zmień domyślne JSON serializer używany w ASP MVC3

Byłoby dobrze, gdybym mógł zmienić rzeczy, jak to przy użyciu DependencyResolver, ale przypuszczam, że jeśli absolutnie wszystko zostało rozwiązane to było, to może się dość powoli.

+0

powiązane: http://stackoverflow.com/questions/7109967/using-json-net-as-default-json-serializer-in-asp-net-mvc-3-is-possible –

+1

Zapytałem pytanie 2 tygodnie przed połączonym duplikatem ... To sprawia, że ​​drugie pytanie jest duplikatem! – Tim

Odpowiedz

40

najlepiej jest dziedziczą z klasy JsonResult i zastąpić metody Execute jak

public class CustomJsonResult: JsonResult 
{ 
    public CustomJsonResult() 
    { 
     JsonRequestBehavior = JsonRequestBehavior.DenyGet; 
    } 
    public override void ExecuteResult(ControllerContext context) { 
      if (context == null) { 
       throw new ArgumentNullException("context"); 
      } 
      if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && 
       String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { 
       throw new InvalidOperationException(MvcResources.JsonRequest_GetNotAllowed); 
      } 

      HttpResponseBase response = context.HttpContext.Response; 

      if (!String.IsNullOrEmpty(ContentType)) { 
       response.ContentType = ContentType; 
      } 
      else { 
       response.ContentType = "application/json"; 
      } 
      if (ContentEncoding != null) { 
       response.ContentEncoding = ContentEncoding; 
      } 
      if (Data != null) { 
       CustomJsSerializer serializer = new CustomJsSerializer(); 
       response.Write(serializer.Serialize(Data)); 
      } 
     } 
} 

kod jest pobierana z JsonResult klasy mvc3 i zmienił tę linię

JavaScriptSerializer serializer = new JavaScriptSerializer(); 

do

CustomJsSerializer serializer = new CustomJsSerializer(); 

można użyć tej klasy w sposobie działania jak

public JsonResult result() 
{ 
    var model = GetModel(); 
    return new CustomJsonResult{Data = model}; 
} 

Dodatkowo można przesłonić metody json klasy Controller w sterowniku bazowym jak

public class BaseController:Controller 
{ 
    protected internal override JsonResult Json(object data) 
     { 
      return new CustomJsonResult { Data = data }; 
     } 
} 

teraz jeśli masz wszystkie kontrolery z BaseController następnie return Json(data) zadzwoni Twój schemat serializacji. Istnieją również inne przeciążenia metody Json, które możesz zastąpić.

+0

w ASP.NET MVC 3, metoda - JsonResult Json (dane obiektu) nie jest wirtualny :( – Maxim

+6

Nie, ale JsonResult Json (dane obiektu, ciąg contentType, kodowanie contentEncoding) jest, a drugi tylko delegaci tam tak szczęśliwy nadrzędnym. :) – asgerhallas

+3

Widocznie trzeba zastąpić jedną z 4 parametrów: protected override JsonResult JSON (dane obiektu, ciąg contentType, Kodowanie contentEncoding, zachowanie JsonRequestBehavior) – Daniel

5

Dodaję tę odpowiedź po prostu dlatego używam alternatywnego rozwiązania, które nie wymaga nadrzędnych klasę System.Web.Mvc.Controller. Dodaję następujące metody rozszerzenia do klasy System.Web.Mvc.Controller. Jedyną "zaletą" tego rozwiązania jest to, że nie wymaga to zmiany klasy bazowej generowanych przez kod klas Controller. W przeciwnym razie jest funkcjonalnie równoważny z zaakceptowaną odpowiedzią.

public static JsonResult ToJsonResult(this Controller controller, 
              object target, 
              string contentType, 
              Encoding contentEncoding, 
              JsonRequestBehavior behavior) 
    { 
     if (target != null) 
     { 
      if (target.GetType().HasAttribute<DataContractAttribute>()) 
      { 
       return new DataContractJsonResult() { ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior, Data = target }; 
      } 
     } 
     return new JsonResult() { ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior, Data = target }; 
    } 

    public static JsonResult ToJsonResult(this Controller controller, object target) 
    { 
     return controller.ToJsonResult(target, null, null, JsonRequestBehavior.DenyGet); 
    } 

    public static JsonResult ToJsonResult(this Controller controller, object target, string contentType) 
    { 
     return controller.ToJsonResult(target, contentType, null, JsonRequestBehavior.DenyGet); 
    } 

    public static JsonResult ToJsonResult(this Controller controller, object target, string contentType, Encoding contentEncoding) 
    { 
     return controller.ToJsonResult(target, contentType, contentEncoding, JsonRequestBehavior.DenyGet); 
    } 

    public static JsonResult ToJsonResult(this Controller controller, object target, string contentType, JsonRequestBehavior behavior) 
    { 
     return controller.ToJsonResult(target, contentType, null, behavior); 
    } 

W mojej aplikacji zastąpić domyślnego kontrolera i użyć serializatora Json.NET jeśli typ posiada atrybut DataContract. Ta funkcjonalność jest enkapsulowana w klasie DataContractJsonResult, która nie jest zawarta, ale jest wzorowana na klasie w zaakceptowanej odpowiedzi na to pytanie.

Powiązane problemy