在运行时性能的Web API序列化条件 [英] Web API Conditional Serialization of properties at runtime
问题描述
我期待在建设ASP.Net使用的WebAPI的API。
I am looking at building an API using WebAPI in ASP.Net.
我有一个要求,基于在 运行
,而不是编译时的一些自定义逻辑有条件地排除在XML或JSON属性
。
I have a requirement to conditionally exclude properties from the XML or JSON based on some custom logic at RunTime
and not Compile Time
.
我不得不删除从响应的XML或JSON,它是没有好只是包括空或空值的变量。
I have to remove the xml or json from the response, it is no good just including the tags with a null or empty value.
我已经试过各种方法,但没有去上班。
I have tried various approaches, none of which I seem to be able to get to work.
我曾尝试以下
委托处理程序 from这里
public class ResponseDataFilterHandler : DelegatingHandler
{
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
//Manipulate content here
var content = response.Content as ObjectContent;
if (content != null && content.Value != null)
{
}
//Or replace the content
//response.Content = new ObjectContent(typeof(object), new object(), new MyFormatter());
return response;
});
}
}
当然,我可以在这里空的属性,但他们仍然会出现在响应。
Sure I can null properties out here, but they still appear in the response.
DataContractSurrogate 相似这个
public class MySurrogate: IDataContractSurrogate
{
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
return null;
}
public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
return null;
}
public Type GetDataContractType(Type type)
{
return null;
}
public object GetDeserializedObject(object obj, Type targetType)
{
return null;
}
public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes)
{
}
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj == null) return null;
var type = obj.GetType();
type.GetProperties().ToList()
.ForEach(prop =>
{
try
{
var attr = prop.GetCustomAttributes(typeof(ConditionalDataMemberAttribute), false);
if (attr.Any())
{
var proptype = prop.PropertyType;
//Set the property value to its default value
prop.GetSetMethod().Invoke(obj,
new[] { proptype.IsValueType ? Activator.CreateInstance(proptype) : null });
}
}
catch { }
});
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
return null;
}
public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
return null;
}
}
同样,我可以只空的属性了,我不能删除从输出的XML或JSON。
Again, I can just null the properties out, I cannot remove the xml or json from the output.
我有一个想法,我可以动态编译特定类与所需的属性然后使用DataContractSurrogate与我的新的动态编译的类的实例换出原来的实例 - 但我不喜欢它。
I have an idea where I can dynamically compile a specific class with the required attributes then use the DataContractSurrogate to swap out the original instance with an instance of my new dynamic compiled class - but I don't like it.
香港专业教育学院试图寻找的DataContractSerializer
,但它是密封的,所以我不能从中获得 - 我也看了反编译,并作出一些改变,但它再次使用了内部类如 DataContract
- 我觉得我需要挂接到序列化,但我不知道如何
Ive tried looking at DataContractSerializer
but it is sealed so I cant derive from it - i've also looked to decompile it and make some changes but again it uses internal classes such as DataContract
- I feel I need to hook into the serialization but I don't know how to ?
推荐答案
好吧,我成功地做到这一点使用了一点什么,我已经做了,再加上一些在这里的建议,我也偶然发现的这个
Okay I managed to do this using a bit of what I had already done, plus some of the suggestions on here, I also stumbled upon this
首先,我们通过增加一个 DelegatingHandler
进入管道开始。
First we start by adding a DelegatingHandler
into the pipeline.
config.MessageHandlers.Add(new ResponseDataFilterHandler());
和类本身
public class ResponseDataFilterHandler : DelegatingHandler
{
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
var content = response.Content as ObjectContent;
if (content != null && content.Value != null)
{
var isJson = response.RequestMessage.GetQueryNameValuePairs().Any(r => r.Key == "json" && r.Value == "true");
response.Content = new StringContent(Helper.GetResponseData(content.Value, isJson));
}
return response;
});
}
}
然后我们有一个辅助类的方法获取新的序列化的字符串(这不是督促code; P)
Then we have a helper class method to get the new serialized string (this is not prod code ;p)
public static class Helper
{
public static string GetResponseData(object root,bool isJson)
{
string json = JsonConvert.SerializeObject(root, new JsonSerializerSettings { ContractResolver = new ShouldSerializeContractResolver()});
if (!isJson)
{
XmlDocument doc = JsonConvert.DeserializeXmlNode(json,"response");
json = doc.OuterXml;
}
return json;
}
}
和最后的 ContractReoslver
public class ShouldSerializeContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = (i) =>
{
//Your logic goes here
var r = !property.PropertyName.StartsWith("block-ref");
return r;
};
return property;
}
}
这一切的根源,通过JSON和皈依为xml如果需要的话,我的测试项目中,我使用一个查询字符串(JSON = TRUE)来指定,如果格式应JSON而不是XML。
this roots everything through Json and the converts to xml if required, for my test project I am using a querystring (json=true) to specify if the format should be json instead of xml.
这篇关于在运行时性能的Web API序列化条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!