【问题标题】:Specific JSON settings per controller on ASP.NET MVC 6ASP.NET MVC 6 上每个控制器的特定 JSON 设置
【发布时间】:2016-08-27 06:31:33
【问题描述】:

我需要在我的 ASP.NET MVC 6 webApi 中为每个控制器设置特定的 JSON 设置。 我发现这个示例适用于 MVC 5(我希望!): Force CamelCase on ASP.NET WebAPI Per Controller

using System;
using System.Linq;
using System.Web.Http.Controllers;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Serialization;

public class CamelCaseControllerConfigAttribute : Attribute, IControllerConfiguration 
{
    public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
    {
        var formatter = controllerSettings.Formatters.OfType<JsonMediaTypeFormatter>().Single();
        controllerSettings.Formatters.Remove(formatter);

        formatter = new JsonMediaTypeFormatter
        {
            SerializerSettings = {ContractResolver = new CamelCasePropertyNamesContractResolver()}
        };

        controllerSettings.Formatters.Add(formatter);

    }
}

【问题讨论】:

  • 您不想接收与模型类同名的 API?相反,您希望它们在每个模型的 pasalCase 中?
  • 这只是一个访问JsonSerializerSettings对象的示例。就我而言,我需要更改移动应用程序使用的某些控制器的绑定器

标签: c# configuration json.net asp.net-core asp.net-core-mvc


【解决方案1】:

这个类工作正常:

using System;
using System.Linq;
using Newtonsoft.Json.Serialization;
using Microsoft.AspNet.Mvc.Filters;
using Newtonsoft.Json;
using Microsoft.AspNet.Mvc.Formatters;

namespace Teedl.Web.Infrastructure
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]

    public class MobileControllerConfiguratorAttribute : Attribute, IResourceFilter
    {
        private readonly JsonSerializerSettings serializerSettings;

        public MobileControllerConfiguratorAttribute()
        {
            serializerSettings = new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects,
                TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
                Binder = new TypeNameSerializationBinder("Teedl.Model.Mobile.{0}, Teedl.Model.ClientMobile")
        };
        }


        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }

        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            var mobileInputFormatter = new JsonInputFormatter(serializerSettings);
            var inputFormatter = context.InputFormatters.FirstOrDefault(frmtr => frmtr is JsonInputFormatter);
            if (inputFormatter != null)
            {
                context.InputFormatters.Remove(inputFormatter);
            }
            context.InputFormatters.Add(mobileInputFormatter);

            var mobileOutputFormatter = new JsonOutputFormatter(serializerSettings);
            var outputFormatter = context.OutputFormatters.FirstOrDefault(frmtr => frmtr is JsonOutputFormatter);
            if (outputFormatter != null)
            {
                context.OutputFormatters.Remove(outputFormatter);
            }
            context.OutputFormatters.Add(mobileOutputFormatter);
        }
    }
}

使用:

[Route("api/mobile/businessrequest")]
[Authorize]
[MobileControllerConfigurator]
public class MobileBusinessRequestController : BaseController
{

【讨论】:

  • Input/OutputFormatters 在资源上下文中不再存在。有谁知道现在如何访问它们?
  • 也想要“Microsoft.AspNetCore.Mvc.Filters”的解决方案。
  • 也许对于不同的框架版本你可以使用stackoverflow.com/a/44499722/782022
  • 另请参阅stackoverflow.com/a/52193035/10391,了解在最新的 Core MVC 中自定义输入格式化程序的方法
【解决方案2】:

您可以在控制器操作方法上使用 JsonResult 的返回类型。就我而言,我需要特定的操作来为某些遗留场景返回 Pascal Case。 JsonResult 对象允许您将可选参数作为 JsonSerializerSettings 传递。

public JsonResult Get(string id)
{
    var data = _service.getData(id);

    return Json(data, new JsonSerializerSettings
    {
        ContractResolver = new DefaultContractResolver()
    });

}

为了获得更一致的控制器方法签名,我最终创建了一个扩展方法:

public static JsonResult ToPascalCase(this Controller controller, object model)
{
    return controller.Json(model, new JsonSerializerSettings
    {
        ContractResolver = new DefaultContractResolver()
    });
}

现在我可以简单地调用控制器内部的扩展方法,如下所示:

public IActionResult Get(string id)
{
    var data = _service.getData(id);
    return this.ToPascalCase(data);
}

【讨论】:

  • 是的,这也是我正在做的事情 - 类似的场景:具有 JS 依赖项的旧库依赖于默认情况下使用旧代码构建。无法控制应用程序设置客户端获取正确的案例。希望有一种不同的方式来做到这一点,以保留更简单的合同界面。
  • @RickStrahl 编辑答案以包含处理此问题的扩展方法。干净一点。
猜你喜欢
  • 1970-01-01
  • 2015-10-02
  • 1970-01-01
  • 2022-06-30
  • 2023-03-07
  • 1970-01-01
  • 2016-08-23
  • 2011-03-31
  • 1970-01-01
相关资源
最近更新 更多