Build your first .NET Core app
This tutorial will show you how to create an ASP.NET Core MVC app from scratch and use it to display content from your Kontent.ai project. If you're new to ASP.NET Core MVC, you might want to take the Microsoft Getting started with ASP.NET Core MVC tutorial first.
New to Kontent.ai?
If you're starting with Kontent.ai, we suggest you begin with the Hello World tutorial, in which you'll learn the basics of creating content.
Table of contents
You’ll use the Kontent.ai .NET boilerplate (a template for new applications with a few basic features built on top) and customize it to suit your needs. The boilerplate includes the Delivery .NET SDK, 404 error handling, logging, sitemap generator, and more.
Requirements
Make sure you have the following installed:
- .NET 5 SDK
- An IDE (such as Visual Studio 2019) or the text editor of your choice
Prepare the boilerplate
1. Register .NET template
In your command line, register a new custom template named ASP.NET Core MVC with Kontent.ai in your .NET templates.
dotnet new --install "Kontent.Ai.Boilerplate::*"dotnet new --install "Kontent.Ai.Boilerplate::*"
2. Create an app based on the template
Now you can initialize a new app based on the new .NET template.
dotnet new kontent-ai-mvc --name "MyKontentAiWebsite"dotnet new kontent-ai-mvc --name "MyKontentAiWebsite"
3. Run the app
Your new web app is ready. Navigate to its folder and run it.
cd .\MyKontentAiWebsite dotnet runcd .\MyKontentAiWebsite dotnet run
Your app will run and become available at http://localhost:5000
. Open the address in your browser to view it.

