【问题标题】:C# Mvc Generic Route using Slug使用 Slug 的 C# Mvc 通用路由
【发布时间】:2016-09-08 15:37:55
【问题描述】:

我正在尝试创建一个通用路由来处理 slug,但我总是遇到错误

这个想法是,而不是 www.site.com/controller/action 我在网址中得到一个友好的 www.site.com/{slug}

例如www.site.com/Home/Open 将改为 www.site.com/open-your-company

错误

“/”应用程序中的服务器错误找不到资源

在我的 Global.asax 我有

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

    routes.MapRoute("DefaultSlug", "{slug}", new { controller = "Home", action = "Open", slug = "" });
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new
        {
            area = "",
            controller = "Home",
            action = "Index",
            id = UrlParameter.Optional,
            slug = ""
        }
    );
}

在我的cshtml 之一中,我有以下链接(即使已评论,仍然存在相同的错误)。

@Html.ActionLink("Open your company", "DefaultSlug", new { controller = "Home", action = "Open", slug = "open-your-company" })

编辑:家庭控制器

public ActionResult Open() { 
    return View(new HomeModel()); 
}

【问题讨论】:

  • 显示DefaultSlug Route 映射到的动作。
  • 动作是Open inside Home public ActionResult Open() { return View(new HomeModel()); }
  • 但我想你明白了,我看到 HomeModel 内部有一些参数正在按位置访问 url。现在测试一下
  • 您的操作链接正确。由于它的配置方式,它只是没有映射到正确的路线。

标签: c# asp.net-mvc routes slug


【解决方案1】:

在 Global.asax 中slug 不能为空,如果为空,则 url 不会转到默认路由

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

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

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new
        {
            area = "",
            controller = "Home",
            action = "Index",
            id = UrlParameter.Optional
        }
    );
}

并更新 HomeController

public ActionResult Open(string slug) {
    HomeModel model = contentRepository.GetBySlug(slug);

    return View(model); 
}

测试路线链接...

@Html.RouteLink("Open your company", routeName: "DefaultSlug", routeValues: new { controller = "Home", action = "Open", slug = "open-your-company" })

和操作链接...

@Html.ActionLink("Open your company", "Open", routeValues: new { controller = "Home", action = "Open", slug = "open-your-company" })

两者都产生...

http://localhost:35979/open-your-company

【讨论】:

  • 仍在测试,但此代码不会创建“控制器/动作?slug”?我试图获得类似 www.site.com/slug 而不是“www.site.com/controller/action”
  • 然后使用您在帖子中使用的原始操作链接格式,您可以在其中按名称调用路线DefaultSlug
  • 这是我正在尝试的,但似乎没有用,错误仍然存​​在。有什么想法吗?
  • 我认为错误是因为我使用的是 ActionLink 而不是我应该使用 RouteLink ...尝试一些代码来查看是否有效。
  • 在 html @Html.RouteLink("Open company", "DefaultSlug", new { slug = "open-your-company", controller = "Home", action = "Open" }) in the asax routes.MapRoute( name: "DefaultSlug", url: "{slug}", defaults: new { slug = "", controller = "Home", action = "Open" } ); 我只是不知道如何使它成为一条普通路线,或者至少不需要通过 controlleraction也在 html 中(删除导致同样的错误)
【解决方案2】:

这是我为完成类似任务所采取的步骤。这依赖于模型上的自定义 Slug 字段来匹配路由。

  1. 设置您的控制器,例如控制器\PagesController.cs:

    public class PagesController : Controller
    {
        // Regular ID-based routing
        [Route("pages/{id}")]
        public ActionResult Detail(int? id)
        {
            if(id == null)
            {
                return new HttpNotFoundResult();
            }
    
            var model = myContext.Pages.Single(x => x.Id == id);
            if(model == null)
            {
                return new HttpNotFoundResult();
            }
            ViewBag.Title = model.Title;
            return View(model);
        }
    
        // Slug-based routing - reuse View from above controller.
        public ActionResult DetailSlug (string slug)
        {
            var model = MyDbContext.Pages.SingleOrDefault(x => x.Slug == slug);
            if(model == null)
            {
                return new HttpNotFoundResult();
            }
            ViewBag.Title = model.Title;
            return View("Detail", model);
        }
    }
    
  2. 在 App_Start\RouteConfig.cs 中设置路由

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            // Existing route register code
    
            // Custom route - top priority
            routes.MapRoute(
                    name: "PageSlug", 
                    url: "{slug}", 
                    defaults: new { controller = "Pages", action = "DetailSlug" },
                    constraints: new {
                        slug = ".+", // Passthru for no slug (goes to home page)
                        slugMatch = new PageSlugMatch() // Custom constraint
                    }
                );
            }
    
            // Default MVC route setup & other custom routes
        }
    }
    
  3. 自定义 IRouteConstraint 实现,例如Utils\RouteConstraints.cs

    public class PageSlugMatch : IRouteConstraint
    {
        private readonly MyDbContext MyDbContext = new MyDbContext();
    
        public bool Match(
            HttpContextBase httpContext,
            Route route,
            string parameterName,
            RouteValueDictionary values,
            RouteDirection routeDirection
        )
        {
            var routeSlug = values.ContainsKey("slug") ? (string)values["slug"] : "";
            bool slugMatch = false;
            if (!string.IsNullOrEmpty(routeSlug))
            {
                slugMatch = MyDbContext.Pages.Where(x => x.Slug == routeSlug).Any();
            }
            return slugMatch;
        }
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-28
    • 1970-01-01
    • 2011-07-02
    • 2020-12-03
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多