<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ismail Cagdas</title>
    <description>The latest articles on DEV Community by ismail Cagdas (@ismcagdas).</description>
    <link>https://dev.to/ismcagdas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1673015%2Fc65f62fb-bbbb-45ed-b77a-696d770aaae8.png</url>
      <title>DEV Community: ismail Cagdas</title>
      <link>https://dev.to/ismcagdas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ismcagdas"/>
    <language>en</language>
    <item>
      <title>Angular + ASP.NET Core: Enterprise Project Getting Started Guide</title>
      <dc:creator>ismail Cagdas</dc:creator>
      <pubDate>Thu, 02 Apr 2026 10:29:43 +0000</pubDate>
      <link>https://dev.to/ismcagdas/angular-aspnet-core-enterprise-project-getting-started-guide-1k8l</link>
      <guid>https://dev.to/ismcagdas/angular-aspnet-core-enterprise-project-getting-started-guide-1k8l</guid>
      <description>&lt;p&gt;If you are building an enterprise web application in 2026, the combination of &lt;strong&gt;Angular&lt;/strong&gt; and &lt;strong&gt;ASP.NET Core&lt;/strong&gt; is one of the strongest choices you can make. Angular gives you TypeScript safety, a powerful component architecture, and a mature ecosystem. ASP.NET Core gives you a high-performance, cross-platform backend with first-class dependency injection and a rich middleware pipeline.&lt;/p&gt;

&lt;p&gt;In this post, we will walk through &lt;strong&gt;three different ways&lt;/strong&gt; to start an Angular + ASP.NET Core project — from a fully manual setup to a one-click enterprise starter. By the end, you will have a clear understanding of which approach fits your project best.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;
Approach 1 — Manual Setup

&lt;ul&gt;
&lt;li&gt;Step 1: Create the Angular App&lt;/li&gt;
&lt;li&gt;Step 2: Create the ASP.NET Core Web API&lt;/li&gt;
&lt;li&gt;Step 3: Configure CORS&lt;/li&gt;
&lt;li&gt;Step 4: Set Up the Angular Proxy&lt;/li&gt;
&lt;li&gt;Step 5: Make the First API Call&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Approach 2 — Visual Studio Template&lt;/li&gt;

&lt;li&gt;Approach 3 — ASP.NET Zero&lt;/li&gt;

&lt;li&gt;Comparison&lt;/li&gt;

&lt;li&gt;Common Issues and Solutions&lt;/li&gt;

&lt;li&gt;Next Steps&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we start, make sure you have the following tools installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; 24.x or later — &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;download here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Angular CLI&lt;/strong&gt; 21.x — install with &lt;code&gt;npm install -g @angular/cli&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.NET 10 SDK&lt;/strong&gt; — &lt;a href="https://dotnet.microsoft.com/download/dotnet/10.0" rel="noopener noreferrer"&gt;download here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual Studio 2026&lt;/strong&gt; (Latest stable version) or &lt;strong&gt;VS Code&lt;/strong&gt; with the C# Dev Kit extension&lt;/li&gt;
&lt;li&gt;A terminal you are comfortable with (PowerShell, bash, or the VS Code integrated terminal)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can verify your setup by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;    &lt;span class="c"&gt;# v24.x (use latest stable)&lt;/span&gt;
ng version        &lt;span class="c"&gt;# Angular CLI 21.x&lt;/span&gt;
dotnet &lt;span class="nt"&gt;--version&lt;/span&gt;  &lt;span class="c"&gt;# 10.x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Approach 1 — Manual Setup
&lt;/h2&gt;

&lt;p&gt;This approach gives you full control over every detail. It is the best choice if you want to understand how the pieces fit together or if you have specific architectural requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create the Angular App
&lt;/h3&gt;

&lt;p&gt;Open a terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new MyApp.Client &lt;span class="nt"&gt;--style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;scss &lt;span class="nt"&gt;--routing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="nt"&gt;--ssr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false
cd &lt;/span&gt;MyApp.Client
ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to &lt;code&gt;http://localhost:4200&lt;/code&gt; — you should see the default Angular welcome page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create the ASP.NET Core Web API
&lt;/h3&gt;

&lt;p&gt;Open a new terminal in the parent directory and create the API project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new webapi &lt;span class="nt"&gt;-n&lt;/span&gt; MyApp.Api &lt;span class="nt"&gt;--use-controllers&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;MyApp.Api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's add a simple endpoint to test the connection. Open &lt;code&gt;Controllers/WeatherForecastController.cs&lt;/code&gt; — the template already includes a &lt;code&gt;GET /WeatherForecast&lt;/code&gt; endpoint that returns random forecast data. We will use this for our first integration test.&lt;/p&gt;

&lt;p&gt;Run the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API will start on a port shown in the terminal output (e.g. &lt;code&gt;http://localhost:5266&lt;/code&gt;). You can verify it by navigating to &lt;code&gt;http://localhost:{port}/WeatherForecast&lt;/code&gt; in your browser. Take note of this port — you will need it for the proxy configuration in Step 4.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Configure CORS
&lt;/h3&gt;

&lt;p&gt;By default, your Angular app on &lt;code&gt;localhost:4200&lt;/code&gt; cannot call the API on &lt;code&gt;localhost:5001&lt;/code&gt; because of the browser's same-origin policy. We need to enable CORS on the API side.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;Program.cs&lt;/code&gt; and add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenApi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Add CORS policy&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Angular"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithOrigins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:4200"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowAnyHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AllowAnyMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDevelopment&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapOpenApi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHttpsRedirection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Use the CORS policy&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Angular"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapControllers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This CORS configuration is for development only. In production, you should restrict the allowed origins to your actual domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Set Up the Angular Proxy
&lt;/h3&gt;

&lt;p&gt;While CORS works, a cleaner approach during development is to use Angular's built-in proxy. This way, the Angular dev server forwards API requests to the backend, and you avoid CORS entirely.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;proxy.conf.json&lt;/code&gt; in the root of your Angular project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"/WeatherForecast"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:5266"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"secure"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"changeOrigin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Replace &lt;code&gt;5266&lt;/code&gt; with the actual port your API is running on. You can find it in the terminal output when you run &lt;code&gt;dotnet run&lt;/code&gt; — look for the line that says &lt;code&gt;Now listening on: http://localhost:XXXX&lt;/code&gt;. Also, we are proxying the &lt;code&gt;/WeatherForecast&lt;/code&gt; path directly because the default .NET template does not use an &lt;code&gt;/api&lt;/code&gt; prefix. In a real project, you would typically add a common prefix like &lt;code&gt;/api&lt;/code&gt; to all your controllers (using &lt;code&gt;[Route("api/[controller]")]&lt;/code&gt;) and proxy that single prefix instead.&lt;/p&gt;

&lt;p&gt;Update &lt;code&gt;angular.json&lt;/code&gt; to use the proxy. Find the &lt;code&gt;serve&lt;/code&gt; section and add the &lt;code&gt;proxyConfig&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"serve"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"proxyConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"proxy.conf.json"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now restart the Angular dev server with &lt;code&gt;ng serve&lt;/code&gt;. Any request to &lt;code&gt;/WeatherForecast&lt;/code&gt; from your Angular app will be forwarded to the .NET backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Make the First API Call
&lt;/h3&gt;

&lt;p&gt;Let's update the root component to fetch weather data from the API. First, we need to configure &lt;code&gt;HttpClient&lt;/code&gt;. Open &lt;code&gt;src/app/app.config.ts&lt;/code&gt; and add &lt;code&gt;provideHttpClient()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideHttpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.routes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;provideHttpClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now open &lt;code&gt;src/app/app.ts&lt;/code&gt; and update it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;WeatherForecast&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;temperatureC&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;temperatureF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;forecasts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WeatherForecast&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;WeatherForecast&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/WeatherForecast&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forecasts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then update &lt;code&gt;src/app/app.html&lt;/code&gt; with the template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Weather Forecast&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
@if (forecasts().length &amp;gt; 0) {
  &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Date&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Temp (C)&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Temp (F)&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Summary&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
      @for (f of forecasts(); track f.date) {
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ f.date }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ f.temperatureC }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ f.temperatureF }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ f.summary }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
      }
    &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and check your browser. You should see the weather data rendered in a table. Your Angular frontend is now talking to your ASP.NET Core backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 2 — Visual Studio Template