How the boilerplate will look on first run
Connect the app to your project
Right now the app fetches content from the default Sample Project and displays a preview of 3 articles.
To connect the app to your own project:
- In Kontent.ai, go to Environment settings > General and click Copy to clipboard for the Environment ID.
- In the .NET app folder, open the
appsettings.json
file. - Replace the value of the
ProjectId
key with your environment’s ID. - Save the changes.
When you now rerun the app and open http://localhost:5000
in your browser, the app will work with data from the specified project.
Add classes for your content types
To make app development easier, we recommend using the model generator for .NET to create strongly-typed models representing your content types.
Sample models
By default, the boilerplate comes with a single model describing the structure of an Article content type – you can find the model in the \Models\ContentTypes\
folder.
The Article model is referenced as an example in multiple locations across the app:
\Controllers\HomeController.cs
\Controllers\SiteMapController.cs
\Views\Home\Index.cshtml
\Views\Shared\DisplayTemplates\Article.cshtml
You can adjust the references later when you customize the app.
Your project likely has other content types with a different structure than the provided sample model. This means you can safely overwrite the contents of the \Models\ContentTypes\
folder with your own models.
1. Install the model generator
In your command line, run the following command to install the model generator tool for your app.
# Installs the Kontent.ai model generator tool locally into the app's folder dotnet tool restore# Installs the Kontent.ai model generator tool locally into the app's folder dotnet tool restore
The model generator is now available as the KontentModelGenerator
tool.
2. Generate models
In your command line, use dotnet tool run KontentModelGenerator
with the following parameters:
--projectid
– identifies an environment of your Kontent.ai project.--withtypeprovider
– tells the generator to create theCustomTypeProvider
class to support runtime type resolution.--generatepartials
– tells the generator to create partial classes for easier customization.--structuredmodel
– tells the generator to type rich text elements asIRichTextContent
objects instead of strings.--outputdir
– specifies where to store the generated models.--namespace
– specifies the namespace of the generated models.
# Note: This overwrites existing files in the .\Models\ContentTypes folder dotnet tool run KontentModelGenerator --projectid "<YOUR_PROJECT_ID>" --withtypeprovider true --structuredmodel true --outputdir ".\Models\ContentTypes" --namespace "MyWebsite.Models" --generatepartials true# Note: This overwrites existing files in the .\Models\ContentTypes folder dotnet tool run KontentModelGenerator --projectid "<YOUR_PROJECT_ID>" --withtypeprovider true --structuredmodel true --outputdir ".\Models\ContentTypes" --namespace "MyWebsite.Models" --generatepartials true
For each content type, the generator creates two files, one with the suffix .Generated
and another without the suffix. The suffixed files are partial classes, and suffix-less files are for your custom code.
This means you can extend the models in separate files and re-generate them in the future without losing your code. Learn more about the data types used for individual elements.
3. Map retrieved content to your models
When you fetch content items from your project, you can map the returned data to a specific model.
// Retrieves 3 articles ordered by their post date public async Task<ViewResult> Index() { var response = await DeliveryClient.GetItemsAsync<Article>( new EqualsFilter("system.type", "article"), new LimitParameter(3), new DepthParameter(0), new OrderParameter("elements.post_date") ); // Sends the strongly-typed content items to a View return View(response.Items); }// Retrieves 3 articles ordered by their post date public async Task<ViewResult> Index() { var response = await DeliveryClient.GetItemsAsync<Article>( new EqualsFilter("system.type", "article"), new LimitParameter(3), new DepthParameter(0), new OrderParameter("elements.post_date") ); // Sends the strongly-typed content items to a View return View(response.Items); }
Find the code in the HomeController
controller.
Use the same approach to map your content to the models of your content types. Make sure you adjust the following when retrieving content:
- Replace instances of
Article
with the name of the class representing your content type. - Replace
article
in theEqualsFilter
parameter with the codename of your content type. - Replace the value of the
OrderParameter
so that the API orders the results by values in existing elements or system attributes.
Find more about content filtering in .NET through examples.
3. Display your content
Access any of your content type's elements (available as model properties) in your app's Views.
@using MyWebsite.Helpers.Extensions @model Article <div class="body"> <h2>@Model.Title</h2> <!-- Generates an IMG element for the image using a helper method. --> @Html.AssetImage(@Model.TeaserImage.First(), title: @Model.TeaserImage.First().Name, cssClass: "img-responsive", sizes: new ResponsiveImageSizes(300) .WithMediaCondition(new MediaCondition { MinWidth = 330, MaxWidth = 768, ImageWidth = 689 }))> @Model.Summary </div>@using MyWebsite.Helpers.Extensions @model Article <div class="body"> <h2>@Model.Title</h2> <!-- Generates an IMG element for the image using a helper method. --> @Html.AssetImage(@Model.TeaserImage.First(), title: @Model.TeaserImage.First().Name, cssClass: "img-responsive", sizes: new ResponsiveImageSizes(300) .WithMediaCondition(new MediaCondition { MinWidth = 330, MaxWidth = 768, ImageWidth = 689 }))> @Model.Summary </div>
If you're using a different model, be sure to change the model declaration and individual properties.
Render rich text elements
To render rich text elements, use the Html.DisplayFor
helper method in your Views.
@* Renders content of a rich text element (BodyCopy in an article) *@ @Html.DisplayFor(model => model.BodyCopy)@* Renders content of a rich text element (BodyCopy in an article) *@ @Html.DisplayFor(model => model.BodyCopy)
By default, the blocks of content in rich text elements will be rendered using their default HTML representations, which match what you get from the Delivery API. For better results, we recommend that you write your own resolvers of rich text content.
Render rich content
To customize the way your app renders components, content items, and images, you need to create display templates for them:
- For components and content items, create display templates named
<ModelName>.cshtml
where theModelName
refers to the content type of the content item or component. For example,Tweet.cshtml
. - (Optional) For images, create a display template named
InlineImage.cshtml
.
For a more in-depth example, see how to retrieve structured content in rich text.
Resolve URLs
If your rich text elements contain links to other content items, you need to tell your app how to build correct URLs.
Open the Resolvers\CustomContentLinkUrlResolver.cs
file in your app and implement these two methods:
ResolveLinkUrl()
for linked content items that are available.ResolveBrokenLinkUrl()
for linked content items that are not available, for example, unpublished or deleted items.
Both methods must return strings.
Check out the example below and add logic for your own content types.
public Task<string> ResolveLinkUrlAsync(IContentLink link) { // Resolves links pointing to Article content items if (link.ContentTypeCodename.Equals(Article.Codename)) { return Task.FromResult($"/articles/{link.UrlSlug}"); } // Add the rest of the resolver logic } public Task<string> ResolveBrokenLinkUrlAsync() { // Resolves URLs to unavailable content items return Task.FromResult("/Error/404"); }public Task<string> ResolveLinkUrlAsync(IContentLink link) { // Resolves links pointing to Article content items if (link.ContentTypeCodename.Equals(Article.Codename)) { return Task.FromResult($"/articles/{link.UrlSlug}"); } // Add the rest of the resolver logic } public Task<string> ResolveBrokenLinkUrlAsync() { // Resolves URLs to unavailable content items return Task.FromResult("/Error/404"); }
Learn more about how the link resolvers work.
Configure the app
The boilerplate also includes a set of pre-configured features such as error handling, logging, sitemap.xml generator. You can configure most of these features in the Startup.cs
file.
Handle errors
When you run the app locally on your machine without specifying any environment-specific launch profile, the app will use a development profile. This means that if your app encounters an exception, it will be logged to the console and displayed directly in your browser.
In a production environment (that is when the app is run with a production profile), all errors are still logged, but a custom error page is displayed instead of the stack trace.
If you'd like to tweak the error handling and relevant error pages, see the following:
- The
Configure
method in theStartup
class specifies app behavior in different environments. - The
ErrorController
controller specifies what pages to display for specific HTTP status codes such as 404 Not Found. - The views in the
\Views\Error
folder contain pages that are displayed when an error occurs in a production environment.
Think through your caching strategy
To use fewer Content API calls, the app employs a fixed-time caching mechanism. By default, the app caches responses from Kontent.ai for 24 minutes. When content is stale (that means your cached content is older than what's in your Kontent.ai project) it is cached for only 2 seconds. You can change the expiration times via the DeliveryCacheOptions
in Startup.cs
.
Add caching to improve performance
Without any caching, you would be making requests to the Delivery API with each page load. You can greatly improve your app performance by caching the API responses and the dependencies among them.