Newtonsoft.Json动态过滤属性
Newtonsoft.Json动态过滤属性
接口写的多了,会发现很多的问题。同一个dto,不同的action返回的字段个数不一样。往往开发人员因为懒或者各种原因一股脑的全返回,会浪费很多流量且用户体验很差。
当然也会有负责一些的,根据不同的action定义不同的output类。毫无疑问这很麻烦,浪费开发时间。博主本人也是深受其扰,之前看到一篇博文 Newtonsoft.Json高级用法 里面有说到动态决定是属性是否序列化。深得我心于是上手试了一下。博文里的代码很不完善
本人的项目返回类型均为 OutputModel(Status、Message、Data(数据))。把output丢给json序列化的时候,拿到的只有属性只有Status、Message、Data。而我们要针对的是Data类型的属性。本人进行改造后。由于过滤的属性清单与OutPutModel的又不一致(因为我们要序列化的是output,我们传入的是data里的属性),无法进行序列化,后面又实验了一下效率如何。如下图,5w次循环竟然与之前差了71倍之多。于是博主准备自己动手去写一个

自己动手
动手之前应该思考一下,我们需要的是什么效果。
- 根据传入数组动态决定哪些属性需要初始化
 - 针对OutPutModel的处理
 - 效率的高效,至少要直接序列化的差距不会太大
 
我想要用法是在序列化的时候传入一个字符串数组(也就是需要序列化属性),这里对思路进行梳理一下
return Json(output,new []{"Name","Age"})
- 使用反射,拿到output.Data的Type
 - 使用type创建一个实例,循环type的GetProperties。判断property是否在传入的字符串数组中
 - 使用property.GetValue获取到属性值,然后再SetValue到创建的实例中
 - 把实例赋值给output.Data
 
很简单,就是对output的data进行一次替换,下面代码很完美的可以解决问题。
private static void Filtered(OutputModel output, string[] param)
{
Type type = null;
if (param == null || param.Length <= 0)
{
return;
}
type = null; if (output.Data == null) return;
type = output.Data.GetType();
object result = Activator.CreateInstance(type);
foreach (var property in type.GetProperties())
{
if (!((IList)param).Contains(property.Name)) continue;
object value = property.GetValue(output.Data, null);
property.SetValue(result, value);
}
output.Data = result;
}
细心的同学可能会发现上面的少了针对List的处理
Type type = null;
if (output.Data is IList)
{
var dataList = output.Data as IList;
if (dataList.Count > 0)
{
type = dataList[0].GetType();
var result = Activator.CreateInstance(output.Data.GetType()) as IList; foreach (var temp in dataList)
{
var instance = Activator.CreateInstance(type);
foreach (var property in type.GetProperties())
{
if (!((IList) param).Contains(property.Name)) continue;
object value = property.GetValue(temp, null);
property.SetValue(instance, value);
}
result.Add(instance);
}
output.Data = result;
}
}
上面的一些代码运行起来效率比原生5000次只低不50-100ms,完全可以接受。但是会发现序列化后我们不想要被序列化的属性值变成了null。研究了一下问题出在
var instance = Activator.CreateInstance(type); 这里,因为我们创建的还是那个类嘛。。属性也无法被砍掉。想了想这里可以用动态类型去实现。
type = obj.GetType();
var result = new ExpandoObject() as IDictionary<string, Object>;
foreach (var property in type.GetProperties())
{
if (retain)
{
if (!((IList)props).Contains(property.Name.ToLower())) continue;
}
else
{
if (((IList)props).Contains(property.Name.ToLower())) continue;
}
object value = property.GetValue(obj, null);
result.Add(property.Name, value); }
obj = result;
实验了一下对效果非常满意,另外一个有意思的事情是效率竟然比原生要快上一倍

这张图直接进行序列化

这张图是用过滤了属性

