问题描述
我想控制从我的模特属性是序列化到我WebAPI2 JSON响应的基础上,查询参数匹配的属性。我主要是想做到这一点,以减少带宽而不会导致视图模型类的增殖的GET。例如:
I would like to control which properties from my model are serialized to my WebAPI2 JSON response, based on matching a query parameter to an attribute. I mainly want to do this to reduce bandwidth on GETs without causing a proliferation of ViewModel classes. For example:
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()
,通过所有属性检查属性迭代。不知道这种想法的性能。
To do this myself, I could derive all of my model classes from a custom base implementing ISerializable
. In ISerializable.GetObjectData()
, iterate through all properties inspecting the attributes. Not sure about performance on this idea.
不想重塑这个解决方案,但如果它已经存在作为一个包。
Don't want to reinvent this solution, though if it already exists as a package.
推荐答案
一种可能性是引入一个定制的 JsonConditionalIncludeAttribute
可应用于属性和字段:
One possibility would be to introduce a custom attribute JsonConditionalIncludeAttribute
that can be applied to properties and fields:
[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
,并为具有属性返回null至少有一个 [JsonConditionalInclude]
应用,其中没有一个匹配供应合同解析器的一个过滤器:
Next, subclass DefaultContractResolver
, override CreateProperty
, and return null for properties that have at least one [JsonConditionalInclude]
applied, none of which match the a filter supplied to the contract resolver:
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
等于您的自定义合同解析器,初始化 FILTERNAME
从您的网络请求,例如:
Finally, when serializing your class to JSON, set JsonSerializerSettings.ContractResolver
equal to your custom contract resolver, initializing the FilterName
from your web request, for instance:
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;
}
}
该合同解析器将适用于所有的类被序列化,而不仅仅是根类,它看起来是你想要的。
The contract resolver will apply to all classes being serialized, not just the root class, which looks to be what you want.
这篇关于根据查询参数条件系列化会员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!