Web API在运行时对属性进行条件序列化

我正在寻找在ASP.Net中使用WebAPI构建API。

我要求在RunTime而不是Compile Time根据某些自定义逻辑有条件地从XML或JSON中排除属性

我必须从响应中删除xml或json,仅包含null或空值的标记并不好。

我尝试了各种方法,但我似乎无法开始工作。

我尝试了以下内容

从这里 委派处理程序

 public class ResponseDataFilterHandler : DelegatingHandler { protected override System.Threading.Tasks.Task 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; }); } } 

当然我可以在这里找空属性,但它们仍然出现在响应中。

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 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。

我有一个想法,我可以动态编译具有所需属性的特定类,然后使用DataContractSurrogate将原始实例与我的新动态编译类的实例交换 – 但我不喜欢它。

我试过看过DataContractSerializer但它是密封的,所以我无法从中得到它 – 我也希望反编译它并进行一些更改但是它再次使用内部类,如DataContract – 我觉得我需要挂钩序列化但我不喜欢不知道怎么样?

您应该使用Json.NET并编写自己的转换器

 public class MyJsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { writer.WriteStartArray(); // write your object here based on your custom logic writer.WriteRawValue(value); writer.WriteEndArray(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } public override bool CanConvert(Type objectType) { return true; } } 

您可以像这样使用自定义转换器

 string json = JsonConvert.SerializeObject(SomeObject, new MyJsonConverter()); 

然后,为了避免为Json和XML编写自定义Converter,您可以将Json转换为XML

 XmlDocument doc = JsonConvert.DeserializeXmlNode(json); 

好吧,我设法使用我已经完成的一些工作,加上这里的一些建议,我也偶然发现了这个

首先,我们首先将DelegatingHandler添加到管道中。

 config.MessageHandlers.Add(new ResponseDataFilterHandler()); 

而class级本身

 public class ResponseDataFilterHandler : DelegatingHandler { protected override System.Threading.Tasks.Task 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; }); } } 

然后我们有一个帮助器类方法来获取新的序列化字符串(这不是prod代码; 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。

只需像这样指定EmitDefaultValue = false

 [DataContract] public class MyClass { [DataMember] public int Id { get; set; } [DataMember(EmitDefaultValue = false)] public string Name { get; set; } } 

有了它,当Name为null时,它将不会显示在XML / JSON中。

如果要动态清空特定属性,可以提供这样的方法。

 [OnSerializing] void OnSerializing(StreamingContext context) { if(someConditionIsMet) this.Name = null; }