Creating Canonical URLs including an id and title slug

我的未来我决定 提交于 2019-12-03 21:43:01

The way that I've handled this before is to have two routes, registered in this order

routes.MapRoute(
    null,
    "questions/{id}/{title}",
    new { controller = "Questions", action = "Index" },
    new { id = @"\d+", title = @"[\w\-]*" });

routes.MapRoute(
    null,
    "questions/{id}",
    new { controller = "Questions", action = "Index" },
    new { id = @"\d+" });

now in the controller action,

public class QuestionsController 
{
    private readonly IQuestionRepository _questionRepo;

    public QuestionsController(IQuestionRepository questionRepo)
    {
        _questionRepo = questionRepo;
    }

    public ActionResult Index(int id, string title)
    {
        var question = _questionRepo.Get(id);

        if (string.IsNullOrWhiteSpace(title) || title != question.Title.ToSlug())
        {
            return RedirectToAction("Index", new { id, title = question.Title.ToSlug() }).AsMovedPermanently();
        }

        return View(question);
    }
}

We'll permanently redirect to the URL that contains the title slug (lowercase title with hyphens as separators) if we only have the id. We also make sure that the title passed is the correct one by checking it against the slugged version of the question title, thereby creating a canonical URL for the question that contains both the id and the correct title slug.

A couple of the helpers used

public static class PermanentRedirectionExtensions
{
    public static PermanentRedirectToRouteResult AsMovedPermanently
        (this RedirectToRouteResult redirection)
    {
        return new PermanentRedirectToRouteResult(redirection);
    }
}

public class PermanentRedirectToRouteResult : ActionResult
{
    public RedirectToRouteResult Redirection { get; private set; }
    public PermanentRedirectToRouteResult(RedirectToRouteResult redirection)
    {
        this.Redirection = redirection;
    }
    public override void ExecuteResult(ControllerContext context)
    {
        // After setting up a normal redirection, switch it to a 301
        Redirection.ExecuteResult(context);
        context.HttpContext.Response.StatusCode = 301;
        context.HttpContext.Response.Status = "301 Moved Permanently";
    }
}

public static class StringExtensions
{
    private static readonly Encoding Encoding = Encoding.GetEncoding("Cyrillic");

    public static string RemoveAccent(this string value)
    {
        byte[] bytes = Encoding.GetBytes(value);
        return Encoding.ASCII.GetString(bytes);
    }

    public static string ToSlug(this string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return string.Empty;
        }

        var str = value.RemoveAccent().ToLowerInvariant();

        str = Regex.Replace(str, @"[^a-z0-9\s-]", "");

        str = Regex.Replace(str, @"\s+", " ").Trim();

        str = str.Substring(0, str.Length <= 200 ? str.Length : 200).Trim();

        str = Regex.Replace(str, @"\s", "-");

        str = Regex.Replace(str, @"-+", "-");

        return str;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!