重载集合资源的Post处理程序方法

本文关键字:处理 程序 方法 Post 集合 资源 重载 | 更新日期: 2023-09-27 18:24:19

我使用的是OpenRasta 2.0.3.0。

我有一个名为ListOfActivity的集合资源,以及两种不同类型的活动,FileUploadActivityCommentActivity。这两个活动类都继承自ActivityBase

如果我向tickets{ticketId]''activities发出GET请求,那么我会返回一个ListOfActivity。我希望能够将任何一种活动POST到同一URI以向集合添加项目,但我在让OpenRasta解决处理程序上的适当方法时遇到了问题。

我的(缩写)处理程序实现是:

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一个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)。

在引入第二个活动资源之前,单帖子方法得到了很好的解决。

我是不是做错了什么?Sebastien Lambla对这个问题的回答似乎表明这应该是可能的。

重载集合资源的Post处理程序方法

你不能那样做,那简直是邪恶。

URI永远不应该在资源注册中重复使用,或者被它弄得非常困惑,无法再做出逻辑决策(我们应该在这些条件上添加一些警告/错误)。

我首先用资源来声明资源类型。这里是"活动列表",所以我们将使用

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

当OpenRasta查看您的方法时,它会尝试找到一些可以将类型取消序列化为正确类型的方法。在这里,因为它们共享一个基类,而OpenRasta是一个非常酷的框架,所以您只需要将类型本身与资源相关联,而不需要给它们自己的标识符(uris)。

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

现在,当您对活动列表执行POST时,OR将查看您的处理程序,找到与http请求匹配的所有方法(此处为POST方法),并尝试在每个方法中取消对请求的序列化,最后选择剩余输入最多的方法。

如果你理解这个概念,你就会知道这意味着OR可能会尝试对这两个方法进行反序列化,这意味着你需要一个可查找的请求(也就是asp.net上的默认请求,而不是HttpListener上的默认值)。您至少需要意识到这一点,如果这可能是一个问题,请独立拆分注册以避免这种情况(例如有tickets/{ticketId}/注释和…/fileUploads等)。

URI名称用于区分一个资源的多个URI,而不是一个URI的多个资源(这在OR中永远不会起作用)。