.NET MVC-4 routing with custom slugs

前端 未结 1 903
慢半拍i
慢半拍i 2020-12-04 20:14

I\'m rewriting a website project with ASP.Net MVC 4 and I find it difficult to setup the right routes. The url structure is not RESTful or following a controller/action patt

相关标签:
1条回答
  • 2020-12-04 21:02

    Since your links looks similar, you can't separate them at the routing level. But here are good news: you can write custom route handler and forget about typical ASP.NET MVC links' parsing.

    First of all, let's append RouteHandler to default routing:

    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "Default", action = "Index", id = UrlParameter.Optional }
    ).RouteHandler = new SlugRouteHandler();
    

    This allows you to operate with your URLs in different ways, e.g.:

    public class SlugRouteHandler : MvcRouteHandler
    {
        protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            var url = requestContext.HttpContext.Request.Path.TrimStart('/');
    
            if (!string.IsNullOrEmpty(url))
            {
                PageItem page = RedirectManager.GetPageByFriendlyUrl(url);
                if (page != null)
                {
                    FillRequest(page.ControllerName, 
                        page.ActionName ?? "GetStatic", 
                        page.ID.ToString(), 
                        requestContext);
                }
            }
    
            return base.GetHttpHandler(requestContext);
        }
    
        private static void FillRequest(string controller, string action, string id, RequestContext requestContext)
        {
            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }
    
            requestContext.RouteData.Values["controller"] = controller;
            requestContext.RouteData.Values["action"] = action;
            requestContext.RouteData.Values["id"] = id;
        }
    }
    

    Some explanations are required here.

    First of all, your handler should derive MvcRouteHandler from System.Web.Mvc.

    PageItem represents my DB-structure, which contains all the necessary information about slug:

    PageItem structure

    ContentID is a foreign key to contents table.

    GetStatic is default value for action, it was convenient in my case.

    RedirectManager is a static class which works with database:

    public static class RedirectManager
    {
        public static PageItem GetPageByFriendlyUrl(string friendlyUrl)
        {
            PageItem page = null;
    
            using (var cmd = new SqlCommand())
            {
                cmd.Connection = new SqlConnection(/*YourConnectionString*/);
                cmd.CommandText = "select * from FriendlyUrl where FriendlyUrl = @FriendlyUrl";
                cmd.Parameters.Add("@FriendlyUrl", SqlDbType.NVarChar).Value = friendlyUrl.TrimEnd('/');
    
                cmd.Connection.Open();
                using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
                {
                    if (reader.Read())
                    {
                        page = new PageItem
                                   {
                                       ID = (int) reader["Id"],
                                       ControllerName = (string) reader["ControllerName"],
                                       ActionName = (string) reader["ActionName"],
                                       FriendlyUrl = (string) reader["FriendlyUrl"],
                                   };
                    }
                }
    
                return page;
            }
        }
    }
    

    Using this codebase, you can add all the restrictions, exceptions and strange behaviors.

    It worked in my case. Hope this helps in yours.

    0 讨论(0)
提交回复
热议问题