可以使用ASP.NET路由为.ashx(IHttpHander)处理程序创建“干净”的URL吗?
|
我有一些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-mvc – 在Asp.Net MVC应用程序中使用Structuremap将
- Global.asax中的ASP.NET会话
- entity-framework – DbContext未在ASP.Net MVC中使用SQL S
- asp.net – aspx中的设计视图没有加载
- asp.net viewstate加密问题
- asp.net-mvc – 什么是适当的时间为ViewData,ViewBag,会话,
- asp.net – 在asp:Button中包装文本
- 是否有WPF的母版页(如asp.net)的概念?
- asp.net-core – 找不到Swashbuckle.AspNetCore SwaggerOpe
