微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将引用的对象展平为referer上的两个json.net属性?

考虑以下课程:
public class User
{
  public virtual int Id {get;set;}
  public virtual string Name {get;set;}
  public virtual User Superior {get;set;}
}

我的目标是使用newtonsofts json.net将其序列化为json,如下所示:

{
  Id: 101,Name: 'Mithon',SuperiorId: 100,SuperiorName: 'TheMan'
}

我为什么要这样做?因为我想使用Json作为我的DTO而不生成动态对象的中间层.生成DTO应该按惯例动态完成,而不是明确地,imho.我知道有些人可能会强烈不同意这一点,但讨论我的方法除了重点之外.我只想知道是否以及如何做到这一点.

挑战是使用JsonPropertyAttribute作为Superior属性只会产生一个属性作为输出,我需要两个属性.如果我使用JsonObjectAttribute,我将得到一个嵌套属性,我会遇到顶级用户也被弄平的问题.

幸运的是,似乎json.net库中有足够的受保护和/或公共属性方法,我可以扩展一些东西以获得所需的结果.那么问题是我应该从哪些类和方法开始到达我想去的地方?将从DefaultContractResolver派生,并覆盖GetProperties方法是好地方,还是我应该寻找其他地方?

简短的回答是肯定的,那将是适当的起点.这就是我最终的结果(现在):
public class MyContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type,MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type,memberSerialization);

        foreach (var pi in type.GetProperties().Where(pi => typeof (Entity).IsAssignableFrom(pi.DeclaringType) && Attribute.IsDefined((MemberInfo) pi,typeof(IdNameMemberAttribute))))
        {
            properties.Add(CreateReferenceProperty(pi,Reflect.GetProperty<Entity>(e => e.Id)));
            properties.Add(CreateReferenceProperty(pi,Reflect.GetProperty<Entity>(e => e.Name)));
        }

        return properties;
    }

    private JsonProperty CreateReferenceProperty(PropertyInfo reference,PropertyInfo referenceMember)
    {
        var jsonProperty = base.CreateProperty(reference,MemberSerialization.OptOut);
        jsonProperty.PropertyName += referenceMember.Name;
        jsonProperty.ValueProvider = new ReferencedValueProvider(reference,referenceMember);
        jsonProperty.Writable = false;

        return jsonProperty;
    }
}

IdNameMemberAttribute只是一个属性,我用它来注释我要序列化的引用属性.重要的一点是,我不会使用Json.NET识别并用于生成JsonProperty的任何内容对其进行注释.这样我就不会从我的CreateProperties中得到重复的JsonProperty.

或者,我可以从DataMemberAttribute派生并查找,修改和克隆JsonProperty以表示我的Id和Name.

对于我的asp.net web api,我将此MyContractResolver设置为JsonFormatter.SerializerSettings的ContractResolver.

所以这使我得以进行序列化.对于反序列化,我有一个自定义ChangeSet对象,我存储PropertyInfo和对象.在反序列化期间,我确保保留Ids,然后解决来自我的数据存储的问题,在我的情况下使用自定义ActionFilter来访问数据存储会话.

这是我的序列化的本质:

var jsonSource = streamReader.ReadToEnd();
var deserializedobject = JsonConvert.DeserializeObject(jsonSource,type,SerializerSettings);
var changeSet = deserializedobject as PropertyChangeSet;
if (changeSet != null)
{
    var jsonChange = JObject.Parse(jsonSource)["Change"].Cast<JProperty>().ToArray();

    IDictionary<string,int> references = jsonChange.Where(IsReferenceId).ToDictionary(t => t.Name.Substring(0,t.Name.Length - 2),t => t.Value.ToObject<int>());
    changeSet.References = references;

    var properties = jsonChange.Where(jp => !IsReferenceId(jp)).Select(t => t.Name).ToList();
    changeSet.Primitives = properties;
}

而且,我的干净实体和动态序列化的所有血腥细节都被封装,遗憾地在两个地方封装,但由于我不想从序列化程序访问我的数据源,所以无法帮助它.

原文地址:https://www.jb51.cc/json/288528.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