Appearance
Are you an LLM? You can read better optimized documentation at /architecture/project_structure.md for this page in Markdown format
Project structure
This document provides a detailed technical breakdown of the solution and project structure for TheExampleApp. It is intended for developers who will be maintaining and extending the application. A high-level overview of the application's purpose and architecture can be found in the Application Overview.
Solution organization
The codebase is organized into a single Visual Studio Solution (.sln) that contains four distinct C# projects (.csproj). This structure separates the main web application from its various testing suites, promoting a clean separation of concerns and facilitating different types of testing.
The solution file, TheExampleApp.sln, defines the following projects:
| Project | Purpose |
|---|---|
TheExampleApp | The main ASP.NET Core web application. This is the deployable asset that serves user requests. |
TheExampleApp.Tests | A dedicated project for unit tests. These tests verify individual components in isolation. |
TheExampleApp.IntegrationTests | A project for integration tests. These tests verify that components work together correctly within the ASP.NET Core pipeline. |
TheExampleApp.E2eTests | A project for end-to-end (E2E) tests. These tests automate a web browser to simulate real user interaction with the application. |
The structure is defined in TheExampleApp.sln as follows:
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
...
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheExampleApp", "TheExampleApp\TheExampleApp.csproj", ...
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheExampleApp.Tests", "TheExampleApp.Tests\TheExampleApp.Tests.csproj", ...
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheExampleApp.IntegrationTests", "TheExampleApp.IntegrationTests\TheExampleApp.IntegrationTests.csproj", ...
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheExampleApp.E2eTests", "TheExampleApp.E2eTests\TheExampleApp.E2eTests.csproj", ...
EndProject
...1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
Main application (TheExampleApp)
TheExampleApp is an ASP.NET Core 2.1 web application built using the Microsoft.NET.Sdk.Web SDK. It follows the Razor Pages model for server-side rendering. Its primary function is to fetch content from the Contentful headless CMS and render it as HTML.
Key dependencies defined in TheExampleApp.csproj include:
xml
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<!-- Fetches content from the headless CMS -->
<PackageReference Include="contentful.aspnetcore" Version="3.3.6" />
<!-- Renders Markdown content from Contentful into HTML -->
<PackageReference Include="Markdig" Version="0.15.4" />
<!-- ASP.NET Core 2.1 metapackage including MVC, Kestrel, etc. -->
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.5" />
<!-- Razor language services -->
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="2.1.2" />
<!-- Tooling for scaffolding controllers, views, etc. -->
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.5" />
</ItemGroup>
<ItemGroup>
<!-- CLI tools for code generation -->
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />
</ItemGroup>
...
</Project>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Standard Folder Structure
The project adheres to the conventional ASP.NET Core folder structure:
Pages/: Contains the Razor Pages that handle incoming HTTP requests. Each.cshtmlfile is paired with a.cshtml.csPageModel class that contains the C# logic for the page. For more details, see the Razor Pages documentation.Models/: Contains the C# Plain Old CLR Objects (POCOs) that represent the content models defined in Contentful. Thecontentful.aspnetcoreSDK uses these classes to deserialize the JSON responses from the Contentful API. See the Models documentation for class definitions.Views/Shared/: Holds shared Razor components, such as_Layout.cshtml(the main site template),_ValidationScriptsPartial.cshtml, and other partial views used across multiple pages.ViewComponents/: Contains reusable, server-side UI components that encapsulate rendering logic. These are similar to partial views but with associated backend logic.wwwroot/: The web root folder for all public, static assets. This includes:css/: Stylesheets.js/: JavaScript files. The project uses minimal client-side JavaScript and does not use a major framework like React or Angular. Thebower.jsonfile is present but empty, indicating Bower was the intended package manager, but no packages are installed.images/: Static image assets.locales/: JSON files for internationalization (i18n). These files are configured as embedded resources in the.csprojfile, allowing the application to load them at runtime to support multiple languages (e.g.,en-USandde-DE).
xml
<!-- TheExampleApp.csproj: Configuration for locale files -->
<ItemGroup>
<EmbeddedResource Include="wwwroot\locales\de-DE.json" />
<EmbeddedResource Include="wwwroot\locales\en-US.json" />
</ItemGroup>1
2
3
4
5
2
3
4
5
Test projects
The solution includes a comprehensive testing strategy divided into three separate projects. This ensures code quality, stability, and correctness across different levels of the application. For a general overview of the testing philosophy, refer to the Testing Overview.
Unit Tests (TheExampleApp.Tests)
This project contains fast, isolated unit tests. It references the main TheExampleApp project to test its classes directly.
- Test Runner:
xUnit - Mocking Framework:
Moq - Purpose: To test individual methods and classes (e.g., services, PageModel logic) in isolation from external dependencies like the file system or network.
Moqis used to create mock objects for these dependencies.
xml
<!-- TheExampleApp.Tests.csproj -->
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="Moq" Version="4.7.145" />
<PackageReference Include="xunit" Version="2.3.1" />
...
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TheExampleApp\TheExampleApp.csproj" />
</ItemGroup>1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Integration Tests (TheExampleApp.IntegrationTests)
This project is for testing how different parts of the application work together. It uses the Microsoft.AspNetCore.TestHost library to host the application in-memory and send HTTP requests to it, testing the full pipeline from routing to response generation without the overhead of a real web server.
- Test Runner:
xUnit - Test Host:
Microsoft.AspNetCore.TestHost - Purpose: To verify the application's request/response pipeline, including routing, model binding, filter execution, and view rendering.
Gotcha: Dependency File Copying
The TheExampleApp.IntegrationTests.csproj file includes a custom MSBuild target named CopyDepsFiles. This is a critical workaround for a known issue in older .NET Core versions where project dependency files (.deps.json) were not correctly copied to the output directory. The TestHost requires these files to resolve and load the application's dependencies correctly.
xml
<!-- TheExampleApp.IntegrationTests.csproj -->
<!-- https://github.com/NuGet/Home/issues/4412 -->
<Target Name="CopyDepsFiles" AfterTargets="Build" Condition="'$(TargetFramework)'!=''">
<ItemGroup>
<DepsFilePaths Include="$([System.IO.Path]::ChangeExtension('%(_ResolvedProjectReferencePaths.FullPath)', '.deps.json'))" />
</ItemGroup>
<Copy SourceFiles="%(DepsFilePaths.FullPath)" DestinationFolder="$(OutputPath)" Condition="Exists('%(DepsFilePaths.FullPath)')" />
</Target>1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
E2E Tests (TheExampleApp.E2eTests)
This project contains end-to-end tests that validate application behavior from the user's perspective. It uses Selenium to programmatically control a web browser and interact with a running instance of the application.
- Test Runner:
xUnit - Browser Automation:
Selenium.WebDriver - Purpose: To simulate user flows, such as navigating between pages, filling out forms, and verifying that the correct content is displayed. These tests are the slowest and most brittle but provide the highest confidence that the application is working as expected.
This project does not reference TheExampleApp directly, as it is designed to run against a deployed or locally hosted instance of the web application. The project file ensures that the necessary ChromeDriver binaries (chromedriver for Linux/macOS and chromedriver.exe for Windows) are copied to the output directory so Selenium can launch and control Google Chrome.
xml
<!-- TheExampleApp.E2eTests.csproj -->
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="Selenium.WebDriver" Version="3.7.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<!-- Ensures the browser driver is available for Selenium at runtime -->
<None Update="chromedriver">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="chromedriver.exe">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Configuration files
The solution's structure and dependencies are defined by the solution (.sln) and project (.csproj) files.
Solution File Structure
The TheExampleApp.sln file at the root of the repository acts as the entry point for IDEs like Visual Studio and CLI tools like dotnet build. It lists all projects in the solution and their build configurations.
Project File Dependencies
The .csproj files use the modern, SDK-style format. They define the target framework, package dependencies (via PackageReference), and project-to-project dependencies (via ProjectReference). The dependency graph is as follows:
TheExampleApp.Tests->TheExampleAppTheExampleApp.IntegrationTests->TheExampleAppTheExampleApp.E2eTests-> (No project reference; runs against a deployed application)
This unidirectional dependency flow ensures that the main application has no knowledge of its tests, which is a fundamental principle of clean software design.