25

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

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

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

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

我的行动:

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

我的模型:

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

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

这工作并返回我预期的结果。

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"
    }
  ]
}

这失败了,因为 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>
4

2 回答 2

26

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

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

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

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

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

于 2012-06-27T17:38:36.440 回答
5

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

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

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

如果你像这样将这些属性添加到你的 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>
于 2012-06-27T15:31:48.313 回答