ASP.NET Core Template: a layered MVC solution with the plumbing already done
A ready-to-use, layered ASP.NET Core 10 MVC solution template with Identity, EF Core, the repository pattern, Mapster mappings, dependency injection, tests and StyleCop warnings fixed.
At a glance
- What is it?
- A ready-to-use .NET 10 solution template split into Common, Data, Services, Web and Tests, with Identity, EF Core, generic repositories that handle audit fields and soft delete, Mapster mappings declared on the view models, and a test suite that starts the whole application. The cost is a template with opinions, and a naming step you have to get right.
- Who is it for?
- ASP.NET Core Template suits a .NET team that wants a structured MVC application with identity, a data layer and a test suite without assembling the layering themselves, and that is happy with EF Core, SQL Server and Mapster as the defaults. It does not suit a team that uses a different ORM, a different mapper or a different identity provider, because the choices are baked into the layers rather than swappable.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 29 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the template gives you on the first run
The repository description calls it a ready-to-use, layered ASP.NET Core 10 MVC solution template with Identity, EF Core, the repository pattern, Mapster mappings, dependency injection, tests and StyleCop warnings fixed.
The first item in the included list sets the shape of everything else. It is a .NET 10 solution in the new `.slnx` format, split into Common, Data, Services, Web and Tests layers.
The rest of the list is the part that saves time. ASP.NET Core MVC with an `Administration` area restricted to the `Administrator` role. ASP.NET Core Identity with the default UI, plus a custom `ApplicationUser` and `ApplicationRole`. Entity Framework Core with SQL Server, migrations applied on startup and data seeding. Generic repositories with audit info, `CreatedOn` and `ModifiedOn`, and soft delete, `IsDeleted` and `DeletedOn`, handled automatically. Mapster mappings declared on the view models through `IMapFrom<T>`, `IMapTo<T>` and `IHaveCustomMappings`. A SendGrid e-mail sender with a `NullMessageSender` for development. Bootstrap 5.3, jQuery 4 and jQuery Validation, restored at build time with LibMan and bundled and minified with WebOptimizer. xUnit.net v3 unit tests using Moq and the EF Core in-memory provider, plus integration tests with `WebApplicationFactory` on the Microsoft Testing Platform. StyleCop analyzers and selected .NET code analysis rules configured in `.globalconfig` and `stylecop.json`, and central package management through `Directory.Packages.props`.
The last item is the GitHub Actions workflow that builds the solution and runs the tests.
The template is published on NuGet as `AspNetCoreTemplate`, the licence is MIT, the default branch is master, and the last push was on 2026-09-24. The release versions track the framework version, with 10.0.12 from 2026-09-23, 10.0.5 from 2026-03-14 and 10.0.1 from 2026-01-10, so the template's version number tells you which .NET release it targets.
The layer graph, and what the dependencies permit
The project overview is a dependency diagram, and it is worth reading because the arrows define the rules you have to follow when you add code.
The `Web` project depends on `Web.ViewModels`, `Web.Infrastructure`, `Services`, `Services.Data`, `Services.Messaging` and `Data`. `Web.ViewModels` depends on `Services.Mapping` and `Data.Models`. `Services.Data` depends on `Services.Mapping`, `Data.Models` and `Data.Common`. `Data` depends on `Data.Models`, `Data.Common` and `Common`, and `Data.Models` depends on `Data.Common`.
Two things fall out of that. The `Common` project sits at the bottom and everything can depend on it, which is where shared primitives live. And the view models layer depends on the mapping layer and on the data models, but not the other way around, so a view model can be mapped to and from a model without the model knowing the view exists.
The `Services.Messaging` project being a dependency of `Web` rather than of `Services` is a bit of a surprise, and the diagram does not show anything depending on it, so it is most likely the sending side of the e-mail abstraction that the web layer wires up. The `NullMessageSender` mentioned in the included list lives in that area, and it is the reason a development environment does not need SendGrid credentials to start.
The `Web.Infrastructure` project appears in the diagram only as a dependency of `Web`, with nothing depending on it, which suggests it holds the MVC wiring, the filters and the view components rather than domain logic.
The `Common` project is described as containing the things shared by the whole solution, and the rest of that section of the README documents each layer in turn.
Installing the template and the naming step
The template is installed from NuGet:
dotnet new install AspNetCoreTemplateAnd a project is created from it:
dotnet new aspnet-core -n YourProjectName -o YourProjectNameThe behaviour that matters is the substitution rule. Every `AspNetCoreTemplate` occurrence in file names, namespaces and the database name is replaced with your project name. So the template does the renaming for you, in the places that are easy to miss when you do it by hand, including the database name.
After creating the files, `dotnet new` asks whether to run `dotnet format`, which re-sorts the `using` directives for your project name so the StyleCop analyzers report no warnings. The answer should be yes, or you pass `--allow-scripts yes` to skip the question.
That step exists because of a specific StyleCop rule. When the namespace changes, the `using` directives end up in the wrong order, and SA1210 is the rule about ordering. A warning-free build is part of the template's promise, since the description says the StyleCop warnings are fixed, and a template that produced a hundred warnings on first build would be a bad advertisement for its own analyzers.
The alternative route is to clone the repository and run the TemplateRenamer tool from the `src` folder to rename the solution in place, then run `dotnet format --diagnostics SA1210 --severity warn` there. The `tools/` directory at the repository root holds that tool.
The prerequisites are the .NET 10 SDK, SQL Server in one of the LocalDB, Express, Developer or Docker container flavours, and optionally Visual Studio 2026, Visual Studio Code or JetBrains Rider.
Running it, and the database created on startup
The run instructions are three steps, and the first is the one that trips people up.
You set the `DefaultConnection` connection string in `Web/YourProjectName.Web/appsettings.json`. It defaults to `Server=.;Database=YourProjectName;Trusted_Connection=True;...`, and for LocalDB you use `Server=(localdb)\mssqllocaldb` instead.
Then you run the web project from the solution folder:
cd YourProjectName
dotnet run --project Web/YourProjectName.WebThe database is created and migrated on startup, and the seeders add the `Administrator` role and a sample setting. So there is no separate migration step before the first run, which is convenient and is also a decision with consequences: the application has write access to your schema on every start.
The third step is granting the administration area to your account. You register a user through the UI and then run a SQL statement to add it to the role:
INSERT INTO AspNetUserRoles (UserId, RoleId)
SELECT u.Id, r.Id FROM AspNetUsers u, AspNetRoles r
WHERE u.Email = '[email protected]' AND r.Name = 'Administrator'That is a manual step with a SQL statement, and the reason it is manual is that the seeding adds the role but not a user in it. The role exists, the user does not, and the first administrator is created by hand.
For anything beyond the first run, migrations are the path. The `Data` project contains a design-time `DbContext` factory that reads its own `appsettings.json`, so migrations are created from that folder with the EF Core tools:
cd Data/YourProjectName.Data
dotnet ef migrations add YourMigrationNameThe design-time factory is the detail that makes this work. Without one, the tools would need to construct the application's service provider at design time, which pulls in the whole host configuration, and the separate factory reads a configuration file instead.
The test suite, and why Web.Tests needs a real database
The test projects use xUnit.net v3 on the Microsoft Testing Platform, which `global.json` turns on for `dotnet test`, so you run it from the solution folder:
dotnet test YourProjectName.slnxEach test project is also a standalone executable, so `dotnet run --project Tests/YourProjectName.Services.Data.Tests` works as well, which is a useful thing to know when a test hangs and you want to see the output.
The unit tests use Moq and the EF Core in-memory provider. The in-memory provider is the fast option and it is fine for repository logic, but it is not SQL Server, so a query that EF Core translates differently against a real server will not be caught by it. That is why the integration tests exist and why they are not optional.
The `Web.Tests` project starts the whole application with `WebApplicationFactory`, which means it needs a reachable SQL Server. You can point it at a separate database with an environment variable:
$env:ConnectionStrings__DefaultConnection = "Server=.;Database=YourProjectName_Tests;Trusted_Connection=True;TrustServerCertificate=True"
dotnet test YourProjectName.slnxThe `ConnectionStrings__DefaultConnection` form is the .NET convention for overriding a configuration value from the environment, with the double underscore standing in for the colon, and the point of pointing it at a separate database is that the application creates and migrates the schema on startup, so the test run would otherwise touch your development database.
The defaults that decide whether this template fits
The template makes a set of choices that are worth listing plainly, because a template is only useful if you agree with its decisions.
The data layer is EF Core with SQL Server, with a generic repository pattern rather than the DbContext used directly. The repositories handle audit information and soft delete automatically, which means the entities in `Data.Models` carry `CreatedOn`, `ModifiedOn`, `IsDeleted` and `DeletedOn` columns and the queries filter them. That is a decision with a price: every entity in your domain carries those four fields whether or not they are meaningful for that entity.
The mapping is Mapster, with the mappings declared on the view models rather than in a central mapping registry. The `IMapFrom<T>` and `IMapTo<T>` interfaces plus `IHaveCustomMappings` are how a view model says what it maps to and when it needs a hand-written mapping instead of the convention-based one.
The UI is server-rendered ASP.NET Core MVC with Bootstrap 5.3 and jQuery 4, which is a deliberately traditional stack, and the client-side libraries are restored at build time with LibMan and bundled and minified with WebOptimizer rather than through a JavaScript build pipeline.
Authentication is ASP.NET Core Identity with the default UI, extended with a custom user and role type.
And the code style is enforced, with StyleCop analyzers and selected .NET code analysis rules in `.globalconfig` and `stylecop.json`, and the packages centrally managed in `Directory.Packages.props`.
The pattern across all of these is the same. Each one is a mainstream, widely understood choice, and each one is baked in. A team that already has opinions here is better off writing the layer it disagrees with, which the template's structure makes possible, because the dependency diagram keeps the layers honest.
Where the ASP.NET Core Template is the wrong choice
The first wrong case is a team whose stack differs in the ways the template hard-codes. Dapper instead of EF Core, AutoMapper instead of Mapster, a different identity provider, or a database that is not SQL Server all mean rewriting the Data layer, and the template's value is concentrated in exactly that layer.
The second is a project that is not an MVC web application. There is no API-only or Blazor-first configuration here, and the Web layer is an MVC application with a Razor front end, so a JSON API service would start by deleting most of what you installed.
The third is a team that does not want the application to migrate the database on startup. That behaviour is convenient for a first run and wrong for a production deployment where multiple instances start at once, and turning it off is a change to the application host that the template does not document as a flag.
The fourth is a team that has a policy on third-party packages. The template brings in SendGrid, LibMan, WebOptimizer, Mapster, Moq, Bootstrap, jQuery and jQuery Validation, and a security review of that list is a real cost, even though each one is individually defensible.
The fifth is an organisation that wants its template to be a starting point rather than a house style. A public template that is popular becomes a dependency in its own right, and the version numbers of the template track the .NET version, so a new .NET release means a new template release and another round of upstream churn in your dependencies.
For a .NET team that wants exactly these layers, these tools and this set of defaults, though, the alternative is assembling the same thing over a few days, and the template gives you a version that already builds without analyzer warnings.
Editorial conclusion
ASP.NET Core Template suits a .NET team that wants a structured MVC application with identity, a data layer and a test suite without assembling the layering themselves, and that is happy with EF Core, SQL Server and Mapster as the defaults. It does not suit a team that uses a different ORM, a different mapper or a different identity provider, because the choices are baked into the layers rather than swappable. Before adopting it, install it with `dotnet new install AspNetCoreTemplate` and create a project so the renaming happens, and set the `DefaultConnection` connection string in `Web/YourProjectName.Web/appsettings.json` before you run, since the application creates and migrates the database on startup.
Frequently asked questions
How do I install and create a project from the ASP.NET Core Template?
Run `dotnet new install AspNetCoreTemplate`, then `dotnet new aspnet-core -n YourProjectName -o YourProjectName`. Every `AspNetCoreTemplate` occurrence in file names, namespaces and the database name is replaced with your project name, and you should accept the prompt to run `dotnet format`.
What layers does the ASP.NET Core Template use?
A .NET 10 solution in the new `.slnx` format, split into Common, Data, Services, Web and Tests. The dependency diagram shows Web depending on the view models, infrastructure, services, services data, messaging and data, with Common at the base of the graph.
Do I need to run migrations before the first start?
No. The database is created and migrated on startup, and the seeders add the `Administrator` role and a sample setting. For later changes, the `Data` project has a design-time DbContext factory, so you run `dotnet ef migrations add YourMigrationName` from `Data/YourProjectName.Data`.
Why do the Web.Tests need a real SQL Server?
Because that project starts the whole application with `WebApplicationFactory`, so it needs a reachable database. You point it at a separate one with the `ConnectionStrings__DefaultConnection` environment variable, as in the README's example with a `YourProjectName_Tests` database.
Which mapping and data libraries does the template use?
Mapster for mappings, declared on the view models through `IMapFrom<T>`, `IMapTo<T>` and `IHaveCustomMappings`, and Entity Framework Core with SQL Server for the data layer, with generic repositories that handle the `CreatedOn`, `ModifiedOn`, `IsDeleted` and `DeletedOn` fields automatically.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nikolayit-asp-net-core-template)