Динамические маршруты из базы данных для ASP.NET MVC CMS
В основном у меня есть сервер CMS, который я создал с помощью ASP.NET MVC, и теперь я перехожу к сайту frontend и должен иметь возможность загружать страницы из моей базы данных cms на основе введенного маршрута.
Таким образом, если пользователь вводит domain.com/students/information, MVC будет искать в таблице страниц, чтобы увидеть, существует ли страница, которая имеет постоянную ссылку, которая соответствует учащимся/информации, если это так будет перенаправлено на контроллер страницы, а затем загрузите данные страницы из базы данных и верните их в представление для отображения.
До сих пор я пытался поймать весь маршрут, но он работает только для двух сегментов URL, так что/студентов/информации, но не /students/information/fall. Я не могу найти что-либо в Интернете о том, как это сделать, поэтому, хотя я бы спросил здесь, прежде чем найти и скомпилировать ASP.NET MVC с открытым исходным кодом и проанализировать код.
Вот конфигурация маршрута, которая у меня есть до сих пор, но я считаю, что есть лучший способ сделать это.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Default route to handle core pages
routes.MapRoute(null,"{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new { controller = "Index" }
);
// CMS route to handle routing to the PageController to check the database for the route.
var db = new MvcCMS.Models.MvcCMSContext();
//var page = db.CMSPages.Where(p => p.Permalink == )
routes.MapRoute(
null,
"{*.}",
new { controller = "Page", action = "Index" }
);
}
Если кто-нибудь может указать мне в правильном направлении, как я буду загружать страницы CMS из базы данных, до трех URL-сегментов и все еще иметь возможность загружать основные страницы, которые имеют предопределенный контроллер и действие.
Ответы
Ответ 1
Вы можете использовать ограничение, чтобы решить, следует ли переопределять логику маршрутизации по умолчанию.
public class CmsUrlConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var db = new MvcCMS.Models.MvcCMSContext();
if (values[parameterName] != null)
{
var permalink = values[parameterName].ToString();
return db.CMSPages.Any(p => p.Permalink == permalink);
}
return false;
}
}
используйте его в определении маршрута, например,
routes.MapRoute(
name: "CmsRoute",
url: "{*permalink}",
defaults: new {controller = "Page", action = "Index"},
constraints: new { permalink = new CmsUrlConstraint() }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Теперь, если у вас есть действие "Index" в "Page" контроллере, например,
public ActionResult Index(string permalink)
{
//load the content from db with permalink
//show the content with view
}
- все URL-адреса будут пойманы по первому маршруту и будут проверены ограничением.
- Если постоянная ссылка существует в db, то URL-адрес будет обрабатываться указателем в контроллере страницы.
- Если не будет сдерживать ограничение, и url вернется к маршруту по умолчанию (я не знаю, есть ли у вас какие-либо другие контроллеры в проекте и как вы решите свою логику 404).
ИЗМЕНИТЬ
Чтобы избежать запроса страницы cms в Index
в контроллере Page
, можно использовать словарь HttpContext.Items
, например
в ограничении
var db = new MvcCMS.Models.MvcCMSContext();
if (values[parameterName] != null)
{
var permalink = values[parameterName].ToString();
var page = db.CMSPages.Where(p => p.Permalink == permalink).FirstOrDefault();
if(page != null)
{
HttpContext.Items["cmspage"] = page;
return true;
}
return false;
}
return false;
то в действии
public ActionResult Index(string permalink)
{
var page = HttpContext.Items["cmspage"] as CMSPage;
//show the content with view
}
надеюсь, что это поможет.
Ответ 2
Я использую более простой подход, который не требует никакой специальной обработки маршрутизатора. Просто создайте один/глобальный контроллер, который обрабатывает несколько необязательных параметров, затем обработайте эти параметры так, как вам нравится:
//Route all traffic through this controller with the base URL being the domain
[Route("")]
public class MyController : Controller
{
//Define up to 5 optional patrameters
[HttpGet("{a1?}/{a2?}/{a3?}/{a4?}/{a5?}")]
public async Task<JsonResult> APIGet(string a1 = "", string a2 = "", string a3 = "", string a4 = "", string a5 = "")
{
//Custom logic processing each of the route variables
return Json(new string[] { a1, a2, a3, a4, a5 });
}
}
Пример вывода на domain.com/test1/test2
["test1","test2","","",""]