当为相同类型注册两个处理程序但具有不同的URI时,处理程序选择算法在确定要使用哪个处理程序时似乎不检查uri。
如果你运行下面的程序,你会发现只会调用HandlerOne(两次)。如果我调用“/ one”或“/ two”并不重要,后者应该由HandlerTwo处理。
我做错了什么或者这是在OpenRasta中解决的问题? (我正在使用2.0.3.0 btw)
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"; }
}
更新 我有一种感觉,我可以使用http://trac.caffeine-it.com/openrasta/wiki/Doc/Handlers/MethodSelection中描述的UriNameHandlerMethodSelector完成我想要的东西,但是我必须注释每个处理程序方法并且还要执行AtUri()。Named(),它看起来像样板文件我和我想避免这种情况。是不是AtUri(X).HandledBy(Y)使X和Y之间的连接清楚了吗?
答案 0 :(得分:5)
尤金,
你永远不应该在同一资源类型上进行多次注册,并且你可能永远不需要ResourcesOfType<object>
与URI关联,这将完全搞砸OpenRasta中使用的解析算法。
如果您要映射两个不同的东西,请创建两个资源类。处理程序和URI只与资源类相关联,如果您在设计资源时失败,OpenRasta将无法匹配这两者,这是设计使然。
如果你想坚持这条路线,我真的不认为你应该这样做,那么你可以注册各种URI来获得一个名字,并提示你应该使用{{ 1}}。这些功能仅适用于那些非常非常罕见的情况,您需要选择退出自动方法解析。
最后,由于OpenRasta是一个可复制的框架,你不应该去破解现有的类,你应该把自己插入到框架中以确保覆盖你不想要的组件并用你自己编写的代码替换它们。在这种情况下,如果您不喜欢默认值并想要一个MVC风格的选择系统,您可以简单地编写一个使用您自己的moel替换处理程序选择的贡献者。或者,如果您希望选择某些方法而不是其他方法,则可以删除现有的操作选择器并将其替换为(或与之相辅相成)。这样,您将依赖已发布的API来扩展OpenRasta,并且您的代码将来不会被破坏。如果您分叉并破解现有代码,我无法保证。
答案 1 :(得分: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();
客户端是我的Model类,然后我从中派生了AgencyClient。
namespace ProductName.Resources
{
public class AgencyClient: Client { }
}
您甚至不需要将从Linq-SQL数据访问层接收的基类强制转换为派生类。 Linq强制转换方法无论如何都不适用于那种事情,虽然这段代码将被编译为错误,但您将收到运行时异常“LINQ to Entities仅支持转换实体数据模型基元类型。”
Context.Set<Client>().Cast<AgencyClient>().ToList(); //will receive a runtime error
像(AgencyClient)这样的传统强制转换不起作用,因为在C#中不容易转换为SubClass。 Convert base class to derived class
使用AS运算符将再次编译甚至运行,但会在返回的列表中给出null值,因此不会检索预期的数据。
Context.Set<Client>().ToList() as IEnumerable<AgencyClient>; //will compile and run but will return null
我仍然不明白OpenRasta如何处理从处理程序到ResourceType的不同返回类,但确实如此,让我们利用它。也许Seb可能会详细说明吗?
因此,OpenRasta会单独处理这些类,并为URI执行正确的处理程序方法。答案 2 :(得分:-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不会浪费时间进一步检查与手头请求无关的处理程序(方法签名等)。
如果可能的话,我还是想就这个问题得到其他意见。也许我只是错过了什么。