2009年9月21日月曜日

Routeでデフォルト省略させたくない

GenerateLink does not return the control name and the view name only for the INDEX view - Stack Overflow

これってデフォルト値と同じパラメータを省略(後方に有効値パラメータ無しの場合)させずに、URLを取得出来るようになればいい、っていう問題だったり?

  routes.MapRoute(
    "Default",                                              // Route name
    "{controller}/{action}/{id}",                           // URL with parameters
    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
  );

↑こういう登録をしてる場合に、

  var url1 = Url.RouteUrl("default");
  var url2 = Url.RouteUrl("default", new { controller="Home" });
  var url3 = Url.RouteUrl("default", new { controller = "Home", action="Index" });

↑これは全部"/"と出力されるけど、これが"/Home/Index"になって欲しい、と。違うなら意味なくなっちゃうからそういう質問だと仮定。

やっぱりRouteクラスを派生させてGetVirtualPathのoverrideでしょ!

  public class FullRoute : Route
  {
    public FullRoute(string url, IRouteHandler routeHandler): 
base(url, routeHandler) { } public FullRoute(string url, RouteValueDictionary defaults,
IRouteHandler routeHandler):
base(url, defaults, routeHandler) { } public FullRoute(string url, RouteValueDictionary defaults,
  RouteValueDictionary constraints, IRouteHandler routeHandler):
base(url, defaults, constraints, routeHandler) { } public FullRoute(string url, RouteValueDictionary defaults,
RouteValueDictionary constraints, RouteValueDictionary dataTokens,
IRouteHandler routeHandler):
base(url, defaults, constraints, dataTokens, routeHandler) { } public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { var dict = new RouteValueDictionary(Defaults); values.ToList().ForEach(kv=>dict[kv.Key] = kv.Value); var url = Url; dict.ToList().ForEach(kv => url = url.Replace(string.Format("{{{0}}}", kv.Key), (string)kv.Value)); url = Regex.Replace(url, @"{([\w].+)?}", ""); url = Regex.Replace(url, @"(\/){2,}", ""); var path = base.GetVirtualPath(requestContext, values); path.VirtualPath = url; return path; } }

※途中のパラメータが空白の時は考慮してないのであしからず。なんかthrowすべきだよね~。

これを使うようにRouteTableに追加。

  routes.Add("FullDefault",
    new FullRoute(
      "{controller}/{action}/{id}/{foo}/{bar}",

      new RouteValueDictionary(new { controller = "Home", action = "Index", id = "", foo = "", bar = "" }),
      new RouteValueDictionary(),
      new MvcRouteHandler()
  ));

※idより後ろのパラメータは特に意味なしデス。

そうすると

  var full1 = Url.RouteUrl("fulldefault");
  var full2 = Url.RouteUrl("fulldefault", new { controller = "Home" });
  var full3 = Url.RouteUrl("fulldefault", new { controller = "Home", action = "Index" });

これが全部"/Home/Index"を返すようになります。

こういう事でいいんですかね?って英語でどうやって答えればいいのか分からない...。