可以使用ASP.NET路由为.ashx(IHttpHander)处理程序创建“干净”
我有一些REST服务使用简单的老式IHttpHandlers。我想要生成更干净的URL,这样我就没有路径中的.ashx。有没有办法使用ASP.NET路由来创建映射到ashx处理程序的路由?我以前看过这些类型的路由:
// Route to an aspx page RouteTable.Routes.MapPageRoute("route-name","some/path/{arg}","~/Pages/SomePage.aspx"); // Route for a WCF service RouteTable.Routes.Add(new ServiceRoute("Services/SomeService",new WebServiceHostFactory(),typeof(SomeService))); 尝试使用RouteTable.Routes.MapPageRoute()生成错误(处理程序不从页面派生)。 System.Web.Routing.RouteBase只有两个派生类:ServiceRoute用于服务,DynamicDataRoute用于MVC。我不知道MapPageRoute()是做什么的(反射器没有显示方法体,它只是显示“性能关键到内联这种类型的方法跨越NGen图像边界”)。 我看到RouteBase没有密封,并且有一个比较简单的界面: public abstract RouteData GetRouteData(HttpContextBase httpContext); public abstract VirtualPathData GetVirtualPath(RequestContext requestContext,RouteValueDictionary values); 所以也许我可以做自己的HttpHandlerRoute。我会给出一个镜头,但是如果有人知道现有或内置的映射到IHttpHandlers的路由,那将是巨大的。 解决方法
好的,我一直在想这个,因为我原来问这个问题,我终于有一个解决方案,只是我想要的。然而,有一些前面的解释是由于。 IHttpHandler是一个非常基本的界面:
bool IsReusable { get; } void ProcessRequest(HttpContext context) 没有内置的访问路径数据的属性,路由数据也不能在上下文或请求中找到。 System.Web.UI.Page对象具有RouteData属性,ServiceRoutes执行解释您的UriTemplates的所有工作,并将值传递到内部正确的方法,ASP.NET MVC提供了自己访问路由数据的方式。即使您有一个RouteBase,(a)确定传入的URL是否与您的路由匹配,(b)解析该URL以从您的IHttpHandler中提取要使用的所有个别值,则没有简单的方法可以通过路由数据到您的IHttpHandler。如果你想保持你的IHttpHandler“纯”,可以这么说,它负责处理url,以及如何从中提取任何值。在这种情况下,RouteBase实现仅用于确定是否应该使用您的IHttpHandler。 然而,一个问题依然存在。一旦RouteBase确定传入的URL与您的路由匹配,就会传递给一个IRouteHandler,它会创建要处理您的请求的IHttpHandler的实例。但是,一旦你在你的IHttpHandler,context.Request.CurrentExecutionFilePath的价值是误导的。这是来自客户端的URL,减去查询字符串。所以这不是你的.ashx文件的路径。而且,您的路由的任何部分(如方法的名称)都将是该路径的一部分,这些部分将是执行文件路径值的一部分。如果您在IHttpHandler中使用UriTemplates来确定IHttpHandler中哪个特定方法应该处理请求,那么这可能是一个问题。 示例:如果您在/myApp/services/myHelloWorldHandler.ashx中有.ashx处理程序 那么你的CurrentExecutionFilePath将是:/ myApp / services / hello / Sam。它包含路由url的一部分,这是一个问题。您希望执行文件路径与您的路由网址匹配。 RouteBase和IRouteHandler的以下实现处理这个问题。 在粘贴2个类之前,这里有一个非常简单的用法示例。请注意,RouteBase和IRouteHandler的这些实现将实际上适用于甚至没有.ashx文件的IHttpHandlers,这是非常方便的。 // A "headless" IHttpHandler route (no .ashx file required) RouteTable.Routes.Add(new GenericHandlerRoute<HeadlessService>("services/headless")); 这将导致所有匹配“服务/无头”路由的传入URL被切换到HeadlessService IHttpHandler的新实例(HeadlessService只是这种情况下的一个例子,这将是您想要传递的任何IHttpHandler实现) 。 好的,所以这里是路由类的实现,注释和全部: /// <summary> /// For info on subclassing RouteBase,check Pro Asp.NET MVC Framework,page 252. /// Google books link: http://books.google.com/books?id=tD3FfFcnJxYC&pg=PA251&lpg=PA251&dq=.net+RouteBase&source=bl&ots=IQhFwmGOVw&sig=0TgcFFgWyFRVpXgfGY1dIUc0VX4&hl=en&ei=z61UTMKwF4aWsgPHs7XbAg&sa=X&oi=book_result&ct=result&resnum=6&ved=0CC4Q6AEwBQ#v=onepage&q=.net%20RouteBase&f=false /// /// It explains how the asp.net runtime will call GetRouteData() for every route in the route table. /// GetRouteData() is used for inbound url matching,and should return null for a negative match (the current requests url doesn't match the route). /// If it does match,it returns a RouteData object describing the handler that should be used for that request,along with any data values (stored in RouteData.Values) that /// that handler might be interested in. /// /// The book also explains that GetVirtualPath() (used for outbound url generation) is called for each route in the route table,but that is not my experience,/// as mine used to simply throw a NotImplementedException,and that never caused a problem for me. In my case,I don't need to do outbound url generation,/// so I don't have to worry about it in any case. /// </summary> /// <typeparam name="T"></typeparam> public class GenericHandlerRoute<T> : RouteBase where T : IHttpHandler,new() { public string RouteUrl { get; set; } public GenericHandlerRoute(string routeUrl) { RouteUrl = routeUrl; } public override RouteData GetRouteData(HttpContextBase httpContext) { // See if the current request matches this route's url string baseUrl = httpContext.Request.CurrentExecutionFilePath; int ix = baseUrl.IndexOf(RouteUrl); if (ix == -1) // Doesn't match this route. Returning null indicates to the asp.net runtime that this route doesn't apply for the current request. return null; baseUrl = baseUrl.Substring(0,ix + RouteUrl.Length); // This is kind of a hack. There's no way to access the route data (or even the route url) from an IHttpHandler (which has a very basic interface). // We need to store the "base" url somewhere,including parts of the route url that are constant,like maybe the name of a method,etc. // For instance,if the route url "myService/myMethod/{myArg}",and the request url were "http://localhost/myApp/myService/myMethod/argValue",// the "current execution path" would include the "myServer/myMethod" as part of the url,which is incorrect (and it will prevent your UriTemplates from matching). // Since at this point in the exectuion,we know the route url,we can calculate the true base url (excluding all parts of the route url). // This means that any IHttpHandlers that use this routing mechanism will have to look for the "__baseUrl" item in the HttpContext.Current.Items bag. // TODO: Another way to solve this would be to create a subclass of IHttpHandler that has a BaseUrl property that can be set,and only let this route handler // work with instances of the subclass. Perhaps I can just have RestHttpHandler have that property. My reticence is that it would be nice to have a generic // route handler that works for any "plain ol" IHttpHandler (even though in this case,you have to use the "global" base url that's stored in HttpContext.Current.Items...) // Oh well. At least this works for now. httpContext.Items["__baseUrl"] = baseUrl; GenericHandlerRouteHandler<T> routeHandler = new GenericHandlerRouteHandler<T>(); RouteData rdata = new RouteData(this,routeHandler); return rdata; } public override VirtualPathData GetVirtualPath(RequestContext requestContext,RouteValueDictionary values) { // This route entry doesn't generate outbound Urls. return null; } } public class GenericHandlerRouteHandler<T> : IRouteHandler where T : IHttpHandler,new() { public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new T(); } } 我知道这个答案已经很长时间了,但这不是一个容易解决的问题。核心逻辑是很容易的,诀窍在某种程度上使您的IHttpHandler知道“基本URL”,以便它可以正确地确定url的哪些部分属于路由,哪些部分是服务调用的实际参数。 这些类将用于我即将到来的C#REST库,RestCake.我希望我的路径下的路径兔洞可以帮助决定RouteBase的任何人,并使用IHttpHandlers做酷的东西。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 为什么要使用流畅的验证而不是ASP.NET MVC验证
- asp.net web大文件上传带进度条实例代码
- asp.net-mvc-4 – 如何在Durandal中使用cshtml文件?
- 如何清除正式环境中的缓存
- 使用 MiniProfiler 来分析 ASP.NET Core 应用
- asp.net-mvc – 使用实体框架的mvc中的模型和表之间的差异(
- asp.net – 如何在Kendo UI中获取下拉菜单的选定项目的文本
- asp.net-mvc – 如何在Asp.Net MVC中做部分帖子?
- 谈谈分布式事务(Distributed Transaction)[共5篇]
- asp.net-mvc-3 – StructureMap初学者|物业注入
- asp.net-mvc-3 – URL路径参数用例
- asp.net-mvc – ASP.NET MVC Javascript ActionR
- Asp.net核心2采用角度6模板
- asp.net-identity – 多租户身份服务器openid身份
- asp.net – 在ValidationSummary上动态显示boots
- asp.net-core-mvc – global.json和src文件夹有多
- asp.net – AspNetSynchronizationContext
- asp.net核心 – 从OWIN迁移到ASP.NET核心
- .net – IAuthenticationFilter.OnAuthenticatio
- asp-classic – 会话清除和页面刷新