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; }
- WebApi,Autofac,System.Web.Http.Filters.ActionFilterAttribute每个请求的实例
- 用于generics类型的ASP.NET Web API模型绑定器
- Web api性能?
- 使用webAPI承载令牌进行SignalR认证
- 图Api – 401未经授权
- entity framework核心:在上一个操作完成之前,在此上下文中启动了第二个操作
- Web Api Request.CreateResponse HttpResponseMessage no intellisense VS2012
- Web API自定义validation,以根据已批准值列表检查字符串
- 装饰ASP.NET Web API IHttpController