1

当为相同类型但具有不同 URI 的两个处理程序注册时,处理程序选择算法在确定要使用哪个处理程序时似乎不会检查 uri。

如果你运行下面的程序,你会注意到只有 HandlerOne 会被调用(两次)。我调用“/one”还是“/two”都没有关系,后者应该由HandlerTwo处理。

我做错了什么还是要在 OpenRasta 中解决这个问题?(我正在使用 2.0.3.0 顺便说一句)

class Program
{
    static void Main(string[] args)
    {
        using (InMemoryHost host = new InMemoryHost(new Configuration()))
        {
            host.ProcessRequest(new InMemoryRequest
            {
                HttpMethod = "GET",
                Uri = new Uri("http://x/one")
            });
            host.ProcessRequest(new InMemoryRequest
            {
                HttpMethod = "GET",
                Uri = new Uri("http://x/two")
            });
        }
    }
}
class Configuration : IConfigurationSource
{
    public void Configure()
    {
        using (OpenRastaConfiguration.Manual)
        {
            ResourceSpace.Has.ResourcesOfType(typeof(object))
                .AtUri("/one").HandledBy(typeof(HandlerOne));
            ResourceSpace.Has.ResourcesOfType(typeof(object))
                .AtUri("/two").HandledBy(typeof(HandlerTwo));
        }
    }
}
class HandlerOne
{
    public object Get() { return "returned from HandlerOne.Get"; }
}
class HandlerTwo
{
    public object Get() { return "returned from HandlerTwo.Get"; }
}

更新 我有一种感觉,我可以使用 UriNameHandlerMethodSelector 来完成我想要的类似操作,如http://trac.caffeine-it.com/openrasta/wiki/Doc/Handlers/MethodSelection所述,但是我必须注释每个处理程序方法并执行 AtUri().Named(),这在我看来就像样板文件,我想避免这种情况。AtUri(X).HandledBy(Y) 不是清楚地说明了 X 和 Y 之间的联系吗?

4

3 回答 3

5

尤金,

您永远不应该在同一资源类型上进行多次注册,并且您可能永远不需要ResourcesOfType<object>与 URI 相关联,这将完全与 OpenRasta 中使用的解析算法相矛盾。

如果您要映射两个不同的事物,请创建两个资源类。处理程序和 URI 仅通过资源类关联,如果您在设计资源时失败,OpenRasta 将无法匹配两者,这是设计使然。

如果您想坚持这条路线,而我真的认为您不应该这样做,那么您可以注册各种 URI 以获得名称,并提示您的每个方法应该使用HttpOperation(ForUriName=blah). 该功能仅适用于您确实需要退出自动方法解析的非常非常罕见的场景。

最后,由于 OpenRasta 是一个可组合的框架,你不应该去破解现有的类,你应该将自己插入到框架中,以确保覆盖你不需要的组件并用你自己编码的东西替换它们。在这种情况下,如果您不喜欢默认设置并想要一个 MVC 样式的选择系统,您可以简单地编写一个贡献者,用您自己的 moel 替换处理程序选择。或者,如果您希望选择某些方法而不是其他方法,您可以删除现有的操作选择器并用您自己的方法替换它们(或补充它们)。这样,您将依赖已发布的 API 来扩展 OpenRasta,并且您的代码将来不会被破坏。如果您分叉和破解现有代码,我无法保证。

于 2011-10-25T08:23:34.280 回答
0

正如 Seb 所解释的,当您使用相同的资源类型注册多个处理程序时,OpenRasta 将处理程序视为一个大型连接类。因此,它猜测(描述它的最佳方式)执行哪个潜在的 GET(或其他 HTTP 动词)方法,它认为哪个最合适。从开发人员的角度来看,这是不可接受的,必须解决。

我在使用 OpenRasta 时需要能够向多个处理程序注册相同的资源类型。当从一个规范化的关系数据库中检索数据时,您一定会从多个请求中获得相同类型的响应。当创建多个查询(在 Linq 中)以从一对多关系的任一侧检索数据时会发生这种情况,这对数据库的整个结构当然很重要。

听取 Seb 的建议,并希望我正确地实施了他的建议,我采用了数据库模型类,并在资源命名空间中为每个可能引入重复资源类型的实例构建了一个派生类。

ResourceSpace.Has.ResourcesOfType<IList<Client>>()
                .AtUri("/clients").And
                .AtUri("/client/{clientid}").HandledBy<ClientsHandler>().AsJsonDataContract();

ResourceSpace.Has.ResourcesOfType<IList<AgencyClient>>()
                .AtUri("/agencyclients").And
                .AtUri("/agencyclients/{agencyid}").HandledBy<AgencyClientsHandler>().AsJsonDataContract();

Client 是我的 Model 类,然后我从中派生了 AgencyClient。

namespace ProductName.Resources
{
    public class AgencyClient: Client { }
}

您甚至不需要将从 Linq-SQL 数据访问层接收的基类转换为派生类。无论如何,Linq cast 方法并不适用于那种事情,尽管此代码将编译它,但它是错误的,您将收到运行时异常“LINQ to Entities 仅支持转换实体数据模型原始类型”。

Context.Set<Client>().Cast<AgencyClient>().ToList();  //will receive a runtime error

像 (AgencyClient) 这样的更传统的强制转换不起作用,因为在 C# 中不容易转换为子类。 将基类转换为派生类

使用 AS 运算符将再次编译甚至运行,但会在返回的列表中给出空值,因此不会检索预期的数据。

Context.Set<Client>().ToList() as IEnumerable<AgencyClient>; //will compile and run but will return null

我仍然不明白 OpenRasta 如何处理从处理程序到 ResourceType 的不同返回类,但确实如此,所以让我们利用它。也许 Seb 可以详细说明?

因此,OpenRasta 将这些类分开处理,并为 URI 执行正确的处理程序方法。

于 2012-12-13T15:25:17.267 回答
-2

我修补了 OpenRasta 以使其工作。这些是我接触的文件:

OpenRasta/Configuration/MetaModel/Handlers/HandlerMetaModelHandler.cs
OpenRasta/Handlers/HandlerRepository.cs
OpenRasta/Handlers/IHandlerRepository.cs
OpenRasta/Pipeline/Contributors/HandlerResolverContributor.cs

主要变化是现在处理程序存储库在对AddResourceHandler的初始化调用中获取注册的 URI ,因此当稍后在处理程序选择期间调用GetHandlerTypesFor时,它还可以检查 URI。接口方面,我改变了这个:

public interface IHandlerRepository
{
    void AddResourceHandler(object resourceKey, IType handlerType);
    IEnumerable<IType> GetHandlerTypesFor(object resourceKey);

对此:

public interface IHandlerRepository
{
    void AddResourceHandler(object resourceKey, IList<UriModel> resourceUris, IType handlerType);
    IEnumerable<IType> GetHandlerTypesFor(object resourceKey, UriRegistration selectedResource);

为简洁起见,我将省略实现。

此更改还意味着 OpenRasta 不会浪费时间进一步检查与手头请求无关的处理程序(它们的方法签名等)。

如果可能的话,我仍然想就这个问题获得其他意见。也许我只是错过了一些东西。

于 2011-10-19T06:35:46.050 回答