以符号方式指定ASP.NET MVC 3路由

时间:2011-07-17 11:17:57

标签: asp.net-mvc-3 asp.net-mvc-routing

我非常喜欢ASP.NET MVC 3框架。或者至少,它肯定比试图愚弄ASP.NET 3.5或4.0无比好。但是,我真的很困惑。他们为什么选择指定带字符串的路由?

IOW,我被告知要指定我的路线(例如):

... new { controller = "Products", action = "List", id = UrlParameter.Optional }

此路由与ProductsController.List()方法匹配。假设我处于重构的状态,我想将ProductsController重命名为InventoryController。在使用我选择的重命名工具后,我打开了Global.aspx并浏览了所有路径,并将所有这些愚蠢的字符串更改为“库存”。您可能会回答我可以进行查找和更换......但请加油!我觉得这是上一代的答案。

我喜欢重构我的代码,因为我更了解我的域名。我不想使用愚蠢的(我说愚蠢,因为它们对编译器没有意义)字符串来引用符号/语义代码构造,这些构造完全对应于最终存储在符号表中的类型和方法名称。有什么意义?为什么要打扰类型呢?让我们回到使用关联数组和字典来编写脚本来表示我们的域模型......在我看来,当我们将它与字符串引用混合时,强类型的好处会大大减少。

但说真的,一个选择就是反思。会有这样的表现吗?我想MVC框架必须使用对“Products”字符串的反射来获取我的ProductsController,所以......但是,你还必须删除类型名称的“Controller”部分,如下所示:

= typeof(ProductsController).Name.Replace("Controller", string.Empty)

我可以使用以下辅助函数来使它成为一个小的DRYer:

public string GetControllerName(Type controller)
{
    return controller.Name.Replace("Controller", string.Empty);
}

基准测试是有序的,如果这是避免这些字符串的唯一方法......仍然,这是愚蠢的。我在一个类型上使用反射来获取MVC将与反射结合使用的字符串,以获得我最初所拥有的类型。

是否有一些理由不采取下一个(逻辑?)步骤并让控制器和操作属性直接期望类型和代理?这不会更简洁,更清晰吗?据我所知,MVC的一个基本方面是约定优于配置,但使用这些字符串的路由对我来说似乎是一种偷偷摸摸的配置形式。

还有另一种解决方法吗?我还是MVC的新手。我读过我们可以替换这些路由组件。有谁知道是否有可能做我正在谈论的事情?如果不可能,那么......我一个人在这里吗?我错过了什么吗?一些最重要的原因是为什么这些路线必须由哑弦设定?如果没有,这可能是为了游说吗?

当我以这种方式使用字符串时,我是否一直在讨厌它?我仍然认为C#需要类似于Ruby的符号和我们的重构工具可以利用的Lisp关键字。类似于“字符串枚举”的类似,其中枚举值名称同时是值。

我理解这个问题的部分内容是主观的,但我也在寻找关于是否可以直接使用类型和代理来指定这些路由配置的客观答案。

谢谢你, Jeromeyers

1 个答案:

答案 0 :(得分:1)

我个人从来没有遇到路线定义方式的问题,因为我总是unit test them。因此,如果我处于重构的情绪中,我的单元测试总能保证路线的行为符合我的要求。

当然,如果您对ASP.NET MVC团队设计框架的方式仍然不满意(不要犹豫是否打开机票并在未来版本中投票改进),您可以随时编写自定义路线:

public class IHateMagicStringsRoute<T> : Route where T : Controller
{
    public IHateMagicStringsRoute(
        string url,
        Expression<Func<T, ActionResult>> expression
    ) : base(url, Parse(expression), new MvcRouteHandler())
    { }

    private static RouteValueDictionary Parse(Expression<Func<T, ActionResult>> expression)
    {
        var mce = expression.Body as MethodCallExpression;
        if (mce != null)
        {
            return new RouteValueDictionary(new
            {
                controller = typeof(T).Name.Replace("Controller", ""),
                action = mce.Method.Name
            });
        }
        return null;
    }
}

然后代替:

routes.MapRoute(
    "Default",
    "{controller}/{action}",
    new { controller = "Home", action = "Index" }
);
你可以:

routes.Add(
    new IHateMagicStringsRoute<HomeController>(
        "{controller}/{action}",
        x => x.Index()
    )
);

现在您可以根据需要重命名控制器和操作。