c#:关于NewtonsoftJson序列化和Grpc序列化的冲突问题

环境:

  • window10
  • asp.net core 3.1

一般web框架都是用Newtonsoft.Json序列化库,在asp.net core中引用如下:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers().AddNewtonsoftJson(options =>
    {
        //忽略循环引用
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        //使用驼峰 首字母小写
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        //设置时间格式
        options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
        //将枚举序列化为字符串
        //options.SerializerSettings.Converters.Add(new StringEnumConverter());
    });
}

这么用一般没什么问题,
然而在grpc中的序列化是需要借助 [DataContract]和[DataMember]的,所以定义一个公共dto模型的时候就不得不考虑冲突的问题:

比如说以下分页请求模型:

public class PageReq
{
    public int PageIndex { get; set; }
    public int PageSize { get; set; }
}

public class GetUserListReq : PageReq
{
    public string Name { get; set; }
}

这个模型在web开发中是没有问题的,但是到了Grpc中就出现了问题:因为PageReq未标记为[DataContract],[DataMember]所以不会被序列化。

于是,在PageReq上增加标记如下:

[DataContract]
public class PageReq
{
    [DataMember(Order = 1)]
    public int PageIndex { get; set; }

    [DataMember(Order = 2)]
    public int PageSize { get; set; }
}

public class GetUserListReq : PageReq
{
    [DataMember(Order = 3)]
    public string Name { get; set; }
}

当打上标记后,针对grpc的数据传输是没有问题了,但当这个模型应用在web开发中时,我们发现所有继承自 PageReq的模型属性都必须打上DataMember标记,否则不被序列化和反序列化,如下所示:

/*模型*/
[DataContract]
public class PageReq
{
    [DataMember(Order = 1)]
    public int PageIndex { get; set; }

    [DataMember(Order = 2)]
    public int PageSize { get; set; }
}

public class GetUserListReq : PageReq
{
    public string Name { get; set; }
}

/*startup.cs引入newtonsoft*/
//...此处省略

/*Controller定义*/
[Route("api/[controller]/[action]")]
public class DemoController : ControllerBase
{
    [HttpPost]
    public string TestJson([FromBody] GetUserListReq req)
    {
        if (string.IsNullOrWhiteSpace(req.Name)) req.Name = "xxxx";
        var res = Newtonsoft.Json.JsonConvert.SerializeObject(req);
        return $"res={res}\r\nname={req.Name},pageIndex={req.PageIndex},pageSize={req.PageSize}";
    }
}

postman测试情况:
在这里插入图片描述
这就尴尬了,先说下原因:
默认Newtonsoft.Json序列化的规则是对所有公共属性都进行序列化,除非手动指定忽略哪些属性,如下:
在这里插入图片描述
而当我们在标记为[DataContract]特性后,就把序列化模式从OptOut改为OptIn,在OptIn模式下,Newtonsoft.Json只会序列化标记为JsonPropertyDataMember特性的属性,其他的则忽略。
让我们来看一下,Newtonsoft.Json的说明:
在这里插入图片描述
知道了其中的原因,那么将公共模型PageReq定义如下:

[JsonObject(MemberSerialization.OptOut)]
[DataContract]
public class PageReq
{
    [DataMember(Order = 1)]
    public int PageIndex { get; set; }

    [DataMember(Order = 2)]
    public int PageSize { get; set; }
}

public class GetUserListReq : PageReq
{
    public string Name { get; set; }
}

这样,再看一下postman的情况:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jackletter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值