103 votes

En utilisant JSON.net comme défaut sérialiseur JSON dans ASP.NET MVC 3 - est-il possible ?

Est-il possible d'utiliser JSON.net par défaut JSON sérialiseur ASP.NET MVC 3?

Selon mes recherches, il semble que la seule façon d'y parvenir est de prolonger ActionResult comme JsonResult dans MVC3 n'est pas virtuel...

J'espère qu'avec MVC3 qu'il y aurait un moyen de spécifier un fournisseur enfichable pour la sérialisation JSON.

Pensées?

107voto

asgerhallas Points 5134

Je crois que la meilleure façon de le faire, est - comme décrit dans vos liens à étendre ActionResult ou de prolonger JsonResult directement.

Comme pour la méthode JsonResult qui n'est pas du virtuel sur le contrôleur qui n'est pas vrai, il suffit de choisir le droit de surcharge. Cela fonctionne bien:

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

EDIT 1: UN JsonResult extension...

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: j'ai enlevé la vérification de Données null comme valeur par les suggestions ci-dessous. Que devraient faire les nouvelles versions de JQuery heureux et semble comme la sane chose à faire, comme la réponse peut ensuite être inconditionnellement désérialisé. Sachez cependant, que ce n'est pas le comportement par défaut pour les réponses JSON à partir de ASP.NET MVC, qui répond plutôt à une chaîne vide, quand il n'y a pas de données.

65voto

MDB Points 111

C'est aussi longtemps après que la question a été répondue, mais je l'ai fait sans la nécessité d'un contrôleur de base ou de l'injection.

J'ai utilisé de l'action des filtres à remplacer le JsonResult avec un 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);            
    }
}

Dans le Global.asax.cs Application_Start (), vous devrez ajouter:

GlobalFilters.Filters.Add(new JsonHandlerAttribute());

Pour la réalisation de l'intérêt, ici, est mon JsonNetResult de l'extension de la classe que j'ai ramassé par ailleurs et que j'ai modifié légèrement pour obtenir de bons à la vapeur de soutien:

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

29voto

Sami Beyoglu Points 27

Utiliser le newtonsoft json convertisseur

21voto

Robert Slaney Points 2491

Je sais que c'est bien après que la question a été posée, mais je suis en utilisant une approche différente, je suis à l'aide de l'injection de dépendance pour instancier mon contrôleurs.

J'ai remplacé le IActionInvoker ( en injectant du contrôleur ControllerActionInvoker Propriété ) avec une version qui remplace la InvokeActionMethod méthode.

Cela signifie pas de changement de contrôleur de l'héritage, et il peut facilement être enlevé lorsque je mettre à MVC4 en modifiant le conteneur d'injection de dépendances d'inscription pour TOUS les contrôleurs

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 - mise à Jour pour afficher le conteneur d'inscription pour les contrôleurs. Je suis l'aide de l'Unité ici.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X