Изменить по умолчанию JSON Serializer, используемый в ASP MVC3

У меня есть контроллер, который возвращает большие объекты JSON в jQuery Flot, и мне было интересно, как легко было бы заменить JavaScriptSerializer по умолчанию чем-то более быстрым, чем тот из ServiceStack.Text.

Было бы хорошо, если бы я мог изменить это, используя DependencyResolver, но я полагаю, что если бы все было разрешено, это могло бы стать довольно медленным.

Ответ 1

лучше всего наследовать от класса JsonResult и переопределить метод Execute, например

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

код берется из класса JsonResult mvc3 и изменяет эту строку

JavaScriptSerializer serializer = new JavaScriptSerializer();

to

CustomJsSerializer serializer = new CustomJsSerializer();

вы можете использовать этот класс в методе действий, например

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

Кроме того, вы можете переопределить json-метод класса Controller на вашем базовом контроллере, например

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

теперь, если у вас есть все ваши контроллеры из BaseController, тогда return Json(data) вызовет вашу схему сериализации. Существуют также другие перегрузки метода Json, которые вы можете переопределить.

Ответ 2

Я добавляю этот ответ просто потому, что я использую альтернативное решение, которое не требует переопределения класса System.Web.Mvc.Controller. Я добавляю следующие методы расширения в класс System.Web.Mvc.Controller. Единственное "преимущество" этого решения заключается в том, что он не требует, чтобы вы изменили базовый класс классов, созданных с помощью кода. В противном случае он функционально эквивалентен принятому ответу.

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

В моем приложении я переопределяю контроллер по умолчанию и использую сериализатор JSON.NET, если тип имеет атрибут DataContract. Эта функциональность инкапсулирована в класс DataContractJsonResult, который не включен, но моделируется после класса в принятом ответе на этот вопрос.