HttpResponseMessage序列化为xml

时间:2020-02-12 14:05:58

标签: c# xml rest serialization

在我们的应用程序中,我们具有一个REST-Api,其中包含多个控制器,例如UsersControllerUserGroupsController等。每个REST-Endpoint上的所有调用(获取,放置,推送,删除)始终返回HttpResponseMessage,该对象始终是以下类型的对象:

public class ComRestResult<T> where T : class
{
   public T Data { get; set; }

   public ValidationItem[] ValidationItems { get; set; }
}

ValidationItem类看起来像:

[DataContract]
[Serializable]
public class ValidationItem
{
   [DataMember]
   public string[] ErrorParameters { get; set; }

   [DataMember]
   public ValidationSeverity Severity { get; set; }

   private ValidationId validationId;

   [IgnoreDataMember]
   [XmlIgnore]
   public ValidationId ValidationId
   {
      get { return validationId; }
      set
      {
         validationId = value;
         if(validationId != ValidationId.UnresolvedError)
         {
            legacyValidationId = validationId.ToString();
         }
      }
   }

   private string legacyValidationId;

   [DataMember(Name = "ValidationId")]
   [XmlElement("ValidationId")]
   public string LegacyValidationId
   {
      get { return legacyValidationId; }
      set
      {
         legacyValidationId = value;
         validationId = ValidationId.UnresolvedError;
         ValidationId parsedValidationId;
         if(!string.IsNullOrEmpty(legacyValidationId) && Enum.TryParse(legacyValidationId, out parsedValidationId))
         {
            validationId = parsedValidationId;
         }
      }

ValidationIdSeverity是枚举。

UsersController的Get-Method例如:

[HttpGet]
[Route("")] 
public HttpResponseMessage Get()
{
    RequestHandler handler = new RequestHandler(Request);
    HttpResponseMessage responseMessage = handler.ProcessRequest<User[]>(PersonsAccess.GetAllPersons);
    return responseMessage;
}

RequestHandler构建所需的HttpResponseMessage,并在其ProcessRequest-Method中使用Func<object, T>

HttpResponseMessage是在ProcessRequest-Method内部用以下行创建的:

HttpResponseMessage httpResponseMessage = request.CreateResponse(httpStatusCode, restResult);

一切都很好。

如果我查看json中的响应,则它看起来像:

{"ValidationItems":[{"ValidationId":"UserIsNew","ErrorParameters":["foo","bar"],"Severity":0,}],"Data":[{"UserId":"ABC123","UserName":"John Smith","IsNew":true},{"UserId":"XYZ789","UserName":"Raimond Test","IsNew":true}]}

这看起来不错。现在,如果我将响应视为xml,则看起来像:

<ComRestResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Data xmlns:d2p1="http://schemas.datacontract.org/2004/07/Comp.Rest.Data.Persons">
    <d2p1:User>
      <d2p1:UserId>ABC123</d2p1:UserId>
      <d2p1:UserName>John Smith</d2p1:UserName>
      <d2p1:IsNew>true</d2p1:IsNew>
    </d2p1:User>
    <d2p1:User>
      <d2p1:UserId>XYZ789</d2p1:UserId>
      <d2p1:UserName>Raimond Test</d2p1:UserName>
      <d2p1:IsNew>true</d2p1:IsNew>
    </d2p1:User>
  </Data>
  <ValidationItems xmlns:d2p1="http://schemas.datacontract.org/2004/07/Comp.BaseInterface.Validation">
    <d2p1:ValidationItem>
      <d2p1:ValidationId>UserIsNew</d2p1:ValidationId>
      <d2p1:ErrorParameters xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <d4p1:string>foo</d4p1:string>
        <d4p1:string>bar</d4p1:string>
      </d2p1:ErrorParameters>
      <d2p1:Severity>Information</d2p1:Severity>
    </d2p1:ValidationItem>
  </ValidationItems>
</ComRestResult>

这看起来不好。尽管所有信息都存在,但xml命名空间存在问题。 d2p1和所有其他

如果我在[DataContract]类上应用[DataMember]User属性,例如:

[DataContract(Name = "User", Namespace = "")]
public class User
{
    [DataMember(Name = "UserId")]
    public string UserId { get; set; }
    [DataMember(Name = "UserName")]
    public string UserName { get; set; }
    [DataMember(Name = "IsNew")]
    public bool IsNew { get; set; }
}

用户的response-xml如下:

<Data>
 <User>
  <IsNew>true</IsNew>
  <UserId>ABC123</UserId>
  <UserName>John Smith</UserName>
 </User>
 <User>
  <IsNew>true</IsNew>
  <UserId>XYZ789</UserId>
  <UserName>Raimond Test</UserName>
 </User>
</Data>

这就是我们所需要的。但是我们是否真的需要在每个类上应用属性,或者是否有可能在序列化时停用(或取消激活)名称空间?

另一个问题是string[]类中的ValidationItem。目前,它被序列化为:

<d2p1:ErrorParameters xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <d4p1:string>foo</d4p1:string>
    <d4p1:string>bar</d4p1:string>
</d2p1:ErrorParameters>

我知道我可以将string[]替换为以下类:

[CollectionDataContract(ItemName = "value", Namespace = "")]
public class StringArray : List<string>
{
}

但是不幸的是,此类很老,经常使用(约4000个引用),并且也用于SOAP序列化。因此,我们不能轻易更改它。

我们还需要类似不带名称空间的xml通用序列化。

1 个答案:

答案 0 :(得分:0)

我自己解决了。

根据以下文章,可以使用XmlSerializer代替DataContractSerializer。这样就可以了。

https://docs.microsoft.com/de-de/aspnet/web-api/overview/formats-and-model-binding/json-and-xml-serialization#xml_media_type_formatter