Appearance
Are you an LLM? You can read better optimized documentation at /getting_started/quick_start.md for this page in Markdown format
Quick start guide
Note: This repository is no longer officially maintained as of Jan, 2023. Feel free to use it, fork it and patch it for your own needs.
This guide provides the fastest path to getting TheExampleApp up and running on your local machine. It is intended for developers who need to quickly set up a working instance for evaluation, debugging, or feature development.
The application is a server-side rendered website built with ASP.NET Core 2.1, sourcing its content from the Contentful headless CMS. For a complete overview of the architecture and dependencies, please refer to the main technical stack documentation.
Read-only mode
The application is pre-configured to run in a "read-only" mode out of the box. This mode connects to a shared, public Contentful space containing demo content. You can browse the application, but you cannot make or see content changes. This is the quickest way to verify that your local environment is set up correctly.
The default configuration is located in TheExampleApp/appsettings.json and points to the read-only demo space:
json:TheExampleApp/appsettings.json
{
// ... other settings
"ContentfulOptions": {
"DeliveryApiKey": "df2a18b8a5b4426741408fc95fa4331c7388d502318c44a5b22b167c3c1b1d03",
"PreviewApiKey": "10145c6d864960fdca694014ae5e7bdaa7de514a1b5d7fd8bd24027f90c49bbc",
"SpaceId": "qz0n5cdakyl9",
"UsePreviewApi": false
}
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Note: The
DeliveryApiKeyis a public key for fetching published content. ThePreviewApiKeyis for fetching draft content. By default,UsePreviewApiisfalse.
5-minute setup
Follow these steps to clone, build, and run the application using the default read-only configuration.
Prerequisites:
- .NET Core 2.1 SDK or later
- Git
- Contentful CLI (only for write access)
Clone and restore
First, clone the repository from GitHub and navigate into the project directory. Then, run dotnet restore to download and install all the required NuGet packages defined in the project file.
bash
# Clone the repository
git clone https://github.com/contentful/the-example-app.csharp.git
# Navigate into the project directory
cd the-example-app.csharp
# Restore .NET dependencies
dotnet restore1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
The dotnet restore command will fetch dependencies such as the Microsoft.AspNetCore.All metapackage, the contentful.aspnetcore SDK, and the Markdig Markdown processor.
Run the application
The application is executed via the standard dotnet run command. This command compiles the project and starts the Kestrel web server. The application's entry point is defined in TheExampleApp/Program.cs.
csharp:TheExampleApp/Program.cs
public class Program
{
public static void Main(string[] args)
{
// The Main method builds and runs the web host.
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>() // Configures the application using the Startup class.
.Build();
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Execute the run command from the root of the project:
bash
dotnet run1
Once the server starts, you can access the application by navigating to http://localhost:3000 in your web browser.
Explore the demo content
With the application running, you are now interacting with a live ASP.NET Core application rendering content fetched from Contentful. The home page, for example, is rendered by the Index.cshtml Razor Page.
Its corresponding Page Model, Index.cshtml.cs, is responsible for fetching the required data from Contentful using the injected IContentfulClient.
csharp:TheExampleApp/Pages/Index.cshtml.cs
public class IndexModel : BasePageModel
{
// The Contentful client is injected via dependency injection.
public IndexModel(IContentfulClient client) : base(client)
{
}
public async Task OnGet()
{
// A QueryBuilder is used to construct a request to the Contentful API.
// This query fetches the 'layout' content type with a slug of 'home'.
var queryBuilder = QueryBuilder<Layout>.New
.ContentTypeIs("layout")
.FieldEquals(f => f.Slug, "home")
.Include(4) // Includes linked entries up to 4 levels deep.
.LocaleIs(HttpContext?.Session?.GetString(Startup.LOCALE_KEY) ?? CultureInfo.CurrentCulture.ToString());
var indexPage = (await _client.GetEntries(queryBuilder)).FirstOrDefault();
IndexPage = indexPage;
// Collect system properties from the layout and its content modules
var systemProperties = new List<SystemProperties> { indexPage.Sys };
if (indexPage.ContentModules != null && indexPage.ContentModules.Any())
{
systemProperties.AddRange(indexPage.ContentModules?.Select(c => c.Sys));
}
SystemProperties = systemProperties;
}
public Layout IndexPage { get; set; }
public IEnumerable<SystemProperties> SystemProperties { get; set; }
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
This demonstrates the core pattern of the application: a Razor Page Model queries the Contentful API for a specific content entry (or entries) and binds the result to a property, which is then used by the Razor view to render the final HTML.
Next steps
After running the application in read-only mode, you can proceed to more advanced configurations.
Setting up write access
To experience the full editorial workflow, you must connect the application to your own Contentful space with write permissions. This involves creating a new space, seeding it with the correct content model, and updating the application's configuration with your new space ID and API keys.
This process allows you to use the Contentful web app to edit content and see the changes reflected in your local instance of the application. For a step-by-step walkthrough, see the detailed guide:
Once configured, you can enable editorial features (like "Edit" buttons) by appending ?editorial_features=enabled to the URL. Learn more about this feature here:
Customizing the application
The application can be customized and extended. Key areas for customization include routing, internationalization, and content modeling.
- Routing: Custom routes are configured in
Startup.csto create user-friendly URLs for courses and lessons. You can modify or extend these conventions for new page types.csharp:TheExampleApp/Startup.csservices.AddMvc().AddRazorPagesOptions( options => { options.Conventions.AddPageRoute("/Courses", "Courses/Categories/{category?}"); options.Conventions.AddPageRoute("/Courses/Index", "Courses/{slug}/lessons"); options.Conventions.AddPageRoute("/Courses/Lessons", "Courses/{slug}/lessons/{lessonSlug}"); });1
2
3
4
5
6 - Internationalization (i18n): The application supports English (
en-US) and German (de-DE). To add a new language, you must update theSupportedCultureslist inStartup.csand provide a corresponding static translation file in the/wwwroot/localesdirectory. The locale resolution logic is handled by aCustomRequestCultureProvider.csharp:TheExampleApp/Startup.cspublic static List<CultureInfo> SupportedCultures = new List<CultureInfo> { // When adding supported locales make sure to also add a static translation // file for the locale under /wwwroot/locales new CultureInfo("en-US"), new CultureInfo("de-DE"), };1
2
3
4
5
6
7 - Content Modeling: To add new types of content, you will need to define a new content type in Contentful and create a corresponding C# class in the
TheExampleApp/Modelsdirectory to represent it.
For more information on development workflows, see:
Deploying to production
The repository includes configuration for deploying to Heroku and Azure. When deploying to a production environment, especially behind a reverse proxy or load balancer, it's important to be aware of the production-specific configurations in Startup.cs. For example, the application includes a rewrite rule to enforce HTTPS by checking the X-Forwarded-Proto header.
csharp:TheExampleApp/Startup.cs
// In the Configure method, for non-development environments:
options.Add((c) => {
var request = c.HttpContext.Request;
// This rule redirects HTTP to HTTPS if the X-Forwarded-Proto header is 'http'
if(request.Headers.ContainsKey("X-Forwarded-Proto") && request.Headers["X-Forwarded-Proto"] == "http")
{
var response = c.HttpContext.Response;
response.StatusCode = StatusCodes.Status301MovedPermanently;
c.Result = RuleResult.EndResponse;
response.Headers[HeaderNames.Location] = "https://" + request.Host + request.Path + request.QueryString;
}
});
app.UseRewriter(options);1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
For detailed deployment instructions and best practices, refer to our deployment guide: