---
title: Create the profile page
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

## Create the _Profile page_ page template

Now that we have the view component and the controller action it posts to, we need to use the view component somewhere to test this functionality.

Let's create a bare-bones page template so that editors can see the profile page in the content tree.

### Start with a content type

While we could make a template that applies to an existing content type, let's create a dedicated _Profile page_ content type and make sure the template only works for this type. This way, we can avoid cluttering the template options when editors are creating landing pages.

Create a new content type with the following properties:

- **Content type name:** Profile page
- **Namespace:** TrainingGuides
- **Name:** ProfilePage
- **Icon:** xp-personalisation
- **Use for:** Pages
- **Include in routing:** True (enabled)
- **Short code name:** TrainingGuidesProfilePage

You don't need to add anything on the **Fields** tab, since we haven't defined ways for editors to configure the profile page.

Now run the [Code generation tool](https://docs.kentico.com/documentation/developers-and-admins/api/generate-code-files-for-system-objects.md) to generate a C# class for this content type in your project:

```cmd title=".NET CLI"
dotnet run -- --kxp-codegen --type "PageContentTypes" --include "TrainingGuides.ProfilePage"
```

### Define and register the template

In your project, add a new _ProfilePage_ folder within the _Profile_ directory, for files related to our new content type and its template.

Since we already created a reusable view component for the profile functionality, defining the template's display will be simple:

```cshtml title="ProfilePagePageTemplate.cshtml"
@using TrainingGuides.Web.Features.Membership.Profile

<vc:update-profile />
```

Then, you can use the `RegisterPageTemplate` attribute in a new _.cs_ file to tell Xperience about the template:

```csharp title="ProfilePagePageTemplate.cs"
using Kentico.PageBuilder.Web.Mvc.PageTemplates;
using TrainingGuides;
using TrainingGuides.Web.Features.Membership.Profile;

[assembly: RegisterPageTemplate(
    identifier: ProfilePagePageTemplate.IDENTIFIER,
    name: "Profile page content type template",
    customViewName: "~/Features/Membership/Profile/ProfilePage/ProfilePagePageTemplate.cshtml",
    ContentTypeNames = [ProfilePage.CONTENT_TYPE_NAME],
    IconClass = "xp-personalisation")]

namespace TrainingGuides.Web.Features.Membership.Profile;
public static class ProfilePagePageTemplate
{
    public const string IDENTIFIER = "TrainingGuides.ProfilePagePageTemplate";
}
```

> **Tip:** Use the `ContentTypeNames` parameter to make sure only pages of the _Profile page_ type can use the template.

### Serve the template from a controller

Now we need to tell Xperience's [Content tree-based router](https://docs.kentico.com/documentation/developers-and-admins/development/routing/content-tree-based-routing.md) to use a template for the _Profile page_ content type.

Create a controller that returns a `TemplateResult` from its `Index` action and register it with the router.

```csharp title="ProfilePageController.cs"
using Kentico.Content.Web.Mvc.Routing;
using Kentico.PageBuilder.Web.Mvc.PageTemplates;
using Microsoft.AspNetCore.Mvc;
using TrainingGuides;

[assembly: RegisterWebPageRoute(
    contentTypeName: ProfilePage.CONTENT_TYPE_NAME,
    controllerType: typeof(TrainingGuides.Web.Features.Membership.Profile.ProfilePageController))]

namespace TrainingGuides.Web.Features.Membership.Profile;
public class ProfilePageController : Controller
{
    public IActionResult Index() => new TemplateResult();
}
```

### Add a page that uses the template

With the template now bound to the content type, you can create a new _Profile page_ in Xperience and assign the new template.

🎬 [Video](https://docs.kentico.com/docsassets/modules/create-profile-page/create-profile-page.mp4)

Make sure to secure the page by enabling the **Requires authentication** checkbox in the **Membership** section of its **Properties** tab.

![Screenshot of the page's properties](https://docs.kentico.com/docsassets/modules/create-profile-page/secured-profile-page.png "Screenshot of the page's properties")

On the live site, the new profile page also displays the member's role badge and its associated benefits.

![Live profile page showing member role badge and benefits section](https://docs.kentico.com/docsassets/modules/create-profile-page/profile-page-live.png "Live profile page showing member role badge and benefits section")

## Consider the possibilities

If you want to expand this functionality, you can allow members to change their email address and tie that flow to a button on the profile page.

You can create new methods in your membership service that use the `UserManager<T>`'s `GenerateChangeEmailTokenAsync` and `ChangeEmailAsync` methods in a flow similar to the existing [password reset process](https://github.com/Kentico/xperience-by-kentico-training-guides/tree/finished/src/TrainingGuides.Web/Features/Membership/Widgets/ResetPassword) in the [finished branch](https://github.com/Kentico/xperience-by-kentico-training-guides/tree/finished) of the _Training guides_ repository. Send an email with a link that contains the token.

You can further expand the functionality by allowing members to define a recovery email address, or a phone number to use in case their primary email is no longer accessible.