下面除上完整的代码,有需要的同学可以进行使用
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using Tool.Response; namespace MvcCustommade
{
public class LimitPropsContractResolver
{ private static object Filtered(object obj, string[] props, bool retain)
{ if (obj == null)
return null;
Type type = null;
if (obj is IList)
{
var dataList = obj as IList;
if (dataList.Count > 0)
{
type = dataList[0].GetType();
List<IDictionary<string, object>> result = new List<IDictionary<string, object>>(); foreach (var temp in dataList)
{
var instance = new ExpandoObject() as IDictionary<string, Object>;
foreach (var property in type.GetProperties())
{
if (retain)
{
if (!((IList)props).Contains(property.Name.ToLower())) continue;
}
else
{
if (((IList)props).Contains(property.Name)) continue;
} object value = property.GetValue(temp, null);
instance.Add(property.Name, value);
}
result.Add(instance);
}
obj = result;
}
}
else
{ type = obj.GetType();
var result = new ExpandoObject() as IDictionary<string, Object>;
foreach (var property in type.GetProperties())
{
if (retain)
{
if (!((IList)props).Contains(property.Name.ToLower())) continue;
}
else
{
if (((IList)props).Contains(property.Name.ToLower())) continue;
}
object value = property.GetValue(obj, null);
result.Add(property.Name, value); }
obj = result;
} return obj;
} /// <summary>
/// 过滤无用的属性
/// </summary>
/// <param name="output">返回的数据</param>
/// <param name="props">过滤的属性数组</param>
/// <param name="retain">过滤的数组是包含还是不包含</param>
public static object CreateProperties(object output, string[] props, bool retain)
{
if (props == null || props.Length <= 0)
{
return output;
}
if (output == null)
{
return null;
}
for (int i = 0; i < props.Length; i++)
{
props[i] = props[i].ToLower();
}
if (output is OutputModel)
{
var outputModel = output as OutputModel;
if (outputModel.Data == null)
{
return outputModel;
}
outputModel.Data = Filtered(outputModel.Data, props, retain);
return outputModel; #region 初始版 //Type type = null; //if (outputModle.Data is IList)
//{
// var ss = outputModle.Data as IList;
// if (ss.Count > 0)
// {
// type = ss[0].GetType();
// List<IDictionary<string, object>> result = new List<IDictionary<string, object>>(); // foreach (var temp in ss)
// {
// var instance = new ExpandoObject() as IDictionary<string, Object>;
// foreach (var property in type.GetProperties())
// {
// if (retain)
// {
// if (!((IList)props).Contains(property.Name)) continue;
// }
// else
// {
// if (((IList)props).Contains(property.Name)) continue;
// } // object value = property.GetValue(temp, null);
// instance.Add(property.Name, value);
// }
// result.Add(instance);
// }
// outputModle.Data = result;
// }
//}
//else
//{
// if (outputModle.Data == null) return;
// type = outputModle.Data.GetType();
// var result = new ExpandoObject() as IDictionary<string, Object>;
// foreach (var property in type.GetProperties())
// {
// if (retain)
// {
// if (!((IList)props).Contains(property.Name)) continue;
// }
// else
// {
// if (((IList)props).Contains(property.Name)) continue;
// }
// object value = property.GetValue(outputModle.Data, null);
// result.Add(property.Name, value); // }
// outputModle.Data = result;
//} #endregion
}
else
{
output = Filtered(output, props, retain);
return output;
} }
}
}
Newtonsoft.Json动态过滤属性的更多相关文章
- Newtonsoft.Json高级用法    1.忽略某些属性      2.默认值的处理      3.空值的处理      4.支持非公共成员      5.日期处理      6.自定义序列化的字段名称
		
手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...
 - EF 实体+ Newtonsoft.Json 输出JSON 时动态忽略属性的解决方法
		
最近的项目采用的是 ASP.NET mvc 4.0 + entity framework 5.0 ,后台以JSON形式抛出数据是借助于Newtonsoft.Json , 要想忽略的属性前面添加特性 ...
 - Newtonsoft.Json输出JSON 时动态忽略属性
		
一,前言 最近做项目采用Json形式和其他客户端交互,借助于Newtonsoft.Json . 由于业务场景不同,输出的Json内容也不同.要想忽略的属性,可以借助Newtonsoft.Json的特性 ...
 - Newtonsoft.Json输出Json时动态忽略属性
		
