Serialization 基于查询参数的条件成员序列化?

Serialization 基于查询参数的条件成员序列化?,serialization,asp.net-web-api,json.net,Serialization,Asp.net Web Api,Json.net,我希望根据查询参数与属性的匹配来控制将模型中的哪些属性序列化到WebAPI2 JSON响应。我主要想这样做是为了减少GET上的带宽,而不会导致ViewModel类的激增。例如: GET /books/1?format=summary public class Book { [SerializeFormat("summary")] public int Id { get; set; } [SerializeFormat("summary")] public st

我希望根据查询参数与属性的匹配来控制将模型中的哪些属性序列化到WebAPI2 JSON响应。我主要想这样做是为了减少GET上的带宽,而不会导致ViewModel类的激增。例如:

GET /books/1?format=summary

public class Book
{
    [SerializeFormat("summary")]
    public int Id { get; set; }

    [SerializeFormat("summary")]
    public string Title { get; set; }

    public string Contents { get; set; }
}

为了自己做到这一点,我可以从实现
ISerializable
的自定义基派生所有模型类。在
ISerializable.GetObjectData()
中,遍历所有属性,检查属性。不确定在这个想法上的表现


如果此解决方案已作为包存在,则不想重新创建此解决方案。

一种可能是引入可应用于属性和字段的自定义
JsonConditionalIncludeAttribute

[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
public class JsonConditionalIncludeAttribute : System.Attribute
{
    public JsonConditionalIncludeAttribute(string filterName)
    {
        this.FilterName = filterName;
    }

    public string FilterName { get; private set; }
}
接下来,对至少应用了一个
[JsonConditionalInclude]
的属性进行子类化、重写并返回null,这些属性都与提供给协定解析程序的a筛选器不匹配:

public class JsonConditionalIncludeContractResolver : DefaultContractResolver
{
    public JsonConditionalIncludeContractResolver(string filterName)
    {
        this.FilterName = filterName;
    }

    public string FilterName { get; set; }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        // Properties without JsonConditionalIncludeAttribute applied are serialized unconditionally.
        // Properties with JsonConditionalIncludeAttribute are serialized only if one of the attributes
        // has a matching filter name.
        var attrs = property.AttributeProvider.GetAttributes(typeof(JsonConditionalIncludeAttribute), true);
        if (attrs.Count > 0 && !attrs.Cast<JsonConditionalIncludeAttribute>().Any(a => a.FilterName == FilterName))
            return null;
        return property;
    }
}

契约解析程序将应用于所有被序列化的类,而不仅仅是根类,它看起来是您想要的。

可能会有所帮助。在JSON被序列化时,查询参数是否可用,以便可以选择自定义的
JsonSerializerSettings
?是的,然后查询参数可用。不过,我看不出
JsonSerializerSettings
有什么帮助。请你把你的想法再详细一点好吗?要让条件属性序列化完成这项工作需要走很长的路,包括复制类上的每个属性。这似乎意味着回应模型内容,而不是请求内容。我喜欢你的想法。您的属性是可选的,这很好。为了对我来说是理想的,它还需要处理一个默认的过滤器状态,可能是一个空字符串,以便设置属性,并且显式匹配场景之一是当没有应用“格式”时。实际上,我必须将CamelCasePropertyNamesContractResolver子类化,然后我可以在整个站点的WebApiConfig中应用它。
public class JsonConditionalIncludeContractResolver : DefaultContractResolver
{
    public JsonConditionalIncludeContractResolver(string filterName)
    {
        this.FilterName = filterName;
    }

    public string FilterName { get; set; }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        // Properties without JsonConditionalIncludeAttribute applied are serialized unconditionally.
        // Properties with JsonConditionalIncludeAttribute are serialized only if one of the attributes
        // has a matching filter name.
        var attrs = property.AttributeProvider.GetAttributes(typeof(JsonConditionalIncludeAttribute), true);
        if (attrs.Count > 0 && !attrs.Cast<JsonConditionalIncludeAttribute>().Any(a => a.FilterName == FilterName))
            return null;
        return property;
    }
}
public class TestClass
{
    public string Property1 { get; set; }

    [JsonConditionalInclude("summary")]
    [JsonConditionalInclude("title")]
    public string Property2 { get; set; }

    [JsonConditionalInclude("summary")]
    public string Property3 { get; set; }

    [JsonConditionalInclude("title")]
    [JsonConditionalInclude("citation")]
    public string Property4 { get; set; }

    [JsonConditionalInclude("citation")]
    public string Field1;

    public static void Test()
    {
        var test = new TestClass { Property1 = "a", Property2 = "b", Property3 = "c", Property4 = "d", Field1 = "e" };
        Test(test, "summary"); // Prints "a", "b" and "c"
        Test(test, "title");   // Prints "a", "b" and "d".
        Test(test, "citation");// Prints "e", "a" and "d"
        Test(test, null);      // Prints "e", "a", "b", "c" and "d".
    }

    public static string Test(TestClass test, string webRequestFormat)
    {
        var settings = new JsonSerializerSettings { ContractResolver = new JsonConditionalIncludeContractResolver(webRequestFormat) };

        var json = JsonConvert.SerializeObject(test, Formatting.Indented, settings);

        Debug.WriteLine(json);
        return json;
    }
}