【问题标题】:Newtonsoft JSON optionally change payload casing WebAPI 2Newtonsoft JSON 可选地更改有效负载外壳 WebAPI 2
【发布时间】:2015-02-25 21:22:24
【问题描述】:

我已将骆驼外壳配置为 Newtonsoft 库的默认 JSON 输出。在 Application_Start 期间调用了以下行:

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

对 WebAPI 的所有 javascript REST 调用(使用 WebAPI 2)都可以正常工作,并将驼峰格式的 JSON 字符串返回给客户端。

现在,我在我的一个网页上使用 jTable 控件 (http://www.jtable.org),并且此控件要求以 正确案例 返回 JSON 有效负载。 所以问题是 即使通过 Application_Start 的默认配置设置为驼峰式大小写,我如何可以选择更改 WebAPI 以返回正确大小写 JSON 有效负载,而不更改全局默认设置是什么? 我需要为应用程序中的这一 WebAPI 调用返回正确的 JSON 有效负载。

我已经尝试过 [http://fizzylogic.nl/2014/07/30/changing-the-casing-of-json-properties-in-asp-dot-net-web-api/] 这个,但我无法让 ActionFilterAttribute.OnActionExecuting 触发。所以解决方案没有奏效。

我还在 WebAPI 方法中添加了以下代码行

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new JsonContractResolver(new JsonMediaTypeFormatter());

这可行,但正确大小写现在成为其他 WebAPI 调用的默认格式。

这是 WebAPI sn-p

public JTableDtoImpl Get(int id, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = "") {
        List<MobileOrderModel> orders = _svc.GetMobileOrders(id);
        var dto = new JTableDtoMobileOrdersImpl(orders, jtStartIndex, jtPageSize) {
            Message = string.Format("DataSource:{0}", _svc.DataSource)
        };
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new JsonContractResolver(new JsonMediaTypeFormatter());
        return dto;
}

这里的问题是我现在无法恢复到默认的驼峰格式,因为那时方法已经返回。

还有其他建议吗?

【问题讨论】:

  • 如果您有三种方法,例如 A、B 和 C,您是否需要在任何/所有方法中动态更改大小写,还是只需要始终为方法 C 运行 Pascal case?
  • 我只需要为方法 C 运行 Pascal 案例(总是)。其他方法应继续使用驼峰式的默认设置。
  • 您可能会让您的方法返回一个字符串,并在正文中使用JsonSerializer 直接传递您想要/需要的任何设置。这不应该影响其他一切的全局设置。
  • 正确。返回一个字符串可能是一个有效的解决方案,但我正在寻找一个更优雅的解决方案,我希望 Newtonsoft.Json 可以提供。到目前为止, Request.CreateResponse() 方法是我要使用的解决方案。谢谢。

标签: c# .net json asp.net-web-api2


【解决方案1】:

您可以使用the overload that takes a MediaTypeFormatter 调用Request.CreateResponse 并传入new JsonMediaTypeFormatter(),类似于您在全局设置它的方式,但专门针对这一方法。当然,您可以指定任何您想要的SerializerSettings。最好将它的私有静态实例保留在您的控制器中,这样您就不会每次都 newing 它。

【讨论】:

  • 大卫,谢谢你的建议。我用过它,它有效。我想我太专注于尝试使用 Newtonsoft.Json 库来实现这一点。我想我希望它有某种类型的 MediaTypeFormatter 覆盖选项,可用于根据调用的 WebAPI 更改 JSON 有效负载的返回方式。
  • 如果您想控制在一个集中位置跨多个 API 方法使用哪些序列化设置,您应该考虑编写自己的 MediaTypeFormatter。然后,您可以检查请求并拥有要路由的序列化程序映射或类似的东西。
  • 哈。最后发现我需要单击复选标记才能将其标记为已接受的解决方案。再次感谢大卫的所有建议。
【解决方案2】:

您需要显式序列化您的 JSON,而不是返回一个对象并让 WebApi 为您序列化它。尝试类似:

public JSonResult Get(int id, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = "")
{
   List<MobileOrderModel> orders = _svc.GetMobileOrders(id);
   var dto = new JTableDtoMobileOrdersImpl(orders, jtStartIndex, jtPageSize) {
      Message = string.Format("DataSource:{0}", _svc.DataSource)
   };
   return Json(dto, JsonRequestBehavior.AllowGet); // This serializes explicitly, before WebApi invokes the default serializer
}

【讨论】:

  • 首先,感谢您的回复。我使用最新版本的 Newtonsoft.Json (6.0.0.0) 尝试了您的解决方案。我找不到“JsonRequestBehavior”。另外,注释 [// This serializes explicit, before WebApi invokes the default serializer] 让我有点困惑。如果 Json() 序列化器在 WebAPI 序列化器之前被调用,那有什么意义呢? WebAPI 序列化器不会胜过 Json() 所做的一切吗?我无法编译代码和验证。请参阅下面我对 David Peden 建议的回复。
【解决方案3】:

这是我最终的 WebAPI 方法,它按我需要的方式工作。太糟糕了,我无法通过 Newtonsoft.Json 库获得此功能,因此该方法将返回业务对象而不是响应对象。为了清楚起见,我从课程中删除了代码。 (即:追踪、cmets 等)。

public class MobileOrdersController : ApiController {
    private static readonly MobileOrdersService _svc = new MobileOrdersService();
    private static readonly MediaTypeFormatter _properCaseFormatter = new JsonMediaTypeFormatter{
        SerializerSettings = new JsonSerializerSettings {
            ContractResolver = new DefaultContractResolver()
        }
    };

    [Authorize][HttpGet]
    public HttpResponseMessage GetCustomerMobileOrders(int id, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = "") {
        try {
            List<MobileOrderModel> orders = _svc.GetMobileOrders(id);
            var dto = new JTableDtoMobileOrdersImpl(orders, jtStartIndex, jtPageSize) {
                Message = string.Format("DataSource:{0}", _svc.DataSource)
            };
            return Request.CreateResponse(HttpStatusCode.OK, dto, _properCaseFormatter);
        } catch (Exception ex) {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
        }
    }
}

以下是 David 推荐的 OkNegotiatedContentResult 解决方案,因为我使用的是 WebAPI 2。

public class MobileOrdersController : ApiController {
    private static readonly MobileOrdersService _svc = new MobileOrdersService();
    private static readonly IContentNegotiator _conneg = GlobalConfiguration.Configuration.Services.GetContentNegotiator();
    private static readonly IEnumerable<JsonMediaTypeFormatter> _mediaTypeFormatters = new[] {
        new JsonMediaTypeFormatter {
            SerializerSettings = new JsonSerializerSettings {
                ContractResolver = new DefaultContractResolver()
            }
        }
    };

    [Authorize][HttpGet]
    public IHttpActionResult GetCustomerMobileOrders(int id, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = "") {
        try {
            List<MobileOrderModel> orders = _svc.GetMobileOrders(id);
            var dto = new JTableDtoMobileOrdersImpl(orders, jtStartIndex, jtPageSize) {
                Message = string.Format("DataSource:{0}", _svc.DataSource)
            };
            return new OkNegotiatedContentResult<JTableDtoMobileOrdersImpl>(dto, _conneg, Request, _mediaTypeFormatters);
        } catch (Exception ex) {
            return new ExceptionResult(ex, this);
        }
    }
}

【讨论】:

  • JsonMediaTypeFormatter 在后台使用 Json.Net。序列化的响应是相同的,无论您的 API 方法上的实际返回类型是什么。不知道你为什么不喜欢这个解决方案...
  • 我还建议明确设置序列化程序设置以维护您想要的大小写,以便 a.) 声明您的意图和 b.) 如果默认值发生更改,您的代码不会休息。
  • 还有一件事,如果您正在运行 Web API 2,您可以返回 OkNegotiatedContentResult&lt;T&gt;(请参阅 here)以获得强类型响应。
  • 关于我关于声明意图的评论,我会将您的格式化程序变量更改为:private static readonly IEnumerable&lt;JsonMediaTypeFormatter&gt; _mediaTypeFormatters = new[] { new JsonMediaTypeFormatter { SerializerSettings = new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() } } };
  • 谢谢。我用你的行更新了代码 sn-p。并在我的项目中使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 2016-12-28
  • 1970-01-01
  • 2021-09-27
  • 1970-01-01
相关资源
最近更新 更多