重载收集资源的后处理程序方法

时间:2012-02-14 08:46:44

标签: c# rest openrasta

我正在使用OpenRasta 2.0.3.0。

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

如果我向 ticket {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();

当我尝试发布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对this question的回答似乎表明它应该是可能的。

1 个答案:

答案 0 :(得分:0)

你不能这样做,那只是简单的邪恶。

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上的默认值)。你需要至少知道这一点,如果它可能是一个问题,请单独拆分注册以避免这种情况(例如有ticket / {ticketId} / comments和... / fileUploads等)。

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