OpenRasta не может правильно десериализовать объект на PUT
Я испытываю действительно странное поведение при обработке 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
ПОСТАВЛЕН на сервер, 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
(но никогда не всплывает) сразу после этого шага, но трассировка стека настолько коротка, что я не знаю, в чем проблема:
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 ответа
Кажется, проблема в том, как URL интерпретируется и сопоставляется с обработчиком, потому что, если я добавлю метод обработчика, который также принимает int id
, как это:
CustomerResource Put(int id, CustomerForm customerForm)
Оно работает. Вероятно, это связано со следующей регистрацией ресурса:
ResourceSpace.Has.ResourcesOfType<CustomerResource>()
.AtUri("/customers/{id}")
Хотя у меня есть это:
ResourceSpace.Has.ResourcesOfType<CustomerForm>()
.WithoutUri
Я пытался изменить регистрацию CustomerForm
включить ID:
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 успешно десериализовать мою сущность.
Звучит странно, но вы пытались переместить идентификатор в верхнюю часть объекта 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".