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

标签 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 string Title { get; set; }

    public string Contents { get; set; }
}

[SerializeFormat("summary","Id","Title")]
public class Book
{ ... }

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

不想重新发明这个解决方案,尽管它已经作为一个包存在。

最佳答案

一种可能性是引入自定义 attribute可应用于属性和字段的 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; }
}

接下来,子类DefaultContractResolver , 覆盖 CreateProperty ,并为至少应用了一个 [JsonConditionalInclude] 的属性返回 null,这些属性都不匹配提供给契约(Contract)解析器的过滤器:

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.ContractResolver等于您的自定义契约(Contract)解析器,从您的网络请求中初始化 FilterName,例如:

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;
    }
}

契约(Contract)解析器将应用于所有被序列化的类,而不仅仅是根类,这看起来就是您想要的。

关于serialization - 基于查询参数的条件成员序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29713847/

相关文章:

c# - 将c#中的JSON数组反序列化为列表

c++ - 通过套接字发送 boost 序列化时应用程序崩溃

c# - 带有oauth的webapi,撤销 token ?

c# - Json.NET 可以使用 Formatting 序列化流式传输吗?

asp.net-web-api - Json.Net TypeNameHandling.Auto 和 Asp Web Api Controller 给出了意外的行为

.net - 如何在 JSON .NET 上对属性名称强制使用引号

c# - 如何使用 Json.Net 将字典序列化为其父对象的一部分

java - 服务器将序列化重写为 GET,将 hibernate 置于服务器上

c# - 使用 ServiceStack 返回具有特定状态代码的自定义 DTO 的选项有哪些?

c# - WebApi 应用程序 : Error 404. 0,处理程序静态文件