2012-02-14 4 views
0

Я использую OpenRasta 2.0.3.0.Перегрузка методов почтового обработчика для ресурса коллекции

У меня есть ресурс коллекции ListOfActivity и два различных вида деятельности, FileUploadActivity и CommentActivity. Оба класса активности наследуют от ActivityBase.

Если я выдаю запрос GET на номер билетов {ticketId] \ действия, то я возвращаюсь ListOfActivity. Я хотел бы иметь возможность POST любой вид деятельности для того же URI, чтобы добавлять элементы в коллекцию, но мне не удается заставить OpenRasta разрешить соответствующий метод для обработчика.

My (сокращенно) реализация обработчик:

public class ActivityHandler : ServiceBase, IActivityHandler 
{ 
    public ListOfActivityResource GetByTicketId(int ticketId) 
    { 
     ... 
    } 

    public OperationResult Post(FileUploadActivity fileUploadActivity, int ticketId) 
    { 
     ... 
    } 

    public OperationResult Post(CommentActivity commentActivity, int ticketId) 
    { 
     ... 
    } 
} 

Вот ресурсные классы:

[XmlType(TypeName = "commentActivity")] 
public class CommentActivity : ActivityBase 
{ 
    [XmlElement("comment")] 
    public string Comment { get; set; } 
} 

[XmlType(TypeName = "fileUploadActivity")] 
public class FileUploadActivity : ActivityBase 
{ 
    [XmlElement("content")] 
    public string Content { get; set; } 
} 

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

    [XmlElement("when")] 
    public DateTime When { get; set; } 

    [XmlElement("who")] 
    public string Who { get; set; } 

    // this property name is purposefully not called 'TicketId' as it caused an 
    // issue with OpenRasta's magic URI <> method matching algorithm because the 
    // UriTemplate for activity resources contains a parameter of the same name 
    [XmlElement("ticketId")] 
    public int TicketIdValue { get; set; } 
} 

[XmlType(TypeName = "activities")] 
[UriTemplate("tickets/{ticketId}/activities")] 
public class ListOfActivity 
{ 
    public ListOfActivity() 
    { 
     this.Activities = new List<ActivityBase>(); 
    } 

    [XmlElement("fileUpload", typeof(FileUploadActivity))] 
    [XmlElement("comment", typeof(CommentActivity))] 
    public List<ActivityBase> Activities { get; set; } 
} 

Отрывок из моей конфигурации является:

ResourceSpace.Has 
    .ResourcesOfType<ListOfActivity>() 
    .AtUri("tickets/{ticketId}/activities") 
    .HandledBy<ActivityHandler>() 
    .AsXmlSerializer(); 

ResourceSpace.Has 
    .ResourcesOfType<FileUploadActivity>() 
    .AtUri("tickets/{ticketId}/activities") 
    .HandledBy<ActivityHandler>() 
    .AsXmlSerializer(); 

ResourceSpace.Has 
    .ResourcesOfType<CommentActivity>() 
    .AtUri("tickets/{ticketId}/activities") 
    .HandledBy<ActivityHandler>() 
    .AsXmlSerializer(); 

При попытке POST a CommentActivity, я получаю ответ 405. Вот то, что я вижу в журнале:

Found 2 operation(s) with a matching name. 
Found 0 operation(s) with matching [HttpOperation] attribute. 
Operation ActivityHandler::Post(FileUploadActivity fileUploadActivity, Int32 ticketId) selected with 2 required members and 0 optional members, with codec XmlSerializerCodec with score 1. 
Operation ActivityHandler::Post(FileUploadActivity fileUploadActivity, Int32 ticketId) selected with 2 required members and 0 optional members, with codec XmlSerializerCodec with score 1. 
Operation ActivityHandler::Post(FileUploadActivity fileUploadActivity, Int32 ticketId) selected with 2 required members and 0 optional members, with codec XmlSerializerCodec with score 1. 
Operation ActivityHandler::Post(CommentActivity commentActivity, Int32 ticketId) selected with 2 required members and 0 optional members, with codec XmlSerializerCodec with score 1. 
Operation ActivityHandler::Post(CommentActivity commentActivity, Int32 ticketId) selected with 2 required members and 0 optional members, with codec XmlSerializerCodec with score 1. 
Operation ActivityHandler::Post(CommentActivity commentActivity, Int32 ticketId) selected with 2 required members and 0 optional members, with codec XmlSerializerCodec with score 1. 
Executing OperationResult OperationResult: type=MethodNotAllowed, statusCode=405. 
No response codec was searched for. The response entity is null or a response codec is already set. 
There was no response entity, not rendering.  
Writing http headers. 

Я попытался именования URI, и с помощью HttpOperationAttribute, но он не работает (как я вроде подозревал, так как они все же URI).

Перед введением второго ресурса активности единственный метод почты был решен в порядке.

Я делаю что-то неправильно здесь? Ответ Себастьяна Ламбла на this question, похоже, указывает, что это должно быть возможно.

ответ

0

Вы не можете этого сделать, это просто зло.

URI никогда не должны использоваться повторно через регистрацию ресурсов, или их ужасно путают, и больше не могут принимать логические решения (мы должны добавить некоторые предупреждения/ошибки в этих условиях).

Сначала я объявляю тип ресурса с каким ресурсом. Здесь это «список мероприятий», поэтому мы будем использовать , что.

ResourceSpace.Has 
    .ResourcesOfType<ListOfActivity>() 
    .AtUri("tickets/{ticketId}/activities") 
    .HandledBy<ActivityHandler>() 
    .AsXmlSerializer(); 

Когда OpenRasta будет смотреть на ваши методы, он будет пытаться найти что-то, что может deserialzie типы к нужному типу. Здесь, поскольку они разделяют базовый класс, а OpenRasta - действительно классная структура, вам просто нужно связать сами типы с ресурсами, не указывая им собственный идентификатор (uris).

ResourceSpace.Has 
    .ResourcesOfType<ActivityBase>() 
    .WithoutUri 
    .AsXmlSerializer() 

Теперь, когда вы делаете вашу POST к списку мероприятий ИЛИ будете смотреть на ваш обработчик, найти все методы, которые соответствуют запросу HTTP (здесь те, пост), и попытаться deserialie запроса в каждом из их, и, наконец, выбрал метод с большинством оставшихся входов.

Если вы понимаете эту концепцию, вы поймете, что это означает ИЛИ может попытаться десериализовать для обоих методов, что означает, что вам нужен запрос, который можно найти (например, по умолчанию для asp.net, а не по умолчанию для HttpListener).Вы должны знать об этом, по крайней мере, и если это может быть проблемой, разделите регистрацию самостоятельно, чтобы избежать этого (например, наличие билетов/{ticketId}/comments и .../fileUploads или таких).

Имена URI предназначены для различения нескольких URI для одного ресурса, а не для нескольких ресурсов для одного URI (который никогда не будет работать в OR).

+0

Я подозревал, что что-то не так с моим подходом. Спасибо, что нашли время, чтобы собрать ответ. Подход, к которому я пришел, заключался в том, чтобы иметь отдельные URI, как вы предложили, но сохранить исходный URI коллекции, чтобы вернуть их в виде единой коллекции. –

Смежные вопросы