Configuring page URLs on MVC sites

Kentico MVC websites respond to incoming requests using standard ASP.NET routing. This means that page URLs are determined by the routes that you register into your MVC application’s routing table.

To ensure that the Kentico administration application knows the correct live site URLs of pages, set URL patterns for your content-only pages types. The URL patterns need to match your MVC application’s route templates.

Alternative page URLs

The main URLs of pages are based on your MVC application’s routes and the URL patterns of page types. However, you can additionally configure the system to support any number of alternative URLs for individual pages. Alternative URLs are managed directly in the administration interface, so they can be added or modified without changes in the application’s routing code.

For more information, see the following pages:

Identifying pages based on a page alias

You can give content editors control over a part of the page URL by adding parameters into URL patterns. This allows you to include suitable human-readable keywords in URLs, and improve the site’s SEO.

By default, content-only pages in Kentico provide a page alias field for this purpose. The system automatically defines a page alias for every content-only page, typically as a URL-safe version of its name in the content tree. Internally, the page alias is stored in the NodeAlias field (column) of each page and you can retrieve it using the {%NodeAlias%} macro expression (for example when specifying URL patterns of page types).

Since page aliases are controlled by content editors, they can change over time. Also, page aliases are only guaranteed to be unique within a given sub-section level of the content tree (under the same parent page). For example, only pages stored directly in the /Articles section will have a unique page alias among each other. 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 with a page alias value in the URL is to combine it with another unique identifier, such as the NodeGUID. This ensures that conflicts cannot occur and URLs remain valid even if a page’s alias changes.

Note: NodeGUID values provide more stable URLs and links than NodeIDs, which may differ when hosting the same website on multiple instances (for example in environments that use content staging).

Typically, a page alias is inserted into the URL pattern of content-only page types using a macro expression. For example, a URL pattern could look like the following: /Articles/{%NodeGUID%}/{%NodeAlias%}

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 include a language prefix in your URL patterns (for example using the {%DocumentCulture%} macro), and/or create a custom page type field and use it instead of the page alias.

Retrieving content-only pages

If you use both a NodeGUID and page alias parameter in your URLs, use the NodeGUID identifier to retrieve specific pages in your code. The generated page type code provides the required method by default.




public static DocumentQuery<Article> GetArticle(Guid nodeGuid, string cultureName, string siteName)
{
    return GetArticles().OnSite(siteName).Culture(cultureName).WhereEquals("NodeGUID", nodeGuid);
}


For URLs that only contain a page alias parameter (NodeAlias), you need to make sure the page alias is always unique. You can, to a certain degree, ensure this uniqueness by limiting how content editors are allowed to create new pages:

To retrieve pages using only the page alias:




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


You can also use the full NodeAliasPath to retrieve pages (for example /Articles/March/On-Roasts for an article named On Roasts). This approach can be useful in scenarios where you have a highly structured content tree, and can build the alias path in your code according to other URL parameters. The generated page type code provides a method for retrieving pages based on the alias path by default.




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


See also: Displaying page content

Example – Displaying pages based on a page alias

The following example shows how you can configure your MVC application to display articles that have a URL containing a page alias parameter, without any additional identifiers. Note that the example is built on the Dancing Goat MVC sample site, which uses patterns like repositories to retrieve content.

  1. In your application’s RouteConfig.cs file, create a route for accessing articles based on a page alias. For example:

    
    
    
     public class RouteConfig
     {
         public static void RegisterRoutes(RouteCollection routes)
         {
         ...
             // Maps a custom route that displays an article based on a provided page alias
             route = routes.MapRoute(
                 name: "ArticleByPageAlias",
                 url: "{culture}/Articles/{pageAlias}",
                 defaults: new { culture = defaultCulture.Name, controller = "Articles", action = "ShowByPageAlias" }
             );
         ...
         }
     };
    
    
     
  2. Create a view model for your page type. For example:

    
    
    
     // Encapsulates data that is sent to associated views
     public class ArticleViewModel
     {
         public string Title { get; set; }
         public string Summary { get; set; }
         public string Text { get; set; }
         public DocumentAttachment Teaser { get; set; }
         public string NodeAlias { get; set; }
    
         // Creates a view model instance for a given Article
         public static ArticleViewModel(Article article)
         {
             // Gets the properties from the given Article object
             NodeAlias = article.NodeAlias;
             Summary = article.Fields.Summary;
             Text = article.Fields.Text;
             Teaser = article.Fields.Teaser;
             Title = article.Fields.Title;     
         }
     }
    
    
     
  3. Add a controller action for retrieving articles based on a page alias.

    
    
    
     public class ArticlesController : Controller
     {
     ...
         // GET: Articles/{pageAlias}
         public ActionResult ShowByPageAlias(string pageAlias)
         {
             // Retrieves an article based on the provided page alias
             var article = mArticleRepository.GetArticle(pageAlias);
             if (article == null)
             {
                 return HttpNotFound();
             }
    
             // Constructs a view model and sends it to a related view
             return View("Show", new ArticleViewModel(article));
         }
     ...
     }
    
    
     
  4. Create an extension method for generating article URLs with a page alias parameter (the method can then be used in your view code).

    
    
    
     public static class UrlHelperExtensions
     {
     ...
         /// <summary>
         /// Generates a fully qualified URL to the action method handling the detail of a specified article.
         /// </summary>
         /// <param name="urlHelper">Url helper</param>
         /// <param name="article">Article object for which the URL will be generated.</param>
         public static string ForArticleByPageAlias(this UrlHelper urlHelper, ArticleViewModel article)
         {
             return urlHelper.Action("ShowByPageAlias", "Articles", new
             {
                 pageAlias = article.NodeAlias
             });
         }
     ...
     }
    
    
     
  5. Retrieve articles based on a page alias. For example using the repository pattern:

    
    
    
     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. Null otherwise.</returns>
         public Article GetArticle(string pageAlias)
         {
             return ArticleProvider.GetArticles()
                 .OnSite(mSiteName)
                 .Culture(mCultureName)
                 .WhereEquals("NodeAlias", pageAlias)
                 .LatestVersion(mLatestVersionEnabled)
                 .Published(!mLatestVersionEnabled);
         }
     ...
     }
    
    
     
  6. Generate article URLs in Views using the created extension method:

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