Asp.net

.NET MVC-4 路由與自定義 slug

  • October 30, 2013

我正在用 ASP.Net MVC 4 重寫一個網站項目,我發現很難設置正確的路線。url 結構不是 RESTful 或遵循控制器/操作模式 - 頁面具有以下 slug 結構。所有 slug 都保存在數據庫中。

/country
/country/carmake
/country/carmake/carmodel
/custom-landing-page-slug
/custom-landing-page-slug/subpage

例子:

/italy
/italy/ferrari
/italy/ferrari/360
/history-of-ferrari
/history-of-ferrari/enzo

因為Country和是不同的模型/實體Car MakeCar Model所以我希望有類似 CountryController、CarMakesController 和 CarModelsController 之類的東西,我可以在其中處理不同的邏輯並從中呈現適當的視圖。此外,我有自定義登錄頁面,其中可以包含一個或多個斜杠。

我的第一次嘗試是有一個包羅萬象的PagesController方法,它會在數據庫中查找 slug 並根據頁麵類型(例如CarMakesController)呼叫適當的控制器,然後執行一些邏輯並呈現視圖。然而,我從來沒有成功地“呼叫”另一個控制器並渲染適當的視圖——而且感覺不對。

誰能在這裡指出我正確的方向?謝謝!

編輯:澄清:我不想要重定向 - 我想將請求委託給不同的控制器來處理邏輯和呈現視圖,具體取決於內容的類型(CountryCarMake)。

由於您的連結看起來很相似,因此您無法在路由級別將它們分開。但這裡有個好消息:您可以編寫自定義路由處理程序而忘記典型的 ASP.NET MVC 連結解析。

首先,讓我們追加RouteHandler到預設路由:

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

這允許您以不同的方式操作您的 URL,例如:

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;
   }
}

這裡需要一些解釋。

首先,您的處理程序應該派生MvcRouteHandlerSystem.Web.Mvc.

PageItem代表我的數據庫結構,其中包含有關 slug 的所有必要資訊:

PageItem 結構

ContentID是內容表的外鍵。

GetStatic是動作的預設值,在我的情況下很方便。

RedirectManager是一個與數據庫一起使用的靜態類:

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;
       }
   }
}

使用這個程式碼庫,你可以添加所有的限制、異常和奇怪的行為。

它在我的情況下有效。希望這對你有幫助。

引用自:https://stackoverflow.com/questions/19611863