&lt;/h2&gt;

&lt;p&gt;If you prefer a faster start with less manual configuration, Visual Studio 2022 ships with a built-in &lt;strong&gt;Angular + ASP.NET Core&lt;/strong&gt; project template.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Visual Studio 2026 and select &lt;strong&gt;Create a new project&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;"ASP.NET Core with Angular"&lt;/strong&gt; and select the template.&lt;/li&gt;
&lt;li&gt;Configure the project name, location, and solution name.&lt;/li&gt;
&lt;li&gt;On the next screen, select &lt;strong&gt;.NET 10&lt;/strong&gt; as the target framework.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Visual Studio generates a solution with two projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;ASP.NET Core&lt;/strong&gt; backend with a sample &lt;code&gt;WeatherForecast&lt;/code&gt; API.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Angular&lt;/strong&gt; frontend with proxy configuration already wired up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Press &lt;strong&gt;F5&lt;/strong&gt; to run the project. Both the backend and the frontend will start together, and you will see a working Angular app fetching data from the API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you get out of the box:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pre-configured proxy (&lt;code&gt;proxy.conf.js&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;HTTPS development certificate setup&lt;/li&gt;
&lt;li&gt;Integrated launch profiles for debugging both projects simultaneously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What you don't get:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication / authorization&lt;/li&gt;
&lt;li&gt;Multi-tenancy&lt;/li&gt;
&lt;li&gt;Role management&lt;/li&gt;
&lt;li&gt;A production-ready UI framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This template is a great starting point for prototypes or simple applications. For enterprise projects, you will need to add these features yourself — or use a framework that includes them. But, be aware that this option may have problems time to time because some pf the NPM packages intorduce breaking changes and it takes time for maintainer team to release a working version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach 3 — ASP.NET Zero
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aspnetzero.com/" rel="noopener noreferrer"&gt;ASP.NET Zero&lt;/a&gt; is a production-ready starter kit built on ASP.NET Core that supports &lt;strong&gt;Angular&lt;/strong&gt;, &lt;strong&gt;React&lt;/strong&gt;, and &lt;strong&gt;MVC (Razor)&lt;/strong&gt; as frontend options. It is designed specifically for enterprise applications and includes dozens of features out of the box.&lt;/p&gt;

&lt;p&gt;Here is how to get started:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://aspnetzero.com/" rel="noopener noreferrer"&gt;aspnetzero.com&lt;/a&gt; and sign up for a license.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;Download&lt;/strong&gt; page, select &lt;strong&gt;Angular&lt;/strong&gt; as your frontend, and download the project.&lt;/li&gt;
&lt;li&gt;Open the solution in Visual Studio or VS Code.&lt;/li&gt;
&lt;li&gt;Update the database connection string in &lt;code&gt;appsettings.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run the &lt;code&gt;migrator&lt;/code&gt; project to create and seed the database:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;src/MyProject.Migrator
dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the backend:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;src/MyProject.Web.Host
dotnet run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the Angular frontend:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;angular
yarn 
yarn create-dynamic-bundles
yarn start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to &lt;code&gt;http://localhost:4200&lt;/code&gt; and log in with the default admin credentials. You will see a fully working enterprise application.&lt;/p&gt;

&lt;p&gt;To run the project propertly, you can follow &lt;a href="https://docs.aspnetzero.com/aspnet-core-angular/latest/Getting-Started-Angular" rel="noopener noreferrer"&gt;Angular Getting Started Document&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you get out of the box:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication &amp;amp; Authorization:&lt;/strong&gt; Login, registration, two-factor authentication, social logins, LDAP/Active Directory integration — all pre-built and configurable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Tenancy:&lt;/strong&gt; Host/tenant architecture with separate databases or shared database options. Tenant registration, subscription management, and edition management are built in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role &amp;amp; Permission Management:&lt;/strong&gt; A granular permission system with role-based and user-based authorization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organization Units:&lt;/strong&gt; Hierarchical organizational structure with the ability to assign users and roles per unit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Logging:&lt;/strong&gt; Every action is logged with user, timestamp, and change details.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Notifications:&lt;/strong&gt; Built-in notification system with SignalR integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI Theme:&lt;/strong&gt; A polished admin theme based on Metronic with responsive design, dark mode, and multiple layout options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Power Tools:&lt;/strong&gt; A Visual Studio extension and a CLI tool that generates &lt;strong&gt;entities, DTOs, application services, API controllers, Angular components, and unit tests&lt;/strong&gt; from a simple entity definition. Instead of writing CRUD code manually, you describe your entity and Power Tools generates everything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see Power Tools in action. Say you want to add a &lt;code&gt;Product&lt;/code&gt; entity to your application. You define the entity fields (Name, Price, Category, etc.) in Power Tools, click &lt;strong&gt;Generate&lt;/strong&gt;, and it creates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Product&lt;/code&gt; entity and database migration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProductAppService&lt;/code&gt; with full CRUD operations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProductDto&lt;/code&gt; and &lt;code&gt;CreateProductDto&lt;/code&gt; classes&lt;/li&gt;
&lt;li&gt;Angular components for listing, creating, and editing products&lt;/li&gt;
&lt;li&gt;Unit tests for the app service&lt;/li&gt;
&lt;li&gt;UI tests for your Angular pages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What would take hours of boilerplate coding is done in under a minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison
&lt;/h2&gt;

&lt;p&gt;Here is how the three approaches compare:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Manual Setup&lt;/th&gt;
&lt;th&gt;VS Template&lt;/th&gt;
&lt;th&gt;ASP.NET Zero&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup time&lt;/td&gt;
&lt;td&gt;30-60 min&lt;/td&gt;
&lt;td&gt;5 min&lt;/td&gt;
&lt;td&gt;10 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authorization / Roles&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-tenancy&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Organization units&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit logging&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UI theme&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Metronic (production-ready)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code generation tools&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Power Tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real-time notifications&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;You build it&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning value&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexibility&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;Full (source code included)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Licensed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Bottom line:&lt;/strong&gt; If you are learning or building a simple prototype, the manual setup or VS template is perfect. If you are building an enterprise application and want to skip months of infrastructure work, ASP.NET Zero gives you a massive head start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Issues and Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CORS Errors
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; The browser console shows &lt;code&gt;Access to XMLHttpRequest has been blocked by CORS policy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Make sure your &lt;code&gt;Program.cs&lt;/code&gt; includes the CORS middleware and that &lt;code&gt;app.UseCors()&lt;/code&gt; is called &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;app.UseAuthorization()&lt;/code&gt;. Also verify that the origin URL matches exactly (including the port number and protocol).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Correct order&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseCors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Angular"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Proxy Not Working
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; API calls return 404 or the Angular app tries to serve the request itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Double-check the &lt;code&gt;proxy.conf.json&lt;/code&gt; path in &lt;code&gt;angular.json&lt;/code&gt;. Make sure the &lt;code&gt;target&lt;/code&gt; URL matches the port your API is running on. Restart &lt;code&gt;ng serve&lt;/code&gt; after any proxy configuration change — the proxy config is only read at startup.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSL Certificate Errors
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; &lt;code&gt;ERR_CERT_AUTHORITY_INVALID&lt;/code&gt; or proxy shows &lt;code&gt;UNABLE_TO_VERIFY_LEAF_SIGNATURE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; For development, set &lt;code&gt;"secure": false&lt;/code&gt; in your &lt;code&gt;proxy.conf.json&lt;/code&gt;. This tells the Angular dev server to accept self-signed certificates. Alternatively, trust the .NET development certificate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet dev-certs https &lt;span class="nt"&gt;--trust&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Angular CLI Version Mismatch
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Symptom:&lt;/strong&gt; Build errors or unexpected behavior after creating the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Make sure your global Angular CLI version matches the version in the project's &lt;code&gt;package.json&lt;/code&gt;. You can check with &lt;code&gt;ng version&lt;/code&gt; and update with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @angular/cli@19
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Now that your Angular + ASP.NET Core project is up and running, here are some next steps depending on which approach you chose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Add authentication:&lt;/strong&gt; If you went with the manual setup or VS template, check out the &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity" rel="noopener noreferrer"&gt;ASP.NET Core Identity documentation&lt;/a&gt; to add login and registration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore ASP.NET Zero:&lt;/strong&gt; If you are interested in the enterprise approach, &lt;a href="https://aspnetzero.com/contact" rel="noopener noreferrer"&gt;contact&lt;/a&gt; ASP.NET Zero Team and explore the &lt;a href="https://docs.aspnetzero.com/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. The Angular getting started guide will have you running in under 10 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try Power Tools:&lt;/strong&gt; If you are already using ASP.NET Zero, generate your first entity with &lt;a href="https://docs.aspnetzero.com/development-guide/rad-tool" rel="noopener noreferrer"&gt;Power Tools&lt;/a&gt; and see how much time it saves.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building enterprise applications is hard. Choosing the right foundation makes it significantly easier. Whether you start from scratch or stand on the shoulders of a mature framework, Angular and ASP.NET Core together give you a rock-solid stack for 2026 and beyond.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>dotnet</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What .NET 10 LTS Means for Enterprise Applications</title>
      <dc:creator>ismail Cagdas</dc:creator>
      <pubDate>Wed, 21 Jan 2026 05:45:09 +0000</pubDate>
      <link>https://dev.to/ismcagdas/what-net-10-lts-means-for-enterprise-applications-2cdh</link>
      <guid>https://dev.to/ismcagdas/what-net-10-lts-means-for-enterprise-applications-2cdh</guid>
      <description>&lt;p&gt;If you are running enterprise applications on .NET 8 or .NET 9, there is an important date you need to mark on your calendar: &lt;strong&gt;November 10, 2026&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On that day, both .NET 8 and .NET 9 will reach end of support—simultaneously. This is not a typo. Due to Microsoft's decision to extend Standard Term Support (STS) from 18 to 24 months, both versions now share the same end-of-life date.&lt;/p&gt;

&lt;p&gt;This creates a unique situation for enterprise teams: whether you played it safe with .NET 8 LTS or chased the latest features with .NET 9, you now face the same migration deadline.&lt;/p&gt;

&lt;p&gt;The target? &lt;strong&gt;.NET 10 LTS&lt;/strong&gt;, released in November 2025 and supported until &lt;strong&gt;November 2028&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Support Timeline You Need to Understand
&lt;/h2&gt;

&lt;p&gt;Microsoft follows a predictable release cadence: even-numbered releases are Long Term Support (LTS) with three years of support, while odd-numbered releases are Standard Term Support (STS) with 18-24 months.&lt;/p&gt;

&lt;p&gt;Here is the current state of .NET support:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Release Type&lt;/th&gt;
&lt;th&gt;End of Support&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.NET 6&lt;/td&gt;
&lt;td&gt;LTS&lt;/td&gt;
&lt;td&gt;November 12, 2024 (Already EOL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 7&lt;/td&gt;
&lt;td&gt;STS&lt;/td&gt;
&lt;td&gt;May 14, 2024 (Already EOL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 8&lt;/td&gt;
&lt;td&gt;LTS&lt;/td&gt;
&lt;td&gt;November 10, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 9&lt;/td&gt;
&lt;td&gt;STS&lt;/td&gt;
&lt;td&gt;November 10, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 10&lt;/td&gt;
&lt;td&gt;LTS&lt;/td&gt;
&lt;td&gt;November 10, 2028&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are still running .NET 6 or .NET 7, you are already operating on unsupported frameworks. No security patches. No bug fixes. This is a compliance risk that needs immediate attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why .NET 10 LTS Matters for Enterprise
&lt;/h2&gt;

&lt;p&gt;Every two years, Microsoft releases an LTS version. Usually, it is the "safe" choice—the boring, stable option that enterprises pick while developers chase newer features. This time is different.&lt;/p&gt;

&lt;p&gt;.NET 10 LTS is not just a stability release. It is a significant leap forward in performance, security, and AI readiness.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Performance That Impacts Your Bottom Line
&lt;/h3&gt;

&lt;p&gt;The performance improvements in .NET 10 are not incremental. Real-world benchmarks show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;30-50% performance improvements&lt;/strong&gt; from JIT inlining, method devirtualization, and stack allocation optimizations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;40-60% reduction in memory usage&lt;/strong&gt; through array interface de-virtualization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;60-80% improvements&lt;/strong&gt; in specific high-throughput scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For enterprise applications, this translates directly to infrastructure savings. If your cloud bill is tied to CPU and memory consumption, .NET 10 can meaningfully reduce your costs without changing a single line of business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Security and Compliance Acceleration
&lt;/h3&gt;

&lt;p&gt;Enterprise applications live and die by compliance requirements. .NET 10 strengthens your security posture through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Updated cipher suites&lt;/strong&gt; with modern cryptographic standards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved request validation&lt;/strong&gt; and hardened default configurations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced vulnerability patching workflows&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-quantum cryptography support&lt;/strong&gt; via Windows CNG&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point deserves attention. Financial services, government contractors, and healthcare organizations are already being asked about quantum-resistant encryption strategies. .NET 10's built-in post-quantum cryptography support checks that compliance box automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. AI-Ready Infrastructure
&lt;/h3&gt;

&lt;p&gt;.NET 10 arrives with built-in AI integration through the new &lt;strong&gt;Microsoft Agent Framework&lt;/strong&gt;. Combined with expanded &lt;strong&gt;ML.NET&lt;/strong&gt; capabilities and new &lt;strong&gt;tensor APIs&lt;/strong&gt;, your applications are positioned to integrate AI features without bolting on external dependencies.&lt;/p&gt;

&lt;p&gt;This is not about hype. It is about having the foundation in place when your business stakeholders inevitably ask for AI-powered features.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Entity Framework Core 10: Enterprise Data Features
&lt;/h3&gt;

&lt;p&gt;For data-driven enterprise applications, EF Core 10 brings two significant additions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vector search support&lt;/strong&gt; for SQL Server 2025 and Azure SQL Database—enabling embeddings and similarity search directly in your ORM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native JSON type support&lt;/strong&gt; for the new SQL Server JSON data type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your roadmap includes semantic search, recommendation engines, or any AI/ML features that rely on vector embeddings, EF Core 10 eliminates the need for specialized vector databases in many scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration Decision Matrix
&lt;/h2&gt;

&lt;p&gt;Not every organization has the same constraints. Here is how to think about your migration strategy:&lt;/p&gt;

&lt;h3&gt;
  
  
  If You Are on .NET 9
&lt;/h3&gt;

&lt;p&gt;This is the easiest path. You are moving from a 2-year STS window to a 3-year LTS window. Most projects can complete this migration in &lt;strong&gt;2-5 days&lt;/strong&gt;. The breaking changes are minimal, and you gain 2.5 additional years of support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; Migrate immediately. There is no reason to wait.&lt;/p&gt;

&lt;h3&gt;
  
  
  If You Are on .NET 8 LTS
&lt;/h3&gt;

&lt;p&gt;You have until November 2026, but do not let that create complacency. The performance improvements alone justify an earlier migration. Plan your upgrade cycle for Q2 2026 at the latest to allow buffer for testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; Start planning now. Execute migration by mid-2026.&lt;/p&gt;

&lt;h3&gt;
  
  
  If You Are on .NET 6 or .NET 7
&lt;/h3&gt;

&lt;p&gt;You are running unsupported frameworks. Every day without patches is a day of accumulated security risk. This is not a feature migration—it is a critical security remediation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; Treat this as a P1 priority. Migrate immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  If You Are on .NET Framework 4.8
&lt;/h3&gt;

&lt;p&gt;The jump to .NET 10 is significant but achievable. Modern tooling, including AI-assisted migration with GitHub Copilot, makes this transformation practical. The benefits—cross-platform support, containerization, modern performance—justify the investment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt; Begin assessment now. Plan a phased migration over the next 12-18 months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tooling Requirements: The Visual Studio Question
&lt;/h2&gt;

&lt;p&gt;There is one critical constraint: &lt;strong&gt;.NET 10 requires Visual Studio 2026&lt;/strong&gt;. Visual Studio 2022 cannot target .NET 10 or use C# 14 features.&lt;/p&gt;

&lt;p&gt;For enterprises with standardized development environments, this means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;VS Code + C# Dev Kit&lt;/strong&gt; is a fully supported alternative available today&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual Studio 2026&lt;/strong&gt; GA is expected in early 2026&lt;/li&gt;
&lt;li&gt;Most enterprises should wait for VS 2026 GA before full rollout, but developers can start with VS Code immediately&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not a blocker, but it does need to factor into your planning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Changes to Prepare For
&lt;/h2&gt;

&lt;p&gt;Every major release brings breaking changes. Here are the ones that will impact most enterprise applications:&lt;/p&gt;

&lt;h3&gt;
  
  
  WebHostBuilder and IWebHost Are Obsolete
&lt;/h3&gt;

&lt;p&gt;The legacy hosting model is deprecated. If your applications still use &lt;code&gt;WebHostBuilder&lt;/code&gt;, you need to migrate to &lt;code&gt;WebApplicationBuilder&lt;/code&gt;. This is the direction Microsoft has been pushing since .NET 6, and .NET 10 makes it explicit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WebHostBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseKestrel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseStartup&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Startup&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Configure services&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Configure middleware&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WithOpenApi Extension Method Removed
&lt;/h3&gt;

&lt;p&gt;If you are using the &lt;code&gt;WithOpenApi()&lt;/code&gt; extension method for minimal APIs, it has been removed. Use the updated OpenAPI generator features instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Default Images Now Use Ubuntu
&lt;/h3&gt;

&lt;p&gt;.NET container images now default to Ubuntu instead of Debian. If your deployment pipelines or Dockerfiles assume Debian-specific packages, you will need to update them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-Year Runway
&lt;/h2&gt;

&lt;p&gt;.NET 10 LTS support extends until November 2028. This gives your organization three full years to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stabilize on a modern, performant runtime&lt;/li&gt;
&lt;li&gt;Adopt AI and ML features at your own pace&lt;/li&gt;
&lt;li&gt;Plan the next major upgrade cycle without pressure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare this to the version hopscotch of STS releases. For enterprise applications that value stability and predictability, .NET 10 LTS is the clear choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: The Time to Act Is Now
&lt;/h2&gt;

&lt;p&gt;The convergence of .NET 8 and .NET 9 end-of-support dates creates a forcing function. Every .NET application in your portfolio needs to be on .NET 10 by November 2026.&lt;/p&gt;

&lt;p&gt;But this is not just about avoiding end-of-life. .NET 10 delivers genuine improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance gains&lt;/strong&gt; that reduce infrastructure costs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security features&lt;/strong&gt; that accelerate compliance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI integration&lt;/strong&gt; that positions you for the future&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three years of LTS support&lt;/strong&gt; that provides stability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start your assessment now. Identify your applications, understand your dependencies, and plan your migration timeline. The runway to November 2026 is shorter than it appears.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>dotnetcore</category>
      <category>dotnetframework</category>
    </item>
    <item>
      <title>A Review of AI-Assisted Development Tools and My Workflow</title>
      <dc:creator>ismail Cagdas</dc:creator>
      <pubDate>Thu, 15 Jan 2026 11:28:22 +0000</pubDate>
      <link>https://dev.to/ismcagdas/a-review-of-ai-assisted-development-tools-and-my-workflow-39fl</link>
      <guid>https://dev.to/ismcagdas/a-review-of-ai-assisted-development-tools-and-my-workflow-39fl</guid>
      <description>&lt;p&gt;The world of software development is buzzing with the promise of Artificial Intelligence, and like many of you, I've been exploring the growing landscape of AI-assisted development tools. As a .NET/ASP.NET Core developer and open-source contributor, I've been piecing together a workflow that helps me leverage these powerful assistants. It's been a journey of discovery, full of pleasant surprises and a few hurdles.&lt;/p&gt;

&lt;p&gt;Here's a look at the tools in my current rotation and the workflow I've settled on for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  My AI Toolkit: A Review of Development Assistants
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Vibe Kanban: The Mission Control
&lt;/h3&gt;

&lt;p&gt;I start most of my tasks in Vibe Kanban. Its strength lies in its flexibility. I can connect it to multiple repositories and, more importantly, assign different AI models to different tasks. I have access to GitHub Copilot, Gemini, and Claude, and Vibe Kanban lets me switch between them seamlessly. This is perfect for running multiple tasks in parallel, though I've found that reviewing the generated output is still a time-consuming but necessary step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcf5msiw0xa9g5z4gld1o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcf5msiw0xa9g5z4gld1o.jpg" alt=" " width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude: The Master Planner
&lt;/h3&gt;

&lt;p&gt;Claude is my go-to for planning. I find it's excellent at understanding programming concepts and laying out a structured plan. The main drawback is the token expiration, which can sometimes be a bit of a nuisance. If I have enouhg limit, mostly I ask Claude to implement Phase 1 of the plan it created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F344h52cbz0l1w1bszeqe.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F344h52cbz0l1w1bszeqe.jpg" alt=" " width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor: The Coder
&lt;/h3&gt;

&lt;p&gt;When it's time to write code, I turn to Cursor. Its "auto mode" is a standout feature, as it's incredibly efficient with token usage, which is a major concern in AI-assisted development. However, as a .NET developer, I sometimes find it challenging to work on my projects within Cursor and occasionally have to switch back to Rider or Visual Studio for certain tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gemini: The Technical Writer
&lt;/h3&gt;

&lt;p&gt;Interestingly, I don't use Gemini much for coding. Instead, it has become my trusted partner for writing technical articles and documentation. In this area, it truly excels.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Copilot: The Dependable Backup
&lt;/h3&gt;

&lt;p&gt;I use GitHub Copilot less frequently than the others, but it's a reliable tool for smaller tasks, especially when I've run out of tokens on other platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  My AI-Powered Development Workflow
&lt;/h2&gt;

&lt;p&gt;My process has evolved into a multi-stage workflow that leverages the strengths of different AI tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Plan with Claude&lt;/strong&gt;: I start by asking Claude to create a detailed plan in a markdown format using Vibe Kanban.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Review and Refine&lt;/strong&gt;: I thoroughly review the plan. If any adjustments are needed, I'll work with Claude to refine it.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Branch and Commit&lt;/strong&gt;: Once the plan is solid, I create a new branch and commit the plan file. This provides clear context for the work that follows.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Code with Cursor&lt;/strong&gt;: With the plan in hand, I open Cursor and begin the development work, following the roadmap laid out by Claude.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;AI-Assisted Review&lt;/strong&gt;: After the initial coding is done, I use another AI to review the changes and suggest improvements.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Manual Verification&lt;/strong&gt;: The final step is always a manual review and testing of the functionality to ensure everything works as expected.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;My next goal is to automate the testing phase. I plan to create a process that runs automated tests before I begin my manual review, which should help streamline the final verification step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Your Workflow?
&lt;/h2&gt;

&lt;p&gt;This is just a snapshot of my current process, and I'm sure it will continue to evolve. I'm curious to hear about your experiences. What tools are you using for AI-assisted development, and what does your workflow look like? Feel free to share your thoughts and recommendations!&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>vibecoding</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>An Opinionated Solution Structure for ASP.NET Core Projects</title>
      <dc:creator>ismail Cagdas</dc:creator>
      <pubDate>Mon, 12 Jan 2026 12:23:07 +0000</pubDate>
      <link>https://dev.to/ismcagdas/an-opinionated-solution-structure-for-aspnet-core-projects-8ld</link>
      <guid>https://dev.to/ismcagdas/an-opinionated-solution-structure-for-aspnet-core-projects-8ld</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0u1sz70p6tqgemwmzh84.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0u1sz70p6tqgemwmzh84.png" alt=" " width="800" height="436"&gt;&lt;/a&gt;&lt;br&gt;
As software projects grow, maintaining a clean and organized codebase becomes increasingly challenging. A well-thought-out solution structure can make the difference between a maintainable application and a tangled mess of dependencies. In this article, I'll walk you through the opinionated solution structure we use in &lt;a href="https://github.com/abpframework/abp" rel="noopener noreferrer"&gt;ABP Framework&lt;/a&gt; — a structure that has proven itself in thousands of production applications.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Solution Structure Matters
&lt;/h2&gt;

&lt;p&gt;Before diving into the details, let's understand why investing time in your solution structure pays off:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability&lt;/strong&gt;: Clear boundaries make code easier to understand and modify&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: Well-separated layers are easier to test in isolation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Collaboration&lt;/strong&gt;: Developers can work on different layers without conflicts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: A good structure grows with your application&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Root Level
&lt;/h2&gt;

&lt;p&gt;We have a sample project named Acme.BookStore. I will try to explain the solution structure using this sample ASP.NET Core application.&lt;br&gt;
Let's start with what you'll find at the root of the solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Acme.BookStore/
├── src/                    # Source projects
├── test/                   # Test projects
├── Acme.BookStore.sln      # Solution file
├── common.props            # Shared MSBuild properties
├── global.json             # SDK version pinning
└── NuGet.Config            # Package source configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The separation of &lt;code&gt;src/&lt;/code&gt; and &lt;code&gt;test/&lt;/code&gt; folders provides immediate clarity. The &lt;code&gt;common.props&lt;/code&gt; file centralizes build configurations, ensuring consistency across all projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Projects: A Layered Architecture
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;src/&lt;/code&gt; folder contains the heart of your application, organized into distinct layers:&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Shared (&lt;code&gt;Acme.BookStore.Domain.Shared&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This is the foundation layer with &lt;strong&gt;zero dependencies&lt;/strong&gt; on other project layers. It contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Constants and enums&lt;/li&gt;
&lt;li&gt;Shared value objects&lt;/li&gt;
&lt;li&gt;Localization resources&lt;/li&gt;
&lt;li&gt;Exception codes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: BookType enum that can be shared across all layers&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;BookType&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Adventure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Biography&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Fiction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Science&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why separate this?&lt;/strong&gt; These elements are often needed by multiple layers and even external clients. Keeping them in a dedicated project prevents circular dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain (&lt;code&gt;Acme.BookStore.Domain&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The core business logic lives here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entities&lt;/strong&gt; and aggregate roots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository interfaces&lt;/strong&gt; (not implementations!)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain services&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain events&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AggregateRoot&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;BookType&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;PublishDate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This layer is &lt;strong&gt;infrastructure-agnostic&lt;/strong&gt; — it doesn't know about databases, APIs, or UI frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Contracts (&lt;code&gt;Acme.BookStore.Application.Contracts&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This project defines the &lt;strong&gt;application layer's public API&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data Transfer Objects (DTOs)&lt;/li&gt;
&lt;li&gt;Application service interfaces&lt;/li&gt;
&lt;li&gt;Permission definitions
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IBookAppService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IApplicationService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PagedResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetBookListDto&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateBookDto&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key benefit&lt;/strong&gt;: This project can be shared with clients (like a Blazor WebAssembly app) without exposing implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application (&lt;code&gt;Acme.BookStore.Application&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Implementation of the application services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application service implementations&lt;/li&gt;
&lt;li&gt;Object mapping configurations&lt;/li&gt;
&lt;li&gt;Business workflow orchestration
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookAppService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApplicationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IBookAppService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_bookRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_bookRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ObjectMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Entity Framework Core (&lt;code&gt;Acme.BookStore.EntityFrameworkCore&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Infrastructure layer for data access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DbContext&lt;/code&gt; implementation&lt;/li&gt;
&lt;li&gt;Repository implementations&lt;/li&gt;
&lt;li&gt;Entity configurations&lt;/li&gt;
&lt;li&gt;Database migrations
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookStoreDbContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AbpDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookStoreDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnModelCreating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OnModelCreating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Books"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;IsRequired&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;HasMaxLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HTTP API (&lt;code&gt;Acme.BookStore.HttpApi&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;API controllers that expose your application services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/books"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AbpController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IBookAppService&lt;/span&gt; &lt;span class="n"&gt;_bookAppService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_bookAppService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HTTP API Client (&lt;code&gt;Acme.BookStore.HttpApi.Client&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This is a powerful pattern — &lt;strong&gt;typed HTTP client proxies&lt;/strong&gt; for consuming your API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Consumers can use IBookAppService directly&lt;/span&gt;
&lt;span class="c1"&gt;// The proxy handles HTTP calls transparently&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_bookAppService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;GetBookListDto&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables code sharing between server and client applications, reducing duplication and ensuring type safety.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web (&lt;code&gt;Acme.BookStore.Web&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The UI layer — whether Razor Pages, Blazor, or MVC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pages/Components&lt;/li&gt;
&lt;li&gt;View models&lt;/li&gt;
&lt;li&gt;Static assets&lt;/li&gt;
&lt;li&gt;UI-specific configurations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Database Migrator (&lt;code&gt;Acme.BookStore.DbMigrator&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;A console application for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running database migrations&lt;/li&gt;
&lt;li&gt;Seeding initial data&lt;/li&gt;
&lt;li&gt;DevOps-friendly deployment scenarios (Like updating all tenant databases if you use database-per tenant approach)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Test Projects: Comprehensive Coverage
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;test/&lt;/code&gt; folder mirrors the source structure:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TestBase&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shared test infrastructure and utilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Domain.Tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unit tests for domain logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Application.Tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Application service integration tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EntityFrameworkCore.Tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Repository and database tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HttpApi.Client.ConsoleTestApp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End-to-end API testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Web.Tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UI layer tests&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This structure makes it clear &lt;strong&gt;what&lt;/strong&gt; you're testing and enables focused test runs during development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Benefits of This Structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Clear Separation of Concerns&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each project has a single, well-defined responsibility. Developers immediately know where to find and place code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Dependency Inversion in Practice&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The domain layer defines repository interfaces; the infrastructure layer implements them. Your business logic remains pure.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Shareable Contracts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;.Domain.Shared&lt;/code&gt; and &lt;code&gt;.Application.Contracts&lt;/code&gt; projects can be packaged as NuGet packages and shared:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Across microservices&lt;/li&gt;
&lt;li&gt;With client applications&lt;/li&gt;
&lt;li&gt;With external integrators&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Testability by Design&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each layer can be tested in isolation with appropriate mocking strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Database Independence&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Switching from SQL Server to PostgreSQL? Only the &lt;code&gt;EntityFrameworkCore&lt;/code&gt; project needs changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Ready for Growth&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This structure naturally evolves into modular monolith or microservices architectures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Monolith: Modular and Microservice Architectures
&lt;/h2&gt;

&lt;p&gt;While this article focuses on a single application structure, the same principles scale beautifully:&lt;/p&gt;

&lt;h3&gt;
  
  
  Modular Monolith
&lt;/h3&gt;

&lt;p&gt;You can organize your solution into &lt;strong&gt;independent modules&lt;/strong&gt;, each following this layered structure. Modules communicate through well-defined interfaces, giving you the benefits of microservices without the operational complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Microservices
&lt;/h3&gt;

&lt;p&gt;Each microservice can follow this exact structure, with the &lt;code&gt;.Domain.Shared&lt;/code&gt; and &lt;code&gt;.Application.Contracts&lt;/code&gt; projects published as NuGet packages for inter-service communication.&lt;/p&gt;

&lt;p&gt;ABP Framework provides comprehensive templates and guidance for both architectures. Check out the &lt;a href="https://github.com/abpframework/abp" rel="noopener noreferrer"&gt;ABP Framework GitHub repository&lt;/a&gt; for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modular application templates&lt;/li&gt;
&lt;li&gt;Microservice solution templates&lt;/li&gt;
&lt;li&gt;Real-world sample applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;If you'd like to try this structure yourself, ABP Framework provides CLI tools to generate solutions with this exact architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; Volo.Abp.Studio.Cli
abp new Acme.BookStore &lt;span class="nt"&gt;-m&lt;/span&gt; none &lt;span class="nt"&gt;--theme&lt;/span&gt; leptonx-lite &lt;span class="nt"&gt;-csf&lt;/span&gt; &lt;span class="nt"&gt;--connection-string&lt;/span&gt; &lt;span class="s2"&gt;"Server=(LocalDb)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;MSSQLLocalDB;Database=BookStore;Trusted_Connection=True;TrustServerCertificate=true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, you can go to &lt;a href="https://abp.io/get-started" rel="noopener noreferrer"&gt;https://abp.io/get-started&lt;/a&gt; page and select other options like PostgreSQL, MongoDB, Angular, Blazor etc...&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A well-organized solution structure is an investment that pays dividends throughout your project's lifecycle. The layered architecture presented here — with its clear separation between domain, application, infrastructure, and presentation layers — provides a solid foundation for building maintainable, testable, and scalable ASP.NET Core applications.&lt;/p&gt;

&lt;p&gt;I encourage you to explore the &lt;a href="https://github.com/abpframework/abp" rel="noopener noreferrer"&gt;ABP Framework on GitHub&lt;/a&gt; to see this structure in action across numerous modules and sample applications. As one of the developers of ABP Framework, I've seen firsthand how this architecture helps teams build robust applications efficiently.&lt;/p&gt;

&lt;p&gt;Whether you're building a simple CRUD application or an enterprise-grade distributed system, starting with a clean structure will serve you well. Happy coding!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions or feedback? Feel free to open an issue on the &lt;a href="https://github.com/abpframework/abp" rel="noopener noreferrer"&gt;ABP Framework GitHub repository&lt;/a&gt; or join our community discussions.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  An Opinionated Solution Structure for ASP.NET Core Projects
&lt;/h1&gt;

&lt;p&gt;As software projects grow, maintaining a clean and organized codebase becomes increasingly challenging. A well-thought-out solution structure can make the difference between a maintainable application and a tangled mess of dependencies. In this article, I'll walk you through the opinionated solution structure we use in &lt;a href="https://github.com/abpframework/abp" rel="noopener noreferrer"&gt;ABP Framework&lt;/a&gt; — a structure that has proven itself in thousands of production applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Solution Structure Matters
&lt;/h2&gt;

&lt;p&gt;Before diving into the details, let's understand why investing time in your solution structure pays off:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability&lt;/strong&gt;: Clear boundaries make code easier to understand and modify&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testability&lt;/strong&gt;: Well-separated layers are easier to test in isolation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team Collaboration&lt;/strong&gt;: Developers can work on different layers without conflicts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: A good structure grows with your application&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Root Level
&lt;/h2&gt;

&lt;p&gt;We have a sample project named Acme.BookStore. I will try to explain the solution structure using this sample ASP.NET Core application.&lt;br&gt;
Let's start with what you'll find at the root of the solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Acme.BookStore/
├── src/                    # Source projects
├── test/                   # Test projects
├── Acme.BookStore.sln      # Solution file
├── common.props            # Shared MSBuild properties
├── global.json             # SDK version pinning
└── NuGet.Config            # Package source configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The separation of &lt;code&gt;src/&lt;/code&gt; and &lt;code&gt;test/&lt;/code&gt; folders provides immediate clarity. The &lt;code&gt;common.props&lt;/code&gt; file centralizes build configurations, ensuring consistency across all projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Projects: A Layered Architecture
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;src/&lt;/code&gt; folder contains the heart of your application, organized into distinct layers:&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain Shared (&lt;code&gt;Acme.BookStore.Domain.Shared&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This is the foundation layer with &lt;strong&gt;zero dependencies&lt;/strong&gt; on other project layers. It contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Constants and enums&lt;/li&gt;
&lt;li&gt;Shared value objects&lt;/li&gt;
&lt;li&gt;Localization resources&lt;/li&gt;
&lt;li&gt;Exception codes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: BookType enum that can be shared across all layers&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;BookType&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Adventure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Biography&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Fiction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Science&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why separate this?&lt;/strong&gt; These elements are often needed by multiple layers and even external clients. Keeping them in a dedicated project prevents circular dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain (&lt;code&gt;Acme.BookStore.Domain&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The core business logic lives here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entities&lt;/strong&gt; and aggregate roots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository interfaces&lt;/strong&gt; (not implementations!)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain services&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain events&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AggregateRoot&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;BookType&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;PublishDate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This layer is &lt;strong&gt;infrastructure-agnostic&lt;/strong&gt; — it doesn't know about databases, APIs, or UI frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Contracts (&lt;code&gt;Acme.BookStore.Application.Contracts&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This project defines the &lt;strong&gt;application layer's public API&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data Transfer Objects (DTOs)&lt;/li&gt;
&lt;li&gt;Application service interfaces&lt;/li&gt;
&lt;li&gt;Permission definitions
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IBookAppService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IApplicationService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PagedResultDto&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetBookListDto&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateBookDto&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key benefit&lt;/strong&gt;: This project can be shared with clients (like a Blazor WebAssembly app) without exposing implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Application (&lt;code&gt;Acme.BookStore.Application&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Implementation of the application services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application service implementations&lt;/li&gt;
&lt;li&gt;Object mapping configurations&lt;/li&gt;
&lt;li&gt;Business workflow orchestration
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookAppService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApplicationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IBookAppService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_bookRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_bookRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ObjectMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Entity Framework Core (&lt;code&gt;Acme.BookStore.EntityFrameworkCore&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Infrastructure layer for data access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DbContext&lt;/code&gt; implementation&lt;/li&gt;
&lt;li&gt;Repository implementations&lt;/li&gt;
&lt;li&gt;Entity configurations&lt;/li&gt;
&lt;li&gt;Database migrations
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookStoreDbContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AbpDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookStoreDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Books&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnModelCreating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OnModelCreating&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToTable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Books"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;IsRequired&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;HasMaxLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HTTP API (&lt;code&gt;Acme.BookStore.HttpApi&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;API controllers that expose your application services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/books"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AbpController&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IBookAppService&lt;/span&gt; &lt;span class="n"&gt;_bookAppService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_bookAppService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HTTP API Client (&lt;code&gt;Acme.BookStore.HttpApi.Client&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;This is a powerful pattern — &lt;strong&gt;typed HTTP client proxies&lt;/strong&gt; for consuming your API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Consumers can use IBookAppService directly&lt;/span&gt;
&lt;span class="c1"&gt;// The proxy handles HTTP calls transparently&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_bookAppService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;GetBookListDto&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables code sharing between server and client applications, reducing duplication and ensuring type safety.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web (&lt;code&gt;Acme.BookStore.Web&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The UI layer — whether Razor Pages, Blazor, or MVC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pages/Components&lt;/li&gt;
&lt;li&gt;View models&lt;/li&gt;
&lt;li&gt;Static assets&lt;/li&gt;
&lt;li&gt;UI-specific configurations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Database Migrator (&lt;code&gt;Acme.BookStore.DbMigrator&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;A console application for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running database migrations&lt;/li&gt;
&lt;li&gt;Seeding initial data&lt;/li&gt;
&lt;li&gt;DevOps-friendly deployment scenarios (Like updating all tenant databases if you use database-per tenant approach)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Test Projects: Comprehensive Coverage
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;test/&lt;/code&gt; folder mirrors the source structure:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TestBase&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shared test infrastructure and utilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Domain.Tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unit tests for domain logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Application.Tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Application service integration tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EntityFrameworkCore.Tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Repository and database tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HttpApi.Client.ConsoleTestApp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End-to-end API testing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Web.Tests&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UI layer tests&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This structure makes it clear &lt;strong&gt;what&lt;/strong&gt; you're testing and enables focused test runs during development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Benefits of This Structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Clear Separation of Concerns&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each project has a single, well-defined responsibility. Developers immediately know where to find and place code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Dependency Inversion in Practice&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The domain layer defines repository interfaces; the infrastructure layer implements them. Your business logic remains pure.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Shareable Contracts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;.Domain.Shared&lt;/code&gt; and &lt;code&gt;.Application.Contracts&lt;/code&gt; projects can be packaged as NuGet packages and shared:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Across microservices&lt;/li&gt;
&lt;li&gt;With client applications&lt;/li&gt;
&lt;li&gt;With external integrators&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Testability by Design&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Each layer can be tested in isolation with appropriate mocking strategies.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Database Independence&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Switching from SQL Server to PostgreSQL? Only the &lt;code&gt;EntityFrameworkCore&lt;/code&gt; project needs changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Ready for Growth&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This structure naturally evolves into modular monolith or microservices architectures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Monolith: Modular and Microservice Architectures
&lt;/h2&gt;

&lt;p&gt;While this article focuses on a single application structure, the same principles scale beautifully:&lt;/p&gt;

&lt;h3&gt;
  
  
  Modular Monolith
&lt;/h3&gt;

&lt;p&gt;You can organize your solution into &lt;strong&gt;independent modules&lt;/strong&gt;, each following this layered structure. Modules communicate through well-defined interfaces, giving you the benefits of microservices without the operational complexity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Microservices
&lt;/h3&gt;

&lt;p&gt;Each microservice can follow this exact structure, with the &lt;code&gt;.Domain.Shared&lt;/code&gt; and &lt;code&gt;.Application.Contracts&lt;/code&gt; projects published as NuGet packages for inter-service communication.&lt;/p&gt;

&lt;p&gt;ABP Framework provides comprehensive templates and guidance for both architectures. Check out the &lt;a href="https://github.com/abpframework/abp" rel="noopener noreferrer"&gt;ABP Framework GitHub repository&lt;/a&gt; for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modular application templates&lt;/li&gt;
&lt;li&gt;Microservice solution templates&lt;/li&gt;
&lt;li&gt;Real-world sample applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;If you'd like to try this structure yourself, ABP Framework provides CLI tools to generate solutions with this exact architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; Volo.Abp.Studio.Cli
abp new Acme.BookStore &lt;span class="nt"&gt;-m&lt;/span&gt; none &lt;span class="nt"&gt;--theme&lt;/span&gt; leptonx-lite &lt;span class="nt"&gt;-csf&lt;/span&gt; &lt;span class="nt"&gt;--connection-string&lt;/span&gt; &lt;span class="s2"&gt;"Server=(LocalDb)&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;MSSQLLocalDB;Database=BookStore;Trusted_Connection=True;TrustServerCertificate=true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, you can go to &lt;a href="https://abp.io/get-started" rel="noopener noreferrer"&gt;https://abp.io/get-started&lt;/a&gt; page and select other options like PostgreSQL, MongoDB, Angular, Blazor etc...&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A well-organized solution structure is an investment that pays dividends throughout your project's lifecycle. The layered architecture presented here — with its clear separation between domain, application, infrastructure, and presentation layers — provides a solid foundation for building maintainable, testable, and scalable ASP.NET Core applications.&lt;/p&gt;

&lt;p&gt;I encourage you to explore the &lt;a href="https://github.com/abpframework/abp" rel="noopener noreferrer"&gt;ABP Framework on GitHub&lt;/a&gt; to see this structure in action across numerous modules and sample applications. As one of the developers of ABP Framework, I've seen firsthand how this architecture helps teams build robust applications efficiently.&lt;/p&gt;

&lt;p&gt;Whether you're building a simple CRUD application or an enterprise-grade distributed system, starting with a clean structure will serve you well. Happy coding!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions or feedback? Feel free to open an issue on the &lt;a href="https://github.com/abpframework/abp" rel="noopener noreferrer"&gt;ABP Framework GitHub repository&lt;/a&gt; or join our community discussions.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>dotnet</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why Modular Monolith Architecture is the Key to Effective AI-Assisted Development</title>
      <dc:creator>ismail Cagdas</dc:creator>
      <pubDate>Tue, 06 Jan 2026 13:53:35 +0000</pubDate>
      <link>https://dev.to/ismcagdas/why-modular-monolith-architecture-is-the-key-to-effective-ai-assisted-development-3cba</link>
      <guid>https://dev.to/ismcagdas/why-modular-monolith-architecture-is-the-key-to-effective-ai-assisted-development-3cba</guid>
      <description>&lt;p&gt;AI coding assistants have revolutionized how we write code. Tools like GitHub Copilot, Claude, ChatGPT, and Cursor have become indispensable companions for developers worldwide. However, there's a growing challenge that many developers are experiencing: &lt;strong&gt;as your codebase grows, AI-generated code quality decreases significantly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore why this happens and how &lt;a href="https://abp.io" rel="noopener noreferrer"&gt;ABP Framework&lt;/a&gt;'s modular monolith architecture provides an elegant solution to this problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: AI Struggles with Large Codebases
&lt;/h2&gt;

&lt;p&gt;If you've been using AI coding assistants for a while, you've probably noticed a pattern. When you start a new project, AI suggestions are remarkably accurate. The code is clean, follows best practices, and integrates nicely with your existing code. But as your project grows to hundreds of files and thousands of lines of code, something changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context Window Limitations
&lt;/h3&gt;

&lt;p&gt;AI models have a fundamental constraint: &lt;strong&gt;context windows&lt;/strong&gt;. Even the most advanced models can only process a limited amount of code at once. When your project has 500+ files with complex interdependencies, the AI simply cannot see the full picture.&lt;/p&gt;

&lt;p&gt;Consider this scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📁 MyLargeProject/
├── 📁 src/
│   ├── 📁 Domain/ (50+ files)
│   ├── 📁 Application/ (80+ files)
│   ├── 📁 Infrastructure/ (40+ files)
│   ├── 📁 HttpApi/ (60+ files)
│   └── 📁 Web/ (100+ files)
├── 📁 tests/ (150+ files)
└── 📁 shared/ (30+ files)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you ask AI to implement a new feature, it might see only 10-20 of these files in its context. The result? Code that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicates existing functionality&lt;/li&gt;
&lt;li&gt;Violates established patterns in your codebase&lt;/li&gt;
&lt;li&gt;Uses inconsistent naming conventions&lt;/li&gt;
&lt;li&gt;Creates unnecessary coupling between components&lt;/li&gt;
&lt;li&gt;Ignores your custom base classes and utilities&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Consistency Problem
&lt;/h3&gt;

&lt;p&gt;In a large monolithic codebase, there are often multiple ways to accomplish the same task. Your team might have established specific patterns over time, but the AI doesn't know about these conventions unless they're explicitly provided in the context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Your established pattern (which AI doesn't see)&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductAppService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApplicationService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IProductAppService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_productRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ProductAppService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;productRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_productRepository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;productRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProductDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_productRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ObjectMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ProductDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// What AI might generate (inconsistent with your patterns)&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;OrderService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OrderDto&lt;/span&gt; 
        &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;// Manual mapping...&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI-generated code works, but it introduces inconsistency, bypasses your repository abstractions, and ignores your mapping conventions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: Modular Monolith Architecture
&lt;/h2&gt;

&lt;p&gt;This is where ABP Framework's modular monolith architecture shines. Instead of one massive codebase, you organize your application into &lt;strong&gt;isolated modules&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Module in ABP?
&lt;/h3&gt;

&lt;p&gt;An ABP module is a independent unit that encapsulates a specific business capability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📁 Acme.ProductManagement/
├── 📁 src/
│   ├── Acme.ProductManagement.Domain/
│   ├── Acme.ProductManagement.Domain.Shared/
│   ├── Acme.ProductManagement.Application/
│   ├── Acme.ProductManagement.Application.Contracts/
│   ├── Acme.ProductManagement.EntityFrameworkCore/
│   ├── Acme.ProductManagement.HttpApi/
│   └── Acme.ProductManagement.Web/
└── 📁 test/
    └── Acme.ProductManagement.Application.Tests/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each module has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear boundaries&lt;/strong&gt;: Well-defined interfaces for communication with other modules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent domain&lt;/strong&gt;: Its own entities, repositories, and domain services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolated application layer&lt;/strong&gt;: Application services that don't leak into other modules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focused scope&lt;/strong&gt;: Typically 10-30 files per layer, not hundreds&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How This Helps AI
&lt;/h3&gt;

&lt;p&gt;When you work with AI on a modular codebase, you can &lt;strong&gt;scope the conversation to a single module&lt;/strong&gt;. Instead of providing context about your entire 500-file project, you provide context about a 50-file module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"I'm working on the ProductManagement module in an ABP Framework project.
Here's the module structure and key files:
- Product entity (Domain layer)
- IProductRepository interface
- ProductAppService (Application layer)

I need to add a feature to track product price history..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the AI has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A complete picture of the relevant code&lt;/li&gt;
&lt;li&gt;Clear patterns to follow&lt;/li&gt;
&lt;li&gt;Defined boundaries it shouldn't cross&lt;/li&gt;
&lt;li&gt;Consistent conventions throughout&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benefits of Module-Scoped AI Development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Reduced Context Size = Better Understanding
&lt;/h3&gt;

&lt;p&gt;A typical ABP module contains a focused set of files that easily fit within AI context windows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Files&lt;/th&gt;
&lt;th&gt;AI Understanding&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full Monolith&lt;/td&gt;
&lt;td&gt;500+&lt;/td&gt;
&lt;td&gt;Poor - sees fragments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single Module&lt;/td&gt;
&lt;td&gt;30-50&lt;/td&gt;
&lt;td&gt;Excellent - sees everything&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When AI can see your entire module, it understands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How entities relate to each other&lt;/li&gt;
&lt;li&gt;Which base classes and interfaces to use&lt;/li&gt;
&lt;li&gt;Your naming conventions and patterns&lt;/li&gt;
&lt;li&gt;The existing functionality to avoid duplication&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. ABP Conventions Guide the AI
&lt;/h3&gt;

&lt;p&gt;ABP Framework follows strong conventions. When you tell AI you're working with ABP, it can leverage these conventions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI understands ABP patterns and generates consistent code&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CategoryAppService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ProductManagementAppService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ICategoryAppService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ICategoryRepository&lt;/span&gt; &lt;span class="n"&gt;_categoryRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CategoryAppService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ICategoryRepository&lt;/span&gt; &lt;span class="n"&gt;categoryRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_categoryRepository&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;categoryRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductManagementPermissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CategoryDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateCategoryDto&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GuidGenerator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_categoryRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InsertAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ObjectMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CategoryDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI naturally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inherits from the correct base class&lt;/li&gt;
&lt;li&gt;Uses the module's permission definitions&lt;/li&gt;
&lt;li&gt;Follows the repository pattern&lt;/li&gt;
&lt;li&gt;Uses ABP's &lt;code&gt;GuidGenerator&lt;/code&gt; and &lt;code&gt;ObjectMapper&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Easier Code Review
&lt;/h3&gt;

&lt;p&gt;When AI-generated code is confined to a module, code review becomes straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;

 src/Acme.ProductManagement.Domain/Categories/Category.cs        | 25 +++
 src/Acme.ProductManagement.Application/Categories/CategoryAppService.cs | 45 +++
 src/Acme.ProductManagement.HttpApi/Categories/CategoryController.cs     | 30 +++
 3 files changed, 100 insertions&lt;span class="o"&gt;(&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All changes are in one module. Reviewers familiar with that module can quickly validate the code quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Sustainable and Maintainable Code
&lt;/h3&gt;

&lt;p&gt;Modular code generated by AI remains maintainable because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It follows established patterns within the module&lt;/li&gt;
&lt;li&gt;Dependencies are explicit and limited&lt;/li&gt;
&lt;li&gt;The code can be understood in isolation&lt;/li&gt;
&lt;li&gt;Future AI sessions can easily pick up where you left off&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Tips for AI-Assisted ABP Development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tip 1: Provide Module Context Upfront
&lt;/h3&gt;

&lt;p&gt;Start your AI conversation with module context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I'm working on an ABP Framework application.
Current module: Acme.Ordering
Module purpose: Handle customer orders and order processing

Key entities:
- Order (AggregateRoot)
- OrderLine (Entity)
- OrderStatus (Enum)

Existing services:
- IOrderRepository
- OrderManager (Domain Service)
- OrderAppService

I want to add a feature to...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tip 2: Reference ABP Conventions Explicitly
&lt;/h3&gt;

&lt;p&gt;When asking AI to generate code, mention the conventions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate an Application Service for managing Shipments.
Follow ABP conventions:
- Inherit from ApplicationService
- Use IRepository&amp;lt;T, TKey&amp;gt; for data access
- Use ObjectMapper for DTO mapping
- Define permissions in ShipmentPermissions class
- Use [Authorize] attributes for permission checks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the following versions of ABP, these instructions will be included in your project out of the box. So, AI will write better and maintainable code by following ABP standards and best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip 3: Keep Cross-Module Communication Explicit
&lt;/h3&gt;

&lt;p&gt;When your feature spans multiple modules, break it down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step 1: Add the event class in Ordering.Domain.Shared
Step 2: Publish the event from OrderAppService
Step 3: (Separate session) Handle the event in Shipping module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps each AI session focused on one module.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip 4: Use Module Templates as Examples
&lt;/h3&gt;

&lt;p&gt;Provide AI with examples from your existing module code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Here's how we implement app services in this module:

[Example of existing ProductAppService]

Now create a similar service for handling Categories.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tip 5: Validate Within Module Boundaries
&lt;/h3&gt;

&lt;p&gt;After AI generates code, verify it respects module boundaries:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Good&lt;/strong&gt;: Module references only its own layers and shared contracts&lt;br&gt;
❌ &lt;strong&gt;Bad&lt;/strong&gt;: Direct references to other module's domain or application layers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Bad - crossing module boundaries&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Acme.Inventory.Domain&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Direct reference to another module's domain!&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Good - using integration events or shared contracts&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Acme.Inventory.Application.Contracts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Only reference contracts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-World Example: Before and After
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before: AI in a Large Monolith
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: "Add a feature to apply discounts to orders"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI Result&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates discount logic directly in OrderController&lt;/li&gt;
&lt;li&gt;Duplicates validation that exists in another service&lt;/li&gt;
&lt;li&gt;Uses direct database access instead of repositories&lt;/li&gt;
&lt;li&gt;Ignores existing Price calculation utilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time spent fixing&lt;/strong&gt;: 2 hours&lt;/p&gt;

&lt;h3&gt;
  
  
  After: AI with Module Focus
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In the Acme.Ordering module, add discount support.
- Add DiscountInfo value object to Order aggregate
- Add ApplyDiscount method to Order entity
- Update OrderAppService.CreateAsync to accept discount code
- Use existing IDiscountValidator from Ordering.Domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;AI Result&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correctly extends Order aggregate&lt;/li&gt;
&lt;li&gt;Follows existing patterns in the module&lt;/li&gt;
&lt;li&gt;Uses the domain service you mentioned&lt;/li&gt;
&lt;li&gt;Generates consistent, reviewable code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time spent fixing&lt;/strong&gt;: 15 minutes&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The modular monolith architecture isn't just an architectural pattern—it's becoming essential for effective AI-assisted development. As AI tools continue to evolve, codebases that are organized into clear, focused modules will get significantly better results from these tools.&lt;/p&gt;

&lt;p&gt;ABP Framework's modular architecture, with its strong conventions, clear boundaries, and standardized patterns, creates an ideal environment for AI-assisted development:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modules provide focused context&lt;/strong&gt; that AI can fully understand&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ABP conventions&lt;/strong&gt; guide AI to generate consistent, framework-aligned code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear boundaries&lt;/strong&gt; prevent AI from creating unwanted dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standardized patterns&lt;/strong&gt; make AI-generated code predictable and maintainable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're building applications with AI assistance (and who isn't these days?), consider how your architecture affects AI code quality. Investing in a modular structure with ABP Framework pays dividends not just in traditional software engineering benefits, but in dramatically improved AI-assisted development workflows.&lt;/p&gt;

&lt;p&gt;The future of development is human-AI collaboration. Make sure your architecture is ready for it.&lt;/p&gt;

&lt;p&gt;To learn more about ABP Framework, visit it's &lt;a href="https://abp.io/docs/latest/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you experienced similar challenges with AI in large codebases? Share your experiences and tips in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>codequality</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
