【问题标题】:Exclude Zero Values when streaming to json with JsonResult in MVC在 MVC 中使用 JsonResult 流式传输到 json 时排除零值
【发布时间】:2018-11-19 19:09:39
【问题描述】:

我有如下所示的 Json。

这实际上是一个复杂得多的对象,但这段摘录说明了我的问题。

我正在考虑缩小生成的 Json 响应的大小。目前正在使用 MVC 中的标准 JsonResult 生成,

有没有办法让 JSonResult 不流式传输值为 0 的属性?如果可能的话,它会大大缩小我的 json 响应!这反过来会使解析速度更快。

 {
    "firstValue": 0.2000,
    "secondValue": 30.80,
    "thirdValue": 0.0,
    "fourthValue": 30.80,
    "fifthValue": 0.0
}

所以我实际上只会将下面的响应传回给调用者:

 {
    "firstValue": 0.2000,
    "secondValue": 30.80,
    "fourthValue": 30.80,
}

我看到答案指向我在我的 Web api 中使用 App_Start,但我使用的是没有应用启动的 Kestrel - 这是由 Service Fabric 托管的

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new[]
    {
        new ServiceInstanceListener(
            serviceContext =>
                new KestrelCommunicationListener(
                    serviceContext,
                    (url, listener) =>
                    {
                        ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

                        return new WebHostBuilder()
                            .UseKestrel(options => { options.Listen(IPAddress.Any, 8081); })
                            .ConfigureServices(
                                services => services
                                    .AddSingleton(serviceContext)
                                    .AddSingleton(new ConfigSettings(serviceContext))
                                    .AddSingleton(new HttpClient())
                                    .AddSingleton(new FabricClient()))
                            .UseContentRoot(Directory.GetCurrentDirectory())
                            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                            .UseStartup<Startup>()
                            .UseSerilog(_log, true)
                            .UseUrls(url)
                            .Build();
                    }))
    };
}

【问题讨论】:

  • 在使用.Where(x =&gt; x.Value != 0)返回数据之前查询数据时,您似乎应该能够做到这一点
  • 我不想那样做,因为这是一个具有大量属性的对象,这将是一个巨大的 where 子句!
  • 我明白了。在这种情况下,您可能会发现 newtonsoft 的条件序列化很有趣:newtonsoft.com/json/help/html/ConditionalProperties.htm 尽管我相信您仍然必须定义要以一种或另一种方式有条件地排除哪些属性。我很想看看是否有人有更优雅的方式来实现这一目标。希望这会有所帮助
  • 您使用的是哪个版本的asp.net-mvc?对于 JSON 序列化,早期版本使用 JavaScriptSerializer,如 here,但 ASP.Net Core 使用 Json.NET,如 here。答案会因序列化程序而异。
  • 我正在使用 ASPNet 核心 - 我从运行 Web API 的服务结构主机内部运行它 - 我在服务中有包 Microsoft.AspNetCore.Mvc

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


【解决方案1】:

这超级简单。只需将 DefaultValueHandling 的值指定为 Ignore

正如该链接中的描述所说:

在序列化对象时忽略成员值与成员默认值相同的成员,以便不将其写入 JSON。此选项将忽略所有默认值(例如,null 表示对象和可空类型;0 表示整数、小数和浮点数;false 表示布尔值)。可以通过在属性上放置 DefaultValueAttribute 来更改忽略的默认值。

【讨论】:

  • 请查看现在添加到我的问题中的启动代码,如何将其集成到那里?没有注册方法
  • 我设法在某个地方运行此代码,我知道它正在被击中,因为我还将 JSON 设置为漂亮的打印。我已将 DefaultValue(0) 置于我的属性之上,但它们仍在输出?
【解决方案2】:

正如Kit 建议的那样,您可以使用DefaultValueHandling 行为。

此外,您始终可以自定义自己的ContractResolver 来解决此类问题。这是使用自定义ContractResolver 忽略默认值的版本:

public class IgnoreZeroContractResolver : DefaultContractResolver
{
    public IgnoreZeroContractResolver( ){ }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        property.ShouldSerialize = instance => {
            var shouldSerialize = true;  // indicate should we serialize this property

            var type = instance.GetType();
            var pi = type.GetProperty(property.PropertyName);  
            var pv = pi.GetValue(instance);
            var pvType = pv.GetType();

            // if current value equals the default values , ignore this property 
            if (pv.GetType().IsValueType){
                var defaultValue = Activator.CreateInstance(pvType);  
                if (pv.Equals(defaultValue)) { shouldSerialize = false; } 
            }
            return shouldSerialize;
        };

        return property;
    }

}

现在您可以将您的 resover 设置为ContractResolver

public void ConfigureServices(IServiceCollection services)
{

    // ...
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddJsonOptions(o =>{
           o.SerializerSettings.ContractResolver =new IgnoreZeroContractResolver();
        });

    // ...

}

测试用例:

var x = new {
    FirstValue =0.2000,
    SecondValue= 30.80,
    ThirdValue= 0.0,
    FourthValue= 30.80,
    FifthValue= 0.0,        // double 0
    SixValue= 0             // int 0
};
return new JsonResult(x);

响应将是:

{"FirstValue":0.2,"SecondValue":30.8,"FourthValue":30.8}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多