C# 发送 XML 时 AspNet WebApi POST 参数为空

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11142702/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 16:41:46  来源:igfitidea点击:

AspNet WebApi POST parameter is null when sending XML

c#asp.net-web-api

提问by Nick

I have a web api service originally using beta bits which I've rebuilt using the release candidate bits and I'm now having this problem.

我有一个最初使用 beta 位的 web api 服务,我已经使用候选发布位重建了它,我现在遇到了这个问题。

I have a POST action that takes a complex option as the only parameter. When I send the request with the body in json format the object is deserialised as expected, but if I send XML instead the parameter is null.

我有一个 POST 操作,它将复杂选项作为唯一参数。当我以 json 格式发送带有正文的请求时,对象按预期反序列化,但如果我发送 XML,则参数为空。

In the beta I worked around this by disabling model binding as described in Carlos Figueira's blog post Disabling model binding on ASP.NET Web APIs Beta

在测试版中,我通过禁用模型绑定来解决这个问题,如 Carlos Figueira 的博客文章禁用 ASP.NET Web API 上的模型绑定 Beta 中所述

In the RC however they have removed the IRequestContentReadPolicy that this method was implementing.

然而,在 RC 中,他们删除了此方法正在实现的 IRequestContentReadPolicy。

My action:

我的行动:

public List<Models.Payload> Post([FromBody]Models.AimiRequest requestValues)
{
  try
  {
    if (requestValues == null)
    {
      var errorResponse = new HttpResponseMessage();
      errorResponse.StatusCode = HttpStatusCode.NotFound;
      errorResponse.Content = new StringContent("parameter 'request' is null");
      throw new HttpResponseException(errorResponse);
    }
    var metadataParams = new List<KeyValuePair<string, string>>();
    foreach (Models.MetadataQueryParameter param in requestValues.Metadata)
    {
      metadataParams.Add(new KeyValuePair<string, string>(param.Name, param.Value));
    }
    List<Core.Data.Payload> data = _payloadService.FindPayloads(metadataParams, requestValues.ContentType, requestValues.RuleTypes);
    var retVal = AutoMapper.Mapper.Map<List<Core.Data.Payload>, List<Models.Payload>>(data);
    return retVal; // new HttpResponseMessage<List<Models.Payload>>(retVal);
  }
  catch (System.Exception ex)
  {
    _logger.RaiseError(ex);
    throw;
  }
}

My model:

我的型号:

public class AimiRequest
{
  public MetadataQueryParameter[] Metadata { get; set; }
  public string ContentType { get; set; }
  public string RuleTypes { get; set; }
}

public class MetadataQueryParameter
{
  public string Name { get; set; }
  public string Value { get; set; }
}

I'm testing using Fiddler to send requests to the service.

我正在测试使用 Fiddler 向服务发送请求。

This works and returns me the expected results.

这有效并返回我预期的结果。

POST http://localhost:51657/api/search HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json; charset=utf-8
Accept: application/json
Host: localhost:51657
Content-Length: 219

{
  "ContentType":null,
  "RuleTypes":null,
  "Metadata":[
    {
    "Name":"ClientName",
    "Value":"Client One"
    },
    {
    "Name":"ClientName",
    "Value":"Client Two"
    }
  ]
}

This fails because the requestValues parameter is null

这失败,因为 requestValues 参数为空

POST http://localhost:51657/api/search HTTP/1.1
User-Agent: Fiddler
Content-Type: application/xml; charset=utf-8
Accept: application/xml
Host: localhost:51657
Content-Length: 213

<AimiRequest>
  <ContentType />
  <RuleTypes />
  <Metadata>
    <MetadataQueryParameter>
      <Name>ClientName</Name>
      <Value>Client One</Value>
    </MetadataQueryParameter>
    <MetadataQueryParameter>
      <Name>ClientName</Name>
      <Value>Client Two</Value>
    </MetadataQueryParameter>
  </Metadata>
</AimiRequest>

采纳答案by matthughes404

By adding the following lines to the ApplicationStart() method in your Global.asax.cs, your original XML request should work:

通过将以下行添加到 Global.asax.cs 中的 ApplicationStart() 方法,您的原始 XML 请求应该可以工作:

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;

By default, the Web API uses the DataContractSerializer class, which requires extra information in the XML request.

默认情况下,Web API 使用 DataContractSerializer 类,该类需要 XML 请求中的额外信息。

The XmlSerializer seems to work more smoothly for me, since I don't have to add the model's namepsace to each XML request.

XmlSerializer 对我来说似乎更顺畅,因为我不必将模型的命名空间添加到每个 XML 请求中。

Once again, i found my information in Mike Wasson's article: http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization#xml_media_type_formatter

再一次,我在 Mike Wasson 的文章中找到了我的信息:http: //www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization#xml_media_type_formatter

回答by matthughes404

I was having the same problem as you, and found the solution by serializing the object using the XmlMediaTypeFormatter as described here: http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization#testing_object_serialization. I used the code in the "Testing Object Serialization" section at the bottom of the article, and replaced his Person object with my model.

我遇到了和你一样的问题,通过使用 XmlMediaTypeFormatter 序列化对象找到了解决方案,如下所述:http: //www.asp.net/web-api/overview/formats-and-model-binding/json- and-xml-serialization#testing_object_serialization。我使用了文章底部“测试对象序列化”部分中的代码,并将他的 Person 对象替换为我的模型。

When I serialized my object, I noticed that the following attributes were added to the root node:

当我序列化我的对象时,我注意到以下属性被添加到根节点:

xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://schemas.datacontract.org/2004/07/NAMESPACE.OF.YOUR.MODEL"

If you add these attributes to your xml like so, your controller should correctly serialize the requestValues object:

如果您像这样将这些属性添加到您的 xml 中,您的控制器应该正确序列化 requestValues 对象:

<AimiRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://schemas.datacontract.org/2004/07/NAMESPACE.OF.YOUR.MODEL">
  <ContentType />
  <RuleTypes />
  <Metadata>
    <MetadataQueryParameter>
      <Name>ClientName</Name>
      <Value>Client One</Value>
    </MetadataQueryParameter>
    <MetadataQueryParameter>
      <Name>ClientName</Name>
      <Value>Client Two</Value>
    </MetadataQueryParameter>
  </Metadata>
</AimiRequest>