Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Is it possible to use JSON.net as default JSON serializer in ASP.NET MVC 3?

According to my research, it seems that the only way to accomplish this is to extend ActionResult as JsonResult in MVC3 is not virtual...

I hoped that with MVC3 that there would be a way to specify a pluggable provider for serializing to JSON.

Thoughts?

share|improve this question
add comment (requires an account with 50 reputation)

3 Answers

up vote 33 down vote accepted

I believe the best way to do it, is - as described in your links - to extend ActionResult or extend JsonResult directly.

As for the method JsonResult that is not virtual on the controller that's not true, just choose the right overload. This works well:

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

EDIT: An 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 (Data == null)
            return;

        // If you need special handling, you can call another form of SerializeObject below
        var serializedObject = JsonConvert.SerializeObject(Data, Formatting.Indented);
        response.Write(serializedObject);
    }
share|improve this answer
Thanks - I though I was on the right track, and you confirmed it...As for JsonResult not being virtual, I didn't even bother to check for other method signatures :), I just took it as granted based on the comment from Maxim here - stackoverflow.com/questions/6883204/… – zam6ak Aug 22 '11 at 19:39
So did I when I had the same problems a couple of weeks ago :) – asgerhallas Aug 22 '11 at 19:52
1  
The code refers to MySpecialContractResolver, which isn't defined. This question helps with that (and was very related to the problem I had to solve): stackoverflow.com/questions/6700053/… – Elliveny Feb 19 '12 at 13:53
1  
Thanks for the great answer. Why the if (Data == null) return; ? For my use case I wanted to get back whatever the JSON standard was, which Json.Net faithfully does, even for null (returning "null"). By intercepting null values you end up sending the empty string back for these, which deviates from the standard and causes downstream problems - for example with jQuery 1.9.1: stackoverflow.com/a/15939945/176877 – Chris Moschini Apr 11 at 4:41
1  
@Chris Moschini: You're absolutely right. It is wrong to return an empty string. But should it return the json value null or an empty json object then? I'm not sure returning a value where an object is expected is problem free either. But either way, the current code is not good in this respect. – asgerhallas Apr 11 at 15:56
show 6 more commentsadd comment (requires an account with 50 reputation)

I know this is well after the question has been answered, but I'm using a different approach as I am using dependency injection to instantiate my controllers.

I have replaced the IActionInvoker ( by injecting the controller's ControllerActionInvoker Property ) with a version that overrides the InvokeActionMethod method.

This means no change to controller inheritance and it can be easily removed when I upgrade to MVC4 by altering the DI container's registration for ALL controllers

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 - Updated to show container registration for controllers. I'm using Unity here.

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);
    }
}
share|improve this answer
2  
+1 for "unobtrusive" solution. – georgiosd Sep 4 '12 at 14:18
Nice, but how do you use it? Or better how did you inject it? – DotNetWise Oct 30 '12 at 23:57
1  
added more implementation – Robert Slaney Oct 31 '12 at 4:36
+1 for using the Stream form of .Serialize(). I was going to point out you can just use JsonConvert like the other top answer, but your approach gradually streams out long/large objects - that's a free performance boost, especially if the downstream client can handle partial responses. – Chris Moschini Apr 11 at 4:49
add comment (requires an account with 50 reputation)

Use newtonsoft json converter

public ActionResult DoSomething()
    {
        dynamic cResponse = new ExpandoObject();
        cResponse.Property1 = "value1";
        cResponse.Property2 = "value2";
        return Content(JsonConvert.SerializeObject(cResponse));
    }
share|improve this answer
add comment (requires an account with 50 reputation)

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.