0

嗨,我一直在尝试解决一个与路由和链接有关的问题,但没有运气。

我有一个存储许多书籍的应用程序。每本书都有显示其详细信息的链接。为了获得详细信息,我在链接中使用每本书的 ID。这是链接的代码:

@Html.ActionLink(book.Name, "Details", new { bookId = book.Id , book = book.BookUrl })

当用户单击其中一个链接时,这是正在调用的控制器,我不允许修改它:

 public ActionResult Details (int bookId){..}

这就是我的链接的显示方式:

http://localhost:51208/Home/Details/C-sharp-5.0-in-a-Nutshell-The-Definitive-Reference/BookId-2

我想要以某种方式停止显示控制器操作和 BookId。所以我的链接看起来像这样:

http://localhost:51208/C-sharp-5.0-in-a-Nutshell-The-Definitive-Reference

据我所知,到目前为止,没有办法使用路由的标准功能来做到这一点,所以我想我必须以某种方式扩展它的功能。

我一直在PRO ASP.NET MVC 4中阅读有关此内容的内容,并且根据我所阅读的内容,我必须创建一个类并从RouteBase.

这将导致必须实现两种方法,一种是RouteData GetRouteData(HttpContextBase httpContext),另一种是VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)

到目前为止,我只知道它GetVirtualPath负责生成链接,所以我认为这是我必须创建实现以获得我想要的功能的地方。

如果是这种情况,有人可以告诉我应该如何实现这种方法吗?

如果这不是要走的路线,那么我怎样才能实现我想要的呢?

4

2 回答 2

2

你可以在你RouteConfig.cs的下面添加一条额外的路线:

    routes.MapRoute(
        "Book Details", // Route name
        "{ bookName }", // URL with parameters
             new { controller = "BookController",
                   action = "Details", 
                   name = UrlParameter.Optional
                 } // Parameter defaults
        );

相应地更改您的Details方法,但其参数必须是bookName.

笔记 :

将此路线放在您为避免歧义而定义的所有路线的底部。

于 2013-03-13T12:41:20.023 回答
1

您可以通过实现自己的 RouteBase 版本来做到这一点。您需要同时实现GetRouteDataGetVirtualPath

您的实现GetRouteData需要检查您的图书数据库,以查看 URL 是否包含数据库中的图书名称,然后返回正确的路线数据,例如

public class BookRoute : RouteBase
{
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var url = httpContext.Request.AppRelativeCurrentExecutionFilePath;
        url = url.Replace(@"~/", "");

        var book = getBookWithTheNameThatMatchesTheUrl(url);

        if (book != null)
        {
            var rd = new RouteData(this, new MvcRouteHandler());
            rd.Values.Add("controller", "Home");
            rd.Values.Add("action", "Details");
            rd.Values.Add("bookId", book.Id);
            return rd;
        }

        return null;
    }

并且您的实现GetVirtualPath需要做相反的事情 - 找到具有给定 ID 的书名,并返回适当的 URL。

例如

public override VirtualPathData GetVirtualPath(RequestContext requestContext, 
                                               RouteValueDictionary values)
{
    if ((string)values["action"] == "Details" && 
        (string)values["controller"] == "Home")
    {
        var bookId = (int)values["bookId"];
        var bookName = LookUpTheBookNameForTheBookWithThisId(bookId);
        return new VirtualPathData(this, bookName);    
    }

    return null;
}

最后,添加routes.Add(new BookRoute());您注册路由的位置以启用检查此新路由。

鉴于该方法getBookWithTheNameThatMatchesTheUrl()会针对每个页面访问数据库,因此您需要缓存查找。

于 2013-03-14T03:42:26.793 回答