OpenRasta не может правильно десериализовать объект на PUT - PullRequest
0 голосов
/ 15 июля 2011

У меня действительно странное поведение при обработке HTTP PUT в обработчике OpenRasta.Подпись метода обработчика выглядит следующим образом:

public CustomerResource Put(CustomerForm customerForm)

А вот соответствующая конфигурация ResourceSpace:

ResourceSpace.Has.ResourcesOfType<CustomerListResource>()
    .AtUri("/customers")
    .HandledBy<CustomerHandler>()
    .RenderedByAspx("~/Views/Customer/CustomerListView.aspx")
    .And.AsJsonDataContract().ForMediaType("application/json;q=0.3")
    .And.AsXmlSerializer().ForMediaType("application/xml;q=0.2");

ResourceSpace.Has.ResourcesOfType<CustomerResource>()
    .AtUri("/customers/{id}")
    .HandledBy<CustomerHandler>()
    .RenderedByAspx("~/Views/Customer/CustomerEditView.aspx")
    .And.AsJsonDataContract().ForMediaType("application/json;q=0.3")
    .And.AsXmlSerializer().ForMediaType("application/xml;q=0.2");

// To support POST and PUT to /customers
ResourceSpace.Has.ResourcesOfType<CustomerForm>()
    .WithoutUri
    .RenderedByAspx("~/Views/Customer/CustomerEditView.aspx")
    .And.AsJsonDataContract().ForMediaType("application/json;q=0.3")
    .And.AsXmlSerializer().ForMediaType("application/xml;q=0.2");

CustomerForm выглядит следующим образом:

[XmlRoot("customer", Namespace = ClientSettings.Namespace)]
public class CustomerForm : FormBase, ICustomer
{
    [XmlElement("contact-info")]
    public ContactInfo ContactInfo { get; set; }

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

ContactInfo выглядит следующим образом:

[XmlRoot("contact-info", Namespace = ClientSettings.Namespace)]
public class ContactInfo
{
    [XmlElement("email")]
    public string Email{ get; set; }

    [XmlElement("first-name")]
    public string FirstName{ get; set; }

    [XmlElement("last-name")]
    public string LastName{ get; set; }

    [XmlElement("mobile-phone-number")]
    public string MobilePhoneNumber { get; set; }
}

Моя проблема в том, что когда CustomerForm PUT для сервера, OpenRasta не может его десериализовать должным образом.Он десериализует его с ContactInfo, установленным на null, хотя он успешно отправляется с клиента.Я даже покопался в IRequest.Entity.Stream, чтобы убедиться, что нужный мне XML действительно есть, и он:

<?xml version="1.0" encoding="utf-8"?>
<customer id="1" xmlns="urn:namespace">
    <contact-info>
        <email>5867ca8a5a5548428c4bc90c1f7e41d6@example.com</email>
        <first-name>0440a6d5f071478d8571bac1301552bc</first-name>
        <last-name>49069fb41eb141c79326dc64fa034573</last-name>
        <mobile-phone-number>59980075</mobile-phone-number>
    </contact-info>
</customer>

Как IRequest.Entity.Stream может содержать необходимые данные при десериализованном объекте CustomerFormполучил в методе Put(CustomerForm) не?У меня есть тесты, которые гарантируют, что сериализация и десериализация работают отлично, и у меня даже есть Post(CustomerForm) в том же самом обработчике, который также работает.Просто когда для HTTP-метода установлен PUT, CustomerForm имеет ContactInfo, установленный на null.

Я полностью прочитал отладочный вывод из OpenRasta и все, что он говорит:

    27-[2011-07-15 11:09:15Z] Information(0) Operation CustomerHandler::Put(CustomerForm customerForm) was selected with a codec score of 0
    27-[2011-07-15 11:09:15Z] Information(0) Loaded codec OpenRasta.Codecs.XmlSerializerCodec
    27-[2011-07-15 11:09:15Z] Verbose(0) Switching to full object media type reading.
27-[2011-07-15 11:09:15Z] Stop(1) Exiting PipelineRunner
27-[2011-07-15 11:09:15Z] Start(1) Entering PipelineRunner: Executing contributor OperationInterceptorContributor.WrapOperations
27-[2011-07-15 11:09:16Z] Stop(1) Exiting PipelineRunner
27-[2011-07-15 11:09:16Z] Start(1) Entering PipelineRunner: Executing contributor OperationInvokerContributor.ExecuteOperations
    27-[2011-07-15 11:09:16Z] Verbose(0) Ignoring constructor, following dependencies didn't have a registration:OpenRasta.OperationModel.Interceptors.IOperationInterceptor[]

Единственная странная особенность, которую я заметил, это то, что MissingMethodException выбрасывается как FirstChanceException (но никогда не всплывает) сразу после этого шага, но его след в стеке настолько короткий, что я понятия не имею, в чем проблемаbe:

2011-07-15T13:09:16.036 AppDomain.FirstChanceException
System.MissingMethodException: Member not found.
   at System.DefaultBinder.BindToMethod(BindingFlags bindingAttr, MethodBase[] match, Object[]& args, ParameterModifier[] modifiers, CultureInfo cultureInfo, String[] names, Object& state)

Я понятия не имею, почему выбрасывается MissingMethodException и почему он не всплывает, если я не подписываюсь на событие AppDomain.FirstChanceException, но это может быть связано с тем, почемумой CustomerForm не десериализован правильно.Однако, поскольку он правильно десериализуется в HTTP POST, у меня есть сомнения.

Идеи?

Ответы [ 2 ]

1 голос
/ 21 октября 2011

Кажется, проблема в том, как URL интерпретируется и сопоставляется с обработчиком, потому что, если я добавлю метод обработчика, который также принимает int id, например:

CustomerResource Put(int id, CustomerForm customerForm)

Это работает.Вероятно, это связано со следующей регистрацией ресурса:

ResourceSpace.Has.ResourcesOfType<CustomerResource>()
    .AtUri("/customers/{id}")

Хотя у меня есть это:

ResourceSpace.Has.ResourcesOfType<CustomerForm>()
    .WithoutUri

Я попытался изменить регистрацию CustomerForm, чтобы включить идентификатор:

ResourceSpace.Has.ResourcesOfType<CustomerForm>()
    .AtUri("/customers/{id}")

А также сделать идентификатор необязательным как при регистрации CustomerResource, так и CustomerForm:

ResourceSpace.Has.ResourcesOfType<CustomerResource>()
    .AtUri("/customers/{*id}")

ResourceSpace.Has.ResourcesOfType<CustomerForm>()
    .AtUri("/customers/{*id}")

Ничего из этого не помогает, но добавление параметра int id вметод-обработчик делает, поэтому я рад, что это заставляет OpenRasta успешно десериализовать мою сущность.

1 голос
/ 15 июля 2011

Звучит странно, но вы пытались переместить идентификатор в верхнюю часть объекта CustomerForm?

[XmlRoot("customer", Namespace = ClientSettings.Namespace)]
public class CustomerForm : FormBase, ICustomer
{
    [XmlAttribute("id")]
    public int Id { get; set; }

    [XmlElement("contact-info")]
    public ContactInfo ContactInfo { get; set; }
}

Openrasta использует сериализатор xml контракта данных .net (ужасный), который чувствителен к позициям элементов.На самом деле мы написали наш собственный сериализатор, который просто возвращается к традиционному сериализатору xml "dot net".

...