运行时属性的 Web API 条件序列化

Ric*_*end 5 c# rest asp.net-web-api

我正在考虑在 ASP.Net 中使用 WebAPI 构建 API。

我需要基于 at和 not 的一些自定义逻辑有条件地从 XML 或 JSON 中排除属性RunTimeCompile Time

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

我尝试了各种方法,但似乎没有一种方法可以开始工作。

我已经尝试了以下

从这里委托处理程序

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


}
Run Code Online (Sandbox Code Playgroud)

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

同样,我可以将属性清空,我无法从输出中删除 xml 或 json。

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

我试过查看,DataContractSerializer但它是密封的,所以我无法从中派生出来 - 我也试图反编译它并进行一些更改,但它再次使用内部类,例如DataContract- 我觉得我需要挂入序列化,但我没有知道怎么 ?

Ric*_*end 3

好吧,我设法使用我已经做过的一些事情以及这里的一些建议来做到这一点,我也偶然发现了这一点

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

config.MessageHandlers.Add(new ResponseDataFilterHandler());
Run Code Online (Sandbox Code Playgroud)

以及班级本身

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;
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我们有一个辅助类方法来获取新的序列化字符串(这不是产品代码;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;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这通过 Json 生成所有内容,并在需要时转换为 xml,对于我的测试项目,我使用查询字符串 (json=true) 来指定格式是否应为 json 而不是 xml。