【问题标题】:Asp.net Mvc Route By Only SlugAsp.net Mvc 路由仅由 Slug
【发布时间】:2017-01-08 19:24:43
【问题描述】:

我正在使用带有 C# 的 ASP.NET MVC 4。我正在使用区域,它的名称类似于“管理员”

这是我的路线配置;

public static class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(name: "PageBySlug",
                        url: "{slug}",
                        defaults: new {controller = "Home", action = "RenderPage"},
                        constraints: new {slug = ".+"});

        routes.MapRoute(name: "Default",
                        url: "{controller}/{action}/{id}",
                        defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional},
                        namespaces: new[] { "Web.Frontend.Controllers.Controllers" });

    }
}

我生成了前端页面链接,例如; “产品/苹果-iphone” 所以我想这样称呼他们。

但错误是:代码无法获取控制器/动作方法。 我使用了前端页面链接,例如;

@Html.ActionLink(linkItem.Title, "RenderPage", routeValues: new {controller = "Home", slug = linkItem.PageSlug})
@Html.RouteLink(linkItem.Title, routeName: "PageBySlug", routeValues: new { controller = "Home", action = "RenderPage", slug = linkItem.PageSlug })
<a href="@Url.Action("RenderPage", "Home", new {slug = linkItem.PageSlug})">@linkItem.Title</a>
<a href="@Url.RouteUrl("PageBySlug", new { controller = "Home", action = "RenderPage", slug = linkItem.PageSlug})">@linkItem.Title</a>

他们正在渲染像这样的 url 链接; http://localhost:1231/products/apple-iphone 这就像我想要的一样。但是当我点击任何链接时,asp.net mvc 给了我这个错误:

“/”应用程序中的服务器错误。

找不到资源。

描述:HTTP 404。您要查找的资源(或其依赖项之一)可能已被删除、名称已更改或暂时不可用。请查看以下 URL 并确保其拼写正确。

请求的网址:/products/apple-iphone

版本信息:Microsoft .NET Framework 版本:4.0.30319; ASP.NET 版本:4.6.1069.1

这是我的控制器;

namespace Web.Frontend.Controllers
{
    public class HomeController : BaseFrontendController
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult RenderPage(string slug)
        {
            return View();
        }
    }   
}

那么我怎样才能像这个组合的 slug 一样捕获每个链接请求并打开我的编码视图?

【问题讨论】:

  • 我想 asp.net mvc 正在寻找一个名为“Products”的控制器,因为我正在使用“products/apple-iphone”、“services/repair-phones”等链接。但我需要“ /" 我的 url 中的字符用于 seo。我不想在链接中使用“products-apple-iphone”。
  • 所以您的预期行为是将值“products/apple-iphone”映射到 RenderPage 操作方法中的 slug 参数?
  • 是的...我现在正在像 menuSlug/pageSlug 一样开发。但我正在寻找一种最佳实践方法来做到这一点。

标签: c# asp.net asp.net-mvc asp.net-mvc-4


【解决方案1】:

问题是,当您请求products/iphone 时,路由引擎不知道您是指slug“products/iphone”还是控制器“products”和操作方法“iphone”。

您可以编写自定义路由约束来处理这个问题。这个约束会检查url的slug部分是否是一个有效的控制器,如果是,就会执行控制器动作。

public class SlugConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName,
                       RouteValueDictionary values, RouteDirection routeDirection)
    {
        var asm = Assembly.GetExecutingAssembly();
        //Get all the controller names
        var controllerTypes = (from t in asm.GetExportedTypes()
                               where typeof(IController).IsAssignableFrom(t)
                               select t.Name.Replace("Controller", ""));
        var slug = values["slug"];
        if (slug != null)
        {

            if (controllerTypes.Any(x => x.Equals(slug.ToString(),
                                                      StringComparison.OrdinalIgnoreCase)))
            {
                return false;
            }
            else
            {
                var c = slug.ToString().Split('/');
                if (c.Any())
                {
                    var firstPart = c[0];
                    if (controllerTypes.Any(x => x.Equals(firstPart, 
                            StringComparison.OrdinalIgnoreCase)))
                    {
                        return false;
                    }
                }
            }
            return true;
        }
        return false;
    }
}

现在,当您为 slug 注册自定义路由定义时,请使用此路由约束。确保在路由模式中使用 {*slug}* 表示它是任何东西(例如:“a/b/c”)(可变数量的 url 段 - 更像是一个包罗万象)

routes.MapRoute(name: "PageBySlug",
                            url: "{*slug}",
                            defaults: new { controller = "Home", action = "RenderPage" },
                      constraints: new { slug = new SlugConstraint() }    
                    , namespaces: new string[] { "Web.Frontend.Controllers.Controllers" });

routes.MapRoute(
             "Default",
             "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            , new string[] { "Web.Frontend.Controllers.Controllers" });

【讨论】:

  • 非常有用。这个答案值得喝啤酒!干杯
【解决方案2】:

您只能提供这种类型的链接

<a href="@Url.RouteUrl("PageBySlug", new {slug = linkItem.PageSlug})">@linkItem.Title</a>

因为 Routetable 使用您提供的路线名称找到您的路线。所以不需要控制器名称和动作名称。

【讨论】:

猜你喜欢
  • 2011-07-02
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 2011-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多