我想在CMS中为页面创建自定义标签,以便用户可以创建自己的SEO网址(例如Wordpress)。
我曾经在Ruby on Rails和PHP框架中通过“滥用” 404路由来做到这一点。当找不到请求的 Controller 时,将调用此路由,从而使用户能够将用户路由到我的动态页面 Controller ,以解析该消息(如果未找到页面,我将从那里重定向到真实的404)。这样,仅查询数据库以检查请求的段。
但是,在MVC中,仅当路由不符合/{controller}/{action}/{id}
的默认路由时,才调用全部路由。
为了仍然能够解析自定义子弹,我修改了RouteConfig.cs
文件:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
RegisterCustomRoutes(routes);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { Controller = "Pages", Action = "Index", id = UrlParameter.Optional }
);
}
public static void RegisterCustomRoutes(RouteCollection routes)
{
CMSContext db = new CMSContext();
List<Page> pages = db.Pages.ToList();
foreach (Page p in pages)
{
routes.MapRoute(
name: p.Title,
url: p.Slug,
defaults: new { Controller = "Pages", Action = "Show", id = p.ID }
);
}
db.Dispose();
}
}
这解决了我的问题,但是需要针对每个请求完全查询
Pages
表。由于重载的show方法(public ViewResult Show(Page p)
)不起作用,我还必须第二次检索页面,因为我只能传递页面ID。最佳答案
即使您的路由注册代码按原样工作,问题仍然是仅在启动时才静态注册路由。添加新帖子后会发生什么-您是否必须重新启动应用程序池?
您可以注册一个包含URL的SEO段子部分的路由,然后在查询中使用段子。RouteConfig.cs
routes.MapRoute(
name: "SeoSlugPageLookup",
url: "Page/{slug}",
defaults: new { controller = "Page",
action = "SlugLookup",
});
PageController.cs
public ActionResult SlugLookup (string slug)
{
// TODO: Check for null/empty slug here.
int? id = GetPageId (slug);
if (id != null) {
return View ("Show", new { id });
}
// TODO: The fallback should help the user by searching your site for the slug.
throw new HttpException (404, "NotFound");
}
private int? GetPageId (string slug)
{
int? id = GetPageIdFromCache (slug);
if (id == null) {
id = GetPageIdFromDatabase (slug);
if (id != null) {
SetPageIdInCache (slug, id);
}
}
return id;
}
private int? GetPageIdFromCache (string slug)
{
// There are many caching techniques for example:
// http://msdn.microsoft.com/en-us/library/dd287191.aspx
// http://alandjackson.wordpress.com/2012/04/17/key-based-cache-in-mvc3-5/
// Depending on how advanced you want your CMS to be,
// caching could be done in a service layer.
return slugToPageIdCache.ContainsKey (slug) ? slugToPageIdCache [slug] : null;
}
private int? SetPageIdInCache (string slug, int id)
{
return slugToPageIdCache.GetOrAdd (slug, id);
}
private int? GetPageIdFromDatabase (string slug)
{
using (CMSContext db = new CMSContext()) {
// Assumes unique slugs.
Page page = db.Pages.Where (p => p.Slug == requestContext.Url).SingleOrDefault ();
if (page != null) {
return page.Id;
}
}
return null;
}
public ActionResult Show (int id)
{
// Your existing implementation.
}
(仅供引用:未编译或未经测试的代码-目前尚未提供我的开发环境。将其视为伪代码;)
此实现将在每次服务器重新启动时搜索一个子段。您还可以在启动时预填充键值从到ID的键值高速缓存,因此所有现有的页面查找都将是廉价的。
关于c# - ASP.NET MVC : Routing custom slugs without affecting performance,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11494184/