Providing friendly URLs on MVC sites

Content only pages in Kentico give content editors control over a part of a page URL, called page alias. This part of a URL that identifies a page using human-readable keywords.

One of the motivations for using page aliases is to improve the site's SEO. That is, you can use page aliases to provide content with more SEO-friendly identifiers in URLs.

Kentico automatically predefines a page alias for every content only page. Internally, page alias is the NodeAlias of the content only page and you can retrieve a page alias using the {%NodeAlias%} macro expression. Each content only page can only have one unique page alias.

Identifying pages based on a page alias

Since page aliases in content only pages are controlled by content editors, they can change. Also, page aliases are only guaranteed to be unique in the current sub-tree (under the current parent page). For example, only pages stored directly in the /Articles section will have a unique page alias. However, if one page is stored under /Articles/March and another page is stored under /Articles/May, they can both have the same page alias. This is why you may not want to use page aliases as the only identifier when displaying pages.

The recommended practice for identifying pages that use page aliases is to use URLs that consist of NodeID and Page alias. This is mainly to ensure SEO in case the page alias of pages changes on the live site.

Typically, a page alias will be part of a macro expression that makes up a URL pattern in content only page types. For example, a URL pattern can be specified like this /Articles/{%NodeID%}/{%NodeAlias%}. Where {%NodeAlias%} accesses the page alias.

Identifying multilingual content when using page aliases

Page aliases remain the same for pages in different cultures. To be able to distinguish pages in different cultures, you can, for example create a new page type field that will be used as the page alias.

Retrieving content only pages based on a page alias

When using page aliases without NodeID to create page URLs, you need to make sure that page alias is always unique. You can, to a certain degree, ensure this uniqueness by limiting the way content editors can create new pages:

To retrieve pages that use both NodeID and a page alias, use the following method. The method is available in generated page type code.

public static DocumentQuery<Article> GetArticle(int nodeId, string cultureName, string siteName)
{
    return GetArticles().OnSite(siteName).Culture(cultureName).WhereEquals("NodeID", nodeId);
}

To retrieve pages that use page alias (NodeAlias) only:

public static DocumentQuery<Article> GetArticles(string pageAlias)
{
    return GetArticles().OnSite(siteName).Culture(cultureName).WhereEquals("NodeAlias", pageAlias).TopN(1);
}

You can also use the whole NodeAliasPath in the URL. URLs built with NodeAliasPath contain the whole path leading to the page. For example /Articles/March/On-Roasts for an article named On Roasts. This approach is useful if you store pages in a more structured content tree. The method is available in generated page type code. You will also need to map a route with a URL pattern for the NodeAliasPath.

Note that NodeAliasPath is limited to 50 characters in length. This means that the resulting URL may be truncated.

public static DocumentQuery<Article> GetArticle(string nodeAliasPath, string cultureName, string siteName)
{
    return GetArticles().OnSite(siteName).Culture(cultureName).Path(nodeAliasPath);
}

Configuring MVC application to display pages based on a page alias

The following example shows how you can configure your MVC application to display articles that have a URL based on a page alias without using a NodeID. Note that the examples build on our MVC Demo site, which uses patterns like repositories to retrieve content and other implementation specifics.

  1. In your application's RouteConfig.cs file, create a route for accessing articles without a NodeID.

    public class RouteConfig
        {
            public static void RegisterRoutes(RouteCollection routes)
            {
    		...
    			route = routes.MapRoute(
    		 	name: "ArticleByPageAlias",
    		 	url: "{culture}/Articles/{pageAlias}",
    		 	defaults: new { culture = defaultCulture.Name, controller = "Articles", action = "ShowByPageAlias" }
    			);
    		...
    	}
    };
  2. Add a controller action for retrieving articles based on a page alias.

    public class ArticlesController : Controller
    {
    ...
    	// GET: Articles/{pageAlias}
    	public ActionResult ShowByPageAlias(string pageAlias)
    	{
    		var article = mArticleRepository.GetArticle(pageAlias);
    		if (article == null)
    		{
    			return HttpNotFound();
    		}
    		return View("Show", article);
    	}
    ...
    }
  3. Create a method for generating article URLs based on a page alias without a NodeID.

    public static class UrlHelperExtensions
    {
    ...
    	/// <summary>
    	/// Generates a fully qualified URL to the action method handling the detail of given article.
    	/// </summary>
    	/// <param name="urlHelper">Url helper</param>
    	/// <param name="article">Article object to generate URL for.</param>
    	public static string ForArticleByPageAlias(this UrlHelper urlHelper, Article article)
    	{
    		return urlHelper.Action("ShowByPageAlias", "Articles", new
    		{
    			pageAlias = article.NodeAlias
    		});
    	}
    ...
    }
  4. Retrieve articles based on a page alias. For example in repositories.

    public interface IArticleRepository
    {
    ...
    	/// <summary>
    	/// Returns the article with the specified page alias.
    	/// </summary>
    	/// <param name="pageAlias">The article page alias.</param>
    	/// <returns>The article with the specified page alias, if found; otherwise, null.</returns>
    	Article GetArticle(string pageAlias);
    ...
    }
    public class KenticoArticleRepository : IArticleRepository
    {
    ...
    	/// <summary>
    	/// Returns the article with the specified page alias.
    	/// </summary>
    	/// <param name="pageAlias">The article page alias.</param>
    	/// <returns>The article with the specified page alias, if found; otherwise, null.</returns>
    	public Article GetArticle(string pageAlias)
    	{
    		return ArticleProvider.GetArticles()
    			.OnSite(mSiteName)
    			.Culture(mCultureName)
    			.WhereEquals("NodeAlias", pageAlias)
    			.LatestVersion(mLatestVersionEnabled)
    			.Published(!mLatestVersionEnabled);
    	}
    ...
    }
  5. Work with article URLs in Views based on a page alias.

    <a href="@Url.ForArticleByPageAlias(article)">@article.Fields.Title </a>

Was this page helpful?