public virtual void SerializeToPath(IRouteAction action, IPathStack path) { // TODO: child action binding if (_handlers == null) return; IPathStack bestStack = null; foreach (ActionHandler handler in _handlers) { if (handler.Action == action.Method) { IPathStack trialStack = new PathStack(false); handler.Binding.SerializePath(trialStack, action.Parameters); if (action.ChildAction != null) { if (!(handler is ParentActionHandler)) throw new BindingException("Method is not a parent action and can't handle further calls."); } else { if (handler is ParentActionHandler) throw new BindingException("Method is a parent action. You should add the default sub-action."); } if (trialStack.Index == 0) trialStack.TrailingSlash = !DisableTrailingSlash; if (bestStack == null || trialStack.Index > bestStack.Index || (trialStack.Index == bestStack.Index && trialStack.QueryString.Count > bestStack.QueryString.Count)) bestStack = trialStack; } } if (bestStack != null) { path.Push(bestStack); } else throw new BindingException(String.Format("Method \"{0}\" is not bindable.", action.Method.Name)); }
private void SerializePath(IRouteAction action, IPathStack path, bool requireEntry) { IControllerBinding[] bindings = GetControllerBindings(action.ControllerType); if (bindings == null || bindings.Length == 0) throw new BindingException(String.Format("Type \"{0}\" is not bindable.", action.ControllerType.FullName)); IPathStack bestStack = null; foreach (IControllerBinding b in bindings) if (!requireEntry || b is IEntryControllerBinding) { IPathStack trialStack = new PathStack(false); if (requireEntry) ((IEntryControllerBinding)b).SerializeToPath(action, trialStack); else b.SerializeToPath(action, trialStack); IRouteAction childAction = action.ChildAction; if (childAction != null) { SerializePath(childAction, trialStack, false); } if (bestStack == null || trialStack.Index > bestStack.Index || (trialStack.Index == bestStack.Index && trialStack.QueryString.Count > bestStack.QueryString.Count)) bestStack = trialStack; } if (bestStack != null) { path.Push(bestStack); } else throw new BindingException(String.Format("Type \"{0}\" is not a bindable EntryController.", action.ControllerType.FullName)); }
public virtual bool TryBinding(IHttpContext context, IPathStack path, object controller, out IHttpHandler handler) { if (_handlers == null) { handler = null; return false; } int bestIndex = -1; int bestOverloadWeight = -1; object[] bestParameters = null; ActionHandler bestHandler = null; int index = path.Index; object[] parameters; int overloadWeight; foreach (ActionHandler h in _handlers) { if (h.Binding.TryBinding(context, path, out parameters, out overloadWeight) && (overloadWeight > bestOverloadWeight || ( overloadWeight == bestOverloadWeight && parameters.Length < bestParameters.Length //The fewer parameters the better if same overload weight )) && (path.IsAtEnd || h is ParentActionHandler)) { bestIndex = path.Index; bestHandler = h; bestParameters = parameters; bestOverloadWeight = overloadWeight; } path.ReverseToIndex(index); } if (bestHandler == null) { handler = null; return false; } // shouldTrailSlash = bestIndex == index; I.e. the best mapping hasn't used a path if (bestIndex == index ^ path.TrailingSlash ^ DisableTrailingSlash && !(bestHandler is ParentActionHandler) && context.Request.HttpMethod == "GET") { // TODO: Make more efficient by simply extracting the final path section and use relative redirect: ../pathsection or ./pathsection/ IPathStack newPath = new PathStack(false); newPath.Push(path); newPath.TrailingSlash = !path.TrailingSlash; context.Route.Dispose(); context.Response.Redirect("~/" + newPath.ToString(), false); context.Response.StatusCode = 301; context.Response.End(); } path.ReverseToIndex(bestIndex); if (controller == null) controller = _controllerCreator(); context.Route.AddController(controller, index); // Controller is bound, add it to the route context handler = bestHandler.GetHttpHandler(context, controller, bestParameters); return true; }