Generar Slug

Para generar un slug, como ejemplo un Article

public class Article
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Slug { get; set; }
}

Crear una clase de extension de string

public static class Text
{
    public static string Slugify(this string text)
    {
        var pattern = @"[^a-zA-Z0-9\-]";
        var replacement = "-";
        var regex = new Regex(pattern);
        var result = regex.Replace(RemoveDiacritics(text), replacement).Replace("--", "-").Trim('-');
        return result;
    }

    private static string RemoveDiacritics(string text)
    {
        var normalizedString = text.ToLower().Trim().Normalize(NormalizationForm.FormD);
        var stringBuilder = new StringBuilder();
        foreach (var c in normalizedString)
        {
            var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
            if (unicodeCategory != UnicodeCategory.NonSpacingMark)
            {
                stringBuilder.Append(c);
            }
        }
        return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
    }
}

Antes de guardar el Article, generar un Slug

public void Create(Article model)
{
    model.Slug = model.Title.Slugify();
    _context.Articles.Add(model);
    _context.SaveChanges();
}

Crear un Constraint

public class SlugConstraint : IRouteConstraint
{

    public bool Match(HttpContext httpContext,
        IRouter route,
        string routeKey,
        RouteValueDictionary values,
        RouteDirection routeDirection)
    {
        var pattern = @"[a-z0-9\-]*";
        var regex = new Regex(pattern);
        var result = regex.IsMatch(values[routeKey]?.ToString());
        return result;
    }
}

En Startup.cs añadir un MapRoute

routes.MapRoute(
    name: "",
    template: "{controller}/{action}/{slug}",
    defaults: new { controller = "Article", action = "Details" },
    constraints: new { slug = new SlugConstraint() }
);