一,前言 最近做项目采用Json形式和其他客户端交互,借助于Newtonsoft.Json . 由于业务场景不同,输出的Json内容也不同.要想忽略的属性,可以借助Newtonsoft.Json的特性 ...
 - c#使用 Newtonsoft.Json 将entity转json时,忽略为null的属性
		
c#使用 Newtonsoft.Json 将entity转json时,忽略为null的属性,直接在属性上加下面的特性 [JsonProperty(NullValueHandling=NullValue ...
 - C# Newtonsoft.Json JObject移除属性,在序列化时忽略
		
原文 C# Newtonsoft.Json JObject移除属性,在序列化时忽略 一.针对 单个 对象移除属性,序列化时忽略处理 JObject实例的 Remove() 方法,可以在 指定序列化时移 ...
 - Newtonsoft.Json 指定某个属性使用特定的时间格式
		
Newtonsoft.Json 指定某个属性使用特定的时间格式 Intro Newtonsoft.Json 是 .NET 下最受欢迎 JSON 操作库,原为 JSON.Net 后改名为 Newtons ...
 - Newtonsoft.Json.Linq.JObject 遍历验证每个属性内容
		
业务需求,拦截器验证每个请求inputstream(实际是application/json流)的数据,但是json反序列化实体格式不同. var req = filterContext.Request ...
 - 【Newtonsoft.Json】json序列化小驼峰格式(属性名首字母小写)
		
我是一名 ASP.NET 程序员,专注于 B/S 项目开发.累计文章阅读量超过一千万,我的博客主页地址:https://www.itsvse.com/blog_xzz.html 只需要设置JsonSe ...
 
随机推荐
- 如何让oracle的select强制走索引
			
大多数情况下,oracle数据库内置的查询优化策略还是很成功的,但偶尔也有犯2的时候,即使有索引,也会做全表扫描,可以参考以下语句的写法,强制让select语句使用索引 CREATE OR REPLA ...
 - canvas中的碰撞检测笔记
			
用 canvas 做小游戏或者特效,碰撞检测是少不了的.本文将会涉及普通的碰撞检测,以及像素级的碰撞检测.(本文的碰撞检测均以矩形为例) 普通碰撞检测 普通的矩形碰撞检测比较简单.即已知两个矩形的各顶 ...
 - 基于PHP的AJAX学习笔记(教程)
			
本文转载自:http://www.softeng.cn/?p=107 这是本人在学习ajax过程所做的笔记,通过本笔记的学习,可以完成ajax的快速入门.本笔记前端分别使用原生态的javascript ...
 - WebService的两种方式SOAP和REST比较 (转)
			
我的读后感:由于第一次接触WebService,对于很多概念不太理解,尤其是看到各个OpenAPI的不同提供方式时,更加疑惑.如google map api采用了AJAX方式,通过javascript ...
 - JavaScript 总结几个提高性能知识点
			
前段时间花时间看了大半的<High Performance JavaScript>这本书啊,然后就开始忙项目了,庆幸最忙的一周已经熬过去了.由于空不出时间,这个月写的学习笔记也不多,忙完最 ...
 - JavaScript学习笔记-自定义滚动条
			
这是一个基本实现思路,如果有新手和我一样没什么事,喜欢瞎研究话,可以参考下. 一.Html <div class="scroll_con"> <div class ...
 - AVL树插入操作实现
			
为了提高二插排序树的性能,规定树中的每个节点的左子树和右子树高度差的绝对值不能大于1.为了满足上面的要求需要在插入完成后对树进行调整.下面介绍各个调整方式. 右单旋转 如下图所示,节点A的平衡因子(左 ...
 - arguments.callee 调用自身 caller,callee,apply and call
			
一.Arguments该对象代表正在执行的函数和调用他的函数的参数.[function.]arguments[n]参数function :选项.当前正在执行的 Function 对象的名字.n :选项 ...
 - js中如何去获取外部css样式
			
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
 - OAuth in One Picture
			
近年来,OAuth在各种开放平台的引领下变得非常流行,上图是OAuth协议认证的全过程,图本身已经比较详细,这里不再赘述. 从上图中可以看出,OAuth协议中有三个角色: User, Consumer ...