如何在 POST 正文中为 asp.net WebAPI POST 路由格式化 XML

Posted

技术标签:

【中文标题】如何在 POST 正文中为 asp.net WebAPI POST 路由格式化 XML【英文标题】:How to format XML in POST body for an asp.net WebAPI POST route 【发布时间】:2019-09-15 11:54:25 【问题描述】:

我有一个 asp.net WebAPI RESTful 服务,其中有一个用于 GPS 位置的 POST 端点。

服务器控制器有以下路由:

public HttpResponseMessage PostGpsPositions(GpsPositionsModel positions)

body类如下:

 public class GpsPositionsModel 
  
    [Required]
    public int SenderId  get; set; 
 
    [Required]
    public List<GPSData> Positions  get; set;  
 
 
  public class GPSData 
         
    [Required]
    public double X  get; set; 
   
    [Required]
    public double Y  get; set; 
   
    [Required]
    public double Z  get; set;     
  

我一直只使用json,但有人问我是否可以将正文提交到XML

通过包含Content-Type:"application/xml" 标头,这似乎应该是可能的。

我原以为格式如下所示:

    <?xml version="1.0"?>
    <GpsPositionsModel>
      <SenderId>1</SenderId>
      <Positions>
        <GPSData>
            <x>1.1</x>
            <y>1.1</y>
            <z>1.1</z>
        </GPSData>    
      </Positions>
    </GpsPositionsModel>

但这只是不起作用,我回复400 Bad Request

我在服务器上有一个验证过滤器:

ValidationFilterAttribute : ActionFilterAttribute

OnActionExecuting 中我可以看到它确实有 XML 内容标头,但模型状态为 false:

那么,我的问题是这里的 XML 应该如何格式化?我是否需要在结构中的某处使用ArrayOf,如果需要,如何将其应用于我发送的列表?

更新

添加了 cmets 中建议的属性。

所以我有服务器端:

    namespace Models.Common
    
      [DataContract(Namespace = "http://mynamespace.com")]
      public class GpsPositionsModel
      
        [DataMember]
        [Required]
        public int SenderId  get; set; 

        [DataMember]
        [Required]
        public List<GPSData> Positions  get; set; 
      

      [DataContract(Namespace = "http://mynamespace.com")]
      public class GPSData
      
        [DataMember]
        [Required]
        public double X  get; set; 

        [DataMember]
        [Required]
        public double Y  get; set; 

        [DataMember]
        [Required]
        public double Z  get; set; 
      
    

控制器:

    [HttpPost]
    [Route("gps")]
    public HttpResponseMessage SubmitGpsData([FromBody]GpsPositionsModel gpsData)
          
      return new HttpResponseMessage();
    

使用 Postman,我调用 using:

    <?xml version="1.0"?>
    <GpsPositionsModel xmlns="http://schemas.datacontract.org/2004/07/http://mynamespace.com">
      <SenderId>1</SenderId>
      <Positions>
           <GPSData xmlns="http://schemas.datacontract.org/2004/07/http://mynamespace.com">
                        <x>1.1</x>
                        <y>1.1</y>
                        <z>1.1</z>                          
           </GPSData>
        <GPSData xmlns="http://schemas.datacontract.org/2004/07/http://mynamespace.com">
                        <x>1.1</x>
                        <y>1.1</y>
                        <z>1.1</z>                          
           </GPSData>
      </Positions>
    </GpsPositionsModel>

在 Postman 控制台中我得到:

我用的是WebAPI2,asp.net全框架

    <package id="Microsoft.AspNet.Cors" version="5.2.4" targetFramework="net47" />
      <package id="Microsoft.AspNet.WebApi" version="5.2.4" targetFramework="net47" />
      <package id="Microsoft.AspNet.WebApi.Client" version="5.2.4" targetFramework="net47" />
      <package id="Microsoft.AspNet.WebApi.Core" version="5.2.4" targetFramework="net47" />
      <package id="Microsoft.AspNet.WebApi.Cors" version="5.2.4" targetFramework="net47" />
      <package id="Microsoft.AspNet.WebApi.Owin" version="5.2.4" targetFramework="net47" />
      <package id="Microsoft.AspNet.WebApi.Tracing" version="5.2.4" targetFramework="net47" />
      <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.4" targetFramework="net47" />
      

【问题讨论】:

【参考方案1】:

尝试在action方法的参数中添加[FromBody]属性

public HttpResponseMessage PostGpsPositions([FromBody]GpsPositionsModel positions)

还有,对于模型

在类名上添加[DataContract],在模型中的每个属性上添加[DataMember]

【讨论】:

谢谢@akg179,但不幸的是这并没有什么不同,上面看起来更像你为WCF所做的,但我还是尝试了。【参考方案2】:

对于发布 xml,您需要以以下格式指定 xmlns: http://schemas.datacontract.org/2004/07/Clr.Namespace

因此,在您的情况下,您需要像这样发布 xml:

<GpsPositionsModel xmlns="http://schemas.datacontract.org/2004/07/namespance containing GpsPositionsModel class">
    <Positions>
        <GPSData>
            <X>1</X>
            <Y>1</Y>
            <Z>2</Z>
        </GPSData>
    </Positions>
    <SenderId>1</SenderId>
    </GpsPositionsModel>

如果 GpsPositionsModel 类不在任何命名空间内,您可以将其留空,例如: xmlns="http://schemas.datacontract.org/2004/07/

参考:https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-names

【讨论】:

感谢@Mohsin,但不幸的是这并没有什么区别,上面看起来更像你为 WCF 所做的,但我还是尝试了(包括命名空间) 您可以与命名空间共享更新的 xml 架构吗?我最终测试了它,它有效。我假设您使用的是 Asp.WebApi 2。另外,您使用的是哪个 .Net 框架?

以上是关于如何在 POST 正文中为 asp.net WebAPI POST 路由格式化 XML的主要内容,如果未能解决你的问题,请参考以下文章