// 说明:命名空间中和类名之间可以用 / 和 . 分隔,但是在<system.web>/<httpHandlers>节点中要注意 / 出现的次数与URL中的次数匹配 // IIS的集成模式没有这个问题。 // 补充说明:以上正则表示式当遇到REST风格时,如果在method位置包含了非字符类的文字作为方法的传入参数,匹配后将会造成数据丢失。 // 因为是采用的 (?<method>\w+) ,除非换成 (?<method>[^\.]+) ,并且在得到数据后做UrlDecode /* * 可以解析以下格式的URL:(前一个表示包含命名空间的格式) * * /service/namespace.Fish.AA.Demo/GetMd5.aspx * /service/namespace.Fish.AA/Demo/GetMd5.aspx * /service/Demo/GetMd5.aspx * /api/aa/Demo/GetMd5 * /api/aa.b/Demo/GetMd5?ss=a.b */ /// <summary> /// 从指定的请求中提取UrlActionInfo /// </summary> /// <param name="context"></param> /// <param name="path"></param> /// <returns></returns> public virtual UrlActionInfo GetUrlActionInfo(HttpContext context, string path) { // 扩展点:允许自定义URL解析逻辑 if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } Match match = ServiceUrlRegex.Match(path); if (match.Success == false) { DiagnoseResult diagnoseResult = Http404DebugModule.TryGetDiagnoseResult(context); if (diagnoseResult != null) { diagnoseResult.ErrorMessages.Add("URL解析失败,正则表达式:" + ServiceUrlRegex.ToString()); } return(null); } return(new UrlActionInfo { UrlType = match.Groups["type"].Value, Namesapce = match.Groups["namespace"].Value, ClassName = match.Groups["name"].Value, MethodName = match.Groups["method"].Value, ExtName = match.Groups["extname"].Value }); }
internal IHttpHandler GetHttpHandler(HttpContext context, UrlActionInfo info) { if (context == null) { throw new ArgumentNullException("context"); } if (info == null) { throw new ArgumentNullException("info"); } // 获取内部表示的调用信息 ControllerResolver controllerResolver = new ControllerResolver(context); InvokeInfo vkInfo = controllerResolver.GetActionInvokeInfo(info); if (vkInfo == null) { IHttpHandler handler = Http404DebugModule.TryGetHttp404PageHandler(context); if (handler != null) { return(handler); } else { return(null); } } // 创建能够调用Action的HttpHandler return(ActionHandlerFactory.CreateHandler(vkInfo)); }
internal ControllerResolver(HttpContext context) { if (context == null) { throw new ArgumentNullException("context"); } _context = context; DiagnoseResult = Http404DebugModule.TryGetDiagnoseResult(context); s_metadata.Init(); }
/// <summary> /// 实现IHttpHandlerFactory接口,从当前请求获取IHttpHandler /// </summary> /// <param name="context"></param> /// <param name="requestType"></param> /// <param name="virtualPath"></param> /// <param name="physicalPath"></param> /// <returns></returns> public IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string physicalPath) { // 说明:这里不使用virtualPath变量,因为不同的配置,这个变量的值会不一样。 // 例如:/Ajax/*/*.aspx 和 /Ajax/* // 为了映射HTTP处理器,下面直接使用context.Request.Path string vPath = context.GetRealVirtualPath(); // 根据请求路径,定位到要执行的Action UrlActionInfo info = ParseUrl(context, vPath); if (info == null) { IHttpHandler handler = Http404DebugModule.TryGetHttp404PageHandler(context); if (handler != null) { return(handler); } ExceptionHelper.Throw404Exception(context); } info.SetHttpcontext(context); // 获取内部表示的调用信息 ControllerResolver controllerResolver = new ControllerResolver(context); InvokeInfo vkInfo = controllerResolver.GetActionInvokeInfo(info); if (vkInfo == null) { IHttpHandler handler = Http404DebugModule.TryGetHttp404PageHandler(context); if (handler != null) { return(handler); } ExceptionHelper.Throw404Exception(context); } // 创建能够调用Action的HttpHandler return(ActionHandlerFactory.CreateHandler(vkInfo)); }
public void Test2() { string requestText = @" POST http://www.fish-mvc-demo.com/Ajax/test/DataTypeTest/xxxxxxxxxxx.aspx HTTP/1.1 "; // 上面URL指定了一个不存在的Action名称,会引发404错误 IHttpHandler handler = null; Http404DebugModule debugModule = new Http404DebugModule(); using (WebContext context = WebContext.FromRawText(requestText)) { debugModule.app_BeginRequest(context.Application.Instance, null); var factory = new ServiceHandlerFactory(); handler = factory.GetHandler(context.HttpContext, "POST", null, null); } Assert.IsInstanceOfType(handler, typeof(Http404PageHandler)); }
/// <summary> /// 实现IRouteHandler接口 /// </summary> /// <param name="requestContext"></param> /// <returns></returns> public IHttpHandler GetHttpHandler(RequestContext requestContext) { HttpContext context = requestContext.HttpContext.ApplicationInstance.Context; UrlActionInfo info = GetUrlActionInfo(requestContext.RouteData, context); if (info == null) { IHttpHandler handler = Http404DebugModule.TryGetHttp404PageHandler(context); if (handler != null) { return(handler); } ExceptionHelper.Throw404Exception(context); } info.SetHttpcontext(context); return(GetHttpHandler(context, info)); }
IHttpHandler IHttpHandlerFactory.GetHandler(HttpContext context, string requestType, string virtualPath, string physicalPath) { // 说明:这里不使用virtualPath变量,因为不同的配置,这个变量的值会不一样。 // 例如:/mvc/*/*.aspx 和 /mvc/* // 为了映射HTTP处理器,下面直接使用context.Request.Path string requestPath = context.Request.Path; string vPath = context.GetRealVirtualPath(); // 尝试根据请求路径获取Action ControllerResolver controllerResolver = new ControllerResolver(context); InvokeInfo vkInfo = controllerResolver.GetActionInvokeInfo(vPath); // 如果没有找到合适的Action,并且请求的是一个ASPX页面,则按ASP.NET默认的方式来继续处理 if (vkInfo == null) { if (requestPath.EndsWith(".aspx", StringComparison.OrdinalIgnoreCase)) { // 调用ASP.NET默认的Page处理器工厂来处理 try { return(_msPageHandlerFactory.GetHandler(context, requestType, requestPath, physicalPath)); } catch (Exception ex) { if (controllerResolver.DiagnoseResult != null) { controllerResolver.DiagnoseResult.ErrorMessages.Add("System.Web.UI.PageHandlerFactory不能根据指定的URL地址创建IHttpHandler实例。"); controllerResolver.DiagnoseResult.ErrorMessages.Add(ex.Message); return(Http404DebugModule.TryGetHttp404PageHandler(context)); } throw; } } } return(ActionHandlerFactory.CreateHandler(vkInfo)); }
private RouteData GetRoute(HttpContext context, string virtualPath) { HttpContextWrapper contextWrapper = new HttpContextWrapper(context); // 利用ASP.NET Routing解析URL RouteData routeData = RouteTable.Routes.GetRouteData(contextWrapper); if (routeData == null) { DiagnoseResult diagnoseResult = Http404DebugModule.TryGetDiagnoseResult(context); if (diagnoseResult != null) { diagnoseResult.ErrorMessages.Add("URL不能与任何路由配置(RouteTable)匹配:" + virtualPath); diagnoseResult.RouteTestResult = (from x in RouteTable.Routes let route = x as Route where route != null select new TestResult { Text = route.Url, IsPass = false }).ToList(); } return(null); } if (routeData.RouteHandler != null && routeData.RouteHandler is StopRoutingHandler) { DiagnoseResult diagnoseResult = Http404DebugModule.TryGetDiagnoseResult(context); if (diagnoseResult != null) { diagnoseResult.ErrorMessages.Add("路由匹配成功,结果是一个StopRoutingHandler"); } return(null); } return(routeData); }
internal UrlActionInfo GetUrlActionInfo(RouteData routeData, HttpContext context) { if (routeData == null) { throw new ArgumentNullException("routeData"); } if (context == null) { throw new ArgumentNullException("context"); } // 采用ASP.NET Routing后,这三个参数都应该可以直接获取到, // 如果URL没有指定,可以通过默认值,或者DataToken指定, // 所以不需要像RestServiceModule那样重新计算 string nspace = GetRouteString(routeData, "namespace"); string className = GetRouteString(routeData, "controller"); string action = GetRouteString(routeData, "action"); if (string.IsNullOrEmpty(className) || string.IsNullOrEmpty(action)) { DiagnoseResult diagnoseResult = Http404DebugModule.TryGetDiagnoseResult(context); if (diagnoseResult != null) { diagnoseResult.ErrorMessages.Add("不能从URL中提取到controller和action信息"); } return(null); } if (action == "{HttpMethod}") // 允许定义这个特殊变量 { action = context.Request.HttpMethod; } ControllerResolver controllerResolver = new ControllerResolver(context); UrlActionInfo info = new UrlActionInfo(); info.RoutePattern = (routeData.Route as Route).Url; // 转换失败?? info.Namesapce = controllerResolver.GetNamespaceMap(nspace); info.ClassName = className; info.MethodName = action; info.Action = action; info.Controller = s_recognizer.GetServiceFullName(info); // 将路由提取到的其它URL参数,保存到UrlActionInfo实例中。 foreach (KeyValuePair <string, object> kvp in routeData.Values) { // 排除3个特定名字。 if (kvp.Key.IsSame("namespace") || kvp.Key.IsSame("controller") || kvp.Key.IsSame("action")) { continue; } string value = kvp.Value as string; if (string.IsNullOrEmpty(value) == false) { info.AddParam(kvp.Key, value); } } return(info); }