Нулевой параметр с веб-API MVC в OWIN Self-Host

Я размещаю веб-API с помощью OWIN в рабочей роли Azure, следуя этим руководствам:

http://www.asp.net/web-api/overview/hosting-aspnet-web-api/use-owin-to-self-host-web-api http://www.asp.net/web-api/overview/hosting-aspnet-web-api/host-aspnet-web-api-in-an-azure-worker-role

Запросы направляются правильно. Точка останова останавливается, как и ожидалось, внутри метода контроллера, но параметр метода, украшенный атрибутом [FromBody], всегда принимает значение NULL.

Ниже приведены подробности моих методов и классов:

Заголовок запроса:

User-Agent: Fiddler
Content-Type: text/xml; charset=utf-8
Host: localhost:81
Content-Length: 365

Тело запроса:

<?xml version="1.0"?>
<Unit name="ShopActiVID" serialNumber="00123" macAddress="40:d8:55:aa:aa:aa" tzOffset="-0400" useDst="True">
  <Door name="Shop Main" ID="146">
    <count date="2014-06-19T16:58:31.0000000Z" in="0" out="0"/>
  </Door>
  <Door name="Conf. Area" ID="147">
    <count date="2014-06-19T16:58:31.0000000Z" in="2" out="0"/>
  </Door>
</Unit>

Класс, используемый в качестве полезной нагрузки для тела:

[DataContract(Name="Unit", IsReference=true)]
    public class AddPeopleCountRequest
    {
        [DataMember(Name="name")]
        public string Name { get; set; }

        [DataMember(Name = "serialNumber")]
        public string SerialNumber { get; set; }

        [DataMember(Name = "macAddress")]
        public string MacAddress { get; set; }

        [DataMember(Name = "tzOffset")]
        public string TzOffset { get; set; }

        [DataMember(Name = "useDst")]
        public bool UseDst { get; set; }

        public List<Door> Doors { get; set; }
    }

    [DataContract(Name="Door", IsReference=true)]
    public class Door 
    {
        [DataMember(Name = "name")]
        public string Name { get; set; }

        [DataMember(Name = "ID")]
        public int Id { get; set; }
        public List<Count> Counts { get; set; }
    }

    [DataContract(Name="count", IsReference=true)]
    public class Count 
    {
        [DataMember(Name = "date")]
        public DateTime Time { get; set; }

        [DataMember(Name = "in")]
        public int In { get; set; }

        [DataMember(Name = "out")]
        public int Out { get; set; }
    }

Метод контроллера:

[RoutePrefix("api/v1")]
public class CollectorController : ApiController
{
    [HttpPost]
    [Route("count")]
    public async Task<IHttpActionResult> AddPeopleCountRecord([FromBody]AddPeopleCountRequest addCountRequest) 
    {
        ...
        return Ok(); 
    }
}

Класс запуска OWIN:

public class Startup
    {
        public void Configuration(IAppBuilder app) 
        {
            var config = new HttpConfiguration();
            config.MapHttpAttributeRoutes();
            app.UseWebApi(config);
        }
    }

Итак, каждый раз, когда я делаю запрос к скрипачу, отправляющему XML, он никогда не десериализуется прямо в параметр Action на контроллере.

Так что я делаю не так?

Спасибо! Очень признателен за помощь!


person Gutemberg Ribeiro    schedule 20.06.2014    source источник


Ответы (2)


Проблема заключается в использовании данных (например, name, serialNumber, macAddress) в качестве атрибутов в xml. По умолчанию средство форматирования Xml веб-API использует DataContractSerializer в качестве сериализатора. Этот сериализатор не поддерживает использование данных в качестве атрибутов в XML. Для этого вам нужно будет использовать XmlSerializer. Вы можете изменить настройки средства форматирования по умолчанию, чтобы использовать этот сериализатор.

Также, как правило, если вы не видите, что параметр вашего действия заполняется, вы можете проверить ModelState валидность, чтобы найти ошибки, если таковые имеются.

if (!ModelState.IsValid)
{
    return BadRequest(this.ModelState);
}
person Kiran Challa    schedule 20.06.2014
comment
Спасибо. Я использую этот XML, потому что именно так стороннее устройство POST XML в моем API ... Я уже использовал XmlSerializer: config.Formatters.XmlFormatter.UseXmlSerializer = true; безуспешно ... У вас есть еще одна подсказка? - person Gutemberg Ribeiro; 20.06.2014

Хорошо, наконец, он заработал.

Сначала в Startup.cs я изменил сериализатор на:

  public class Startup
    {
        public void Configuration(IAppBuilder app) 
        {
            var config = new HttpConfiguration();
            config.Formatters.XmlFormatter.UseXmlSerializer = true;
            config.MapHttpAttributeRoutes();
            app.UseWebApi(config);
        }
    }

Затем, поскольку мы используем старый XmlSerializar, мы не можем сохранить атрибуты DataContract / Member поверх свойств. Вместо этого мы должны использовать XmlAttribute / XmlMember, как показано в следующем коде, и параметр десериализован правильно:

[XmlRoot("Unit")]
    public class AddPeopleCountRequest
    {
        [XmlAttribute("name")]
        public string Name { get; set; }

        [XmlAttribute("serialNumber")]
        public string SerialNumber { get; set; }

        [XmlAttribute("macAddress")]
        public string MacAddress { get; set; }

        [XmlElement(ElementName="Door", Type=typeof(Door))]
        public List<Door> Doors { get; set; }
    }


    public class Door 
    {
        [XmlAttribute("name")]
        public string Name { get; set; }

        [XmlAttribute("ID")]
        public int Id { get; set; }

        [XmlElement(ElementName = "count", Type = typeof(Count))]
        public List<Count> Counts { get; set; }
    }

    public class Count 
    {
        [XmlAttribute("date")]
        public DateTime Time { get; set; }

        [XmlAttribute("in")]
        public int In { get; set; }

        [XmlAttribute("out")]
        public int Out { get; set; }
    }

Всем спасибо за помощь!

person Gutemberg Ribeiro    schedule 20.06.2014