我想在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。
  • 是否有更好的方法来解决我的问题?
  • 是否可以将Page对象而不是页面ID传递给我的Show方法?
  • 最佳答案

    即使您的路由注册代码按原样工作,问题仍然是仅在启动时才静态注册路由。添加新帖子后会发生什么-您是否必须重新启动应用程序池?

    您可以注册一个包含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/

    10-17 02:08