/// <summary> /// Builds a URL based on the Expression passed in /// </summary> /// <typeparam name="TController">Controller Type Only</typeparam> /// <param name="context">The current ViewContext</param> /// <param name="routeCollection">The <see cref="RouteCollection"/> to use for building the URL.</param> /// <param name="action">The action to invoke</param> /// <returns></returns> public static string BuildUrlFromExpression <TController>(RequestContext context, RouteCollection routeCollection, Expression <Action <TController> > action) where TController : Controller { // 4/4/2016 RL: We could not simply just use RouteValueDictionary routeValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action) because it is not Area aware; // so we had to get the guts of that method call and do it ourself to make it respect areas var body = action.Body as MethodCallExpression; Check.RequireNotNull(body, "MvcResources.ExpressionHelper_MustBeMethodCall"); // ReSharper disable PossibleNullReferenceException var actionName = GetTargetActionName(body.Method); // ReSharper restore PossibleNullReferenceException var controllerType = typeof(TController); var controllerName = SitkaController.ControllerTypeToControllerName(controllerType); var routeValues = GetRouteValuesFromExpression(body, controllerType.Namespace, controllerName, actionName); var vpd = routeCollection.GetVirtualPath(context, routeValues); if (vpd == null) { return(null); } var routeUrl = vpd.VirtualPath; return(routeUrl); }
public SitkaRoute(Expression <Action <T> > routeExpression) { RouteExpression = routeExpression; ControllerName = SitkaController.ControllerTypeToControllerName(typeof(T)); Body = GetRouteExpressionBody(routeExpression); var actionName = Body.Method.Name; var attributes = Body.Method.GetCustomAttributes(typeof(ActionNameAttribute), false); if (attributes.Length > 0) { var actionNameAttr = (ActionNameAttribute)attributes[0]; actionName = actionNameAttr.Name; } ActionName = actionName; }
private static IEnumerable <SitkaRouteTableEntry> MakeRoutesForSingleMethod(Dictionary <string, string> areasDictionary, MethodInfo controllerActionMethod, Dictionary <string, List <string> > getMethodsDict) { var sitkaRouteEntries = new List <SitkaRouteTableEntry>(); var controller = SitkaController.ControllerTypeToControllerName(controllerActionMethod.ReflectedType); var controllerPartForUrl = SitkaController.ControllerTypeToControllerNameForUrl(controllerActionMethod.ReflectedType); var isRestrictedToPost = IsRestrictedToPost(controllerActionMethod); var httpPostRouteSuffix = (isRestrictedToPost ? "__HttpPost" : ""); var action = controllerActionMethod.Name; var routeName = $"{controller}__{action}{httpPostRouteSuffix}"; var allParameters = controllerActionMethod.GetParameters(); var controllerAndAction = $"{controller}.{action}"; var parameterString = String.Join(",", allParameters.Select(x => $"{x.ParameterType.FullName} {x.Name}")); var actionControllerNameWithParameters = $"{controller}\t{action}\t{parameterString}"; if (!isRestrictedToPost) { AssertOptionalParametersAreOnlyAtEndOfRoute(routeName, allParameters); if (!getMethodsDict.ContainsKey(controllerAndAction)) { getMethodsDict.Add(controllerAndAction, new List <string>()); } getMethodsDict[controllerAndAction].Add(actionControllerNameWithParameters); } else { if (getMethodsDict.ContainsKey(controllerAndAction)) { if (!getMethodsDict[controllerAndAction].Any(actionControllerNameWithParameters.StartsWith)) { var allGetRoutes = String.Join("\r\n", getMethodsDict[controllerAndAction]); throw new ApplicationException($"The POST route {controllerAndAction} must have a corresponding GET route with the same parameters\r\nPOST route: {actionControllerNameWithParameters}\r\nGET routes: {allGetRoutes}"); } } } // see if it has a route attribute defined; if so, use that as the route url var routeAttribute = controllerActionMethod.GetCustomAttributes <RouteAttribute>(false).SingleOrDefault(); // Now add in all the variants of the route based on parameter overloading // /Foo.mvc/Action/1 => FooController.Action(1) var appendParameters = allParameters.OrderBy(p => p.Position).ToList(); var crossAreaRouteAttribute = controllerActionMethod.GetCustomAttributes <CrossAreaRouteAttribute>(false).SingleOrDefault(); var isCrossAreaRoute = crossAreaRouteAttribute != null; if (areasDictionary == null || !areasDictionary.Any()) { CreateSitkaTableRouteEntry(controllerActionMethod, appendParameters, routeAttribute, action, controller, routeName, sitkaRouteEntries, controllerPartForUrl, null, null, false); } else { if (isCrossAreaRoute) { foreach (var areaKey in areasDictionary.Keys) { CreateSitkaTableRouteEntry(controllerActionMethod, appendParameters, routeAttribute, action, controller, routeName, sitkaRouteEntries, controllerPartForUrl, areaKey, areasDictionary[areaKey], true); } } else { var area = SitkaController.ControllerTypeToAreaName(controllerActionMethod.ReflectedType); Check.Require(areasDictionary.ContainsKey(area), string.Format("Area \"{0}\" not found in Areas Dictionary!", area)); var areaAsSubdomainName = areasDictionary[area]; CreateSitkaTableRouteEntry(controllerActionMethod, appendParameters, routeAttribute, action, controller, routeName, sitkaRouteEntries, controllerPartForUrl, area, areaAsSubdomainName, false); } } return(sitkaRouteEntries); }