2011-07-17 51 views
0

我真的很喜欢ASP.NET MVC 3框架。或者至少,它确实比试图用ASP.NET 3.5或4.0来愚弄更好。但是,我只是对某些事情感到困惑。他们为什么选择用字符串指定路线?指定ASP.NET MVC 3路线符号

IOW,我告诉我的指定的路线是这样的(例如):

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

这条路线相匹配的ProductsController.List()方法。假设我处于重构心态,并且想要将我的ProductsController重命名为InventoryController。在使用我选择的重命名工具后,我打开Global.aspx并遍历所有路线并将所有这些愚蠢的字符串更改为“Inventory”。你可能会回应,我可以做一个查找和替换......但来吧!我觉得这是最后一代的答案。

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

尽管如此,一个选项将是反思。会有这样的性能打击吗?我想MVC框架必须在该产品字符串上使用反射来获得我的产品控制器,所以......但是,您也必须删除类型名称中的“控制器”部分,如下所示:

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

我可以使用下面的辅助函数,使之成为小机:

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

标杆是为了,如果这是为了避免这些字符串的唯一途径......不过,这是愚蠢的。我在一个类型上使用反射来获得一个MVC将与反射结合使用的字符串,以获得我原来首先使用的类型。

是否有某些原因不采取下一步(逻辑?)步骤并让控制器和操作属性直接指望类型和委托?这难道不是简单清晰吗?就我所知,MVC的一个基本方面是约定优于配置,但使用这些字符串进行路由似乎只是对我的配置形式。

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

当我用这种方式使用字符串的时候,我是否还在憎恨它?我仍然认为C#需要类似于Ruby的符号和Lisp的关键字,以便我们的重构工具可以利用。有点像枚举值名称同时是值的“字符串枚举”。

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

谢谢 Jeromeyers

回答

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() 
    ) 
); 

现在,您可以根据自己的喜好重新命名控制器和操作。

+0

太棒了,就是我在找的东西。然而,当你说你因为单元测试而没有任何问题时,我仍然认为由于不得不用这些字符串来中断开发流程。如果单元测试失败(因为它会),那么你将不得不和你的路线一起去,而不是让你的重命名自动处理它。我尽可能地避免这些无关的步骤,这些步骤有助于在我开发的过程中破坏我在工作中与我一起工作的不断变化的卡片屋。 – jeromeyers

+0

快速提问:为什么我们最初使用MapRoute并将“Default”的值作为第一个参数,然后在自定义路径中使用Add方法并忽略提供“Default”参数? – jeromeyers

+0

@ jeromeyers,这是路线的名称。如果你想:'routes.Add(“Default”,new IHateMagicStringsRoute (...));' –