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

发布于 2025-01-05 18:12:29 字数 4520 浏览 4 评论 0原文

我正在使用 OpenRasta 2.0.3.0。

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

如果我向 tickets{ticketId]\activities 发出 GET 请求,则会返回 ListOfActivity。我希望能够将任一类型的活动发布到同一 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 对 的回答这个问题似乎表明这应该是可能的。

I'm using OpenRasta 2.0.3.0.

I have a collection resource called ListOfActivity, and two distinct types of activity, FileUploadActivity and CommentActivity. Both activity classes inherit from ActivityBase.

If I issue a GET request to tickets{ticketId]\activities then I get back a ListOfActivity. I would like to be able to POST either kind of activity to the same URI to add items to the collection, but I am having trouble getting OpenRasta to resolve an appropriate method on the handler.

My (abbreviated) handler implementation is:

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

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

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

Here are the resource classes:

[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; }
}

A snippet of my configuration is:

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();

When I attempt to POST a CommentActivity, I get a 405 response. Here is what I see in the log:

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.

I have tried naming the URIs, and using HttpOperationAttribute, but it doesn't work (as I kind of suspected, as they're all the same URI).

Before the introduction of a second activity resource, the single post method was being resolved fine.

Am I doing something wrong here? Sebastien Lambla's answer to this question would seem to indicate that it should be possible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青瓷清茶倾城歌 2025-01-12 18:12:29

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

URI 永远不应该在资源注册中重复使用,否则会被它搞得非常困惑,并且无法再做出逻辑决策(我们应该在这些情况下添加一些警告/错误)。

我首先声明资源类型和资源是什么。这里是“活动列表”,所以我们将使用that

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

当 OpenRasta 查看您的方法时,它会尝试找到可以将类型反序列化为正确类型的东西。在这里,由于它们共享一个基类,并且 OpenRasta 是一个非常酷的框架,因此您只需将类型本身与资源相关联,而不需要为它们提供自己的标识符 (uri)。

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

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

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

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

You can't do that, that's just plain evil.

URIs should never be reused across resource registrations, OR gets terribly confused by it and can't make logical decisions anymore (we ought to add some warning / error on those conditions).

I'd first declare the resource type with what the resource is. Here it is "the list of activities", so we'll use that.

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

When OpenRasta will look at your methods, it will try and find something that can deserialzie the types to the correct type. Here, as they share a base class and OpenRasta is a really cool framework, you just need to associate the types itself to the resources, without giving them their own identifier (uris).

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

Now when you do your POST to the list of activities, OR will look at your handler, find all methods that match the http request (here the Post ones), and try to deserialie the request in each of them, and finally chose the method with the most inputs remaining.

If you understand that concept, you'll know that this means OR may try to deserialize for both methods, which means you need a request that's seekable (aka the default on asp.net, not the default on HttpListener). You need to be aware of that at the very least, and if it may be an issue, split the registrations independently to avoid this (such as having tickets/{ticketId}/comments and .../fileUploads or such).

URI names are for distinguishing between multiple URIs for one resource, not multiple resources for one URI (which will never ever work in OR).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文