如何在给定控制器类型和lambda表达式的情况下创建RouteValueDictionary?

时间:2018-03-21 02:06:20

标签: c# asp.net-mvc reflection asp.net-mvc-routing

我已经有一些代码适用于大多数情况,但我有兴趣让它更可重复使用并适用于网站可能拥有的所有可能路由。

//--RouteBuilder.cs
public static RouteValueDictionary BuildRouteValueDictionary<TController>(Expression<Func<TController, System.Web.Mvc.ActionResult>> action)
    where TController : System.Web.Mvc.Controller => BuildRouteValueDictionary<TController>((LambdaExpression)action);
public static RouteValueDictionary BuildRouteValueDictionary<TController>(Expression<Func<TController, System.Web.Mvc.JsonResult>> action)
    where TController : System.Web.Mvc.Controller => BuildRouteValueDictionary<TController>((LambdaExpression)action);
private static RouteValueDictionary BuildRouteValueDictionary<TController>(LambdaExpression action)
    where TController : System.Web.Mvc.Controller
{
    //--Find the area and controller values for the given controller class
    var match = new Regex($@"^SomeSite\.(Areas\.(?<area>[a-zA-Z]+)\.)?Controllers\.(?<controller>[a-zA-Z]+)Controller$").Match(typeof(TController).FullName);
    if (match.Success)
    {
        var methodCall = (MethodCallExpression)action.Body;
        //--Compile/Invoke each action parameter that will be used as route values
        var routeValues = methodCall.Method.GetParameters()
            .Select((pi, i) => new
            {
                ParameterName = pi.Name,
                Value = Expression.Lambda(methodCall.Arguments[i]).Compile().DynamicInvoke()
            }).ToDictionary(x => x.ParameterName, x => x.Value);

        return new RouteValueDictionary(routeValues)
        {
            { "area", match.Groups["area"].Value },
            { "controller", match.Groups["controller"].Value },
            { "action", methodCall.Method.GetCustomAttributes(true).OfType<ActionNameAttribute>().FirstOrDefault()?.Name ?? methodCall.Method.Name }
        };
    }

    throw new InvalidOperationException("Cannot determine the route for the specified controller.");
}

//--This sits on a base controller
protected RedirectToRouteResult RedirectToRoute<TController>(Expression<Func<TController, ActionResult>> action)
    where TController : Controller =>
        RedirectToRoute(RouteBuilder.BuildRouteValueDictionary(action));

我一直在研究System.Web.Routing.RouteTable.Routes,这似乎非常适合将网址解析为控制器和操作,但实际上并非如此(除非我错过了某些内容)。希望能够获得特定于站点的正则表达式,并且能够处理重定向或URL生成的任何路由,同时能够享受lambdas对匿名对象和魔术字符串的编译时优势。真的,剩下的唯一问题是确定正确的区域名称。

0 个答案:

没有答案