103

ASP.NET MVC 3 でJSON.NETをデフォルトの JSON シリアライザーとして使用することは可能ですか?

私の調査によると、これを達成する唯一の方法は、MVC3 の JsonResult が仮想ではないため、ActionResult を拡張することのようです ...

ASP.NET MVC 3 では、JSON にシリアル化するためのプラグ可能なプロバイダーを指定する方法があることを期待していました。

考え?

4

7 に答える 7

107

リンクで説明されているように、 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);
    }

編集 2 : 以下の提案に従って、Data が null であることのチェックを削除しました。これは、新しいバージョンの JQuery を満足させるはずであり、応答を無条件に逆シリアル化できるため、適切な方法のように思えます。ただし、これは ASP.NET MVC からの JSON 応答の既定の動作ではなく、データがない場合は空の文字列で応答することに注意してください。

于 2011-08-22T17:05:22.850 に答える
28

Newtonsoft の JSON コンバーターを使用します。

public ActionResult DoSomething()
{
    dynamic cResponse = new ExpandoObject();
    cResponse.Property1 = "value1";
    cResponse.Property2 = "value2";
    return Content(JsonConvert.SerializeObject(cResponse), "application/json");
}
于 2013-05-25T17:37:39.513 に答える
21

これは質問に回答した後でも十分であることはわかっていますが、依存性注入を使用してコントローラーをインスタンス化しているため、別のアプローチを使用しています。

IActionInvoker を (コントローラーの ControllerActionInvoker Property を注入することにより) InvokeActionMethod メソッドをオーバーライドするバージョンに置き換えました。

これは、コントローラーの継承に変更がないことを意味し、すべてのコントローラーの DI コンテナーの登録を変更することにより、MVC4 にアップグレードするときに簡単に削除できます。

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

--- 編集 - コントローラーのコンテナー登録を表示するように更新しました。ここでは 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);
    }
}
于 2012-08-09T07:33:07.300 に答える
13

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");
}
于 2015-04-21T10:30:15.890 に答える
5

Web サービス アクションをタイプ セーフかつシンプルにするバージョンを作成しました。次のように使用します。

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);
    }
}
于 2015-05-22T04:02:05.127 に答える