ASP.NET Core 3.1 Clean Architecture – Invoice Management App (Part 1)

A while ago I saw a youtube video of Jason Taylor’s talk in NDC Conference about clean architecture. He present a source code which you can use as a template for your new project which is already structured based on clean architecture. If you follow the convention on how the code should be written based on his template, coding will be a lot easier for you.

Though Jason Taylor’s template will make your development a lot easier, it is important for you to know about the structure of clean architecture and how the codes interacts. If you are not familiar with clean architecture, following along this article will help you understand it. I will try create my own implementation of clean architecture based on Jason Taylor’s clean architecture.

Looking at the diagram, we have the Domain layer at the core, followed by Application layer then Presentation layer and Infrastructure layer.

Domain layer contains the entities or types that can be use in the application and it does not have any dependency.

Application layer contains business logic and depends on domain layer.

Both infrastructure and Presentation depends only in Application layer. Infrastructure contains external concerns like the type of database while Presentation layer is responsible for presenting the data to the client application for example in this project it will be the react js application.

Advertisements

We can best understand clean architecture by building one application on our own. Create a new ASP.NET Core Web Application.

Name the solution as InvoiceMangementApp and the project as InvoiceManagementApp.Api.

Select React.js for project template and change the authentication to Individual User Accounts.

Build the project by pressing CTRL + SHIFT + B, it will also download the needed node modules for the react project.

Advertisements

Our Api project will serve as our Presentation layer. Let’s add more project to represent the other parts of clean architecture.

Create new Class Library (.Net Standard) project for Domain and Application layer. InvoiceManagementApp.Domain, InvoiceManagementApp.Application.

After creating the projects make sure you are using the latest .Net Standard library which .Net Standard 2.1 at the time of writing. Right click of the project and click properties then set the target framework to the latest .Net Standard framework. Also don’t forget to delete the default Class1.cs file.

Advertisements

Create new Class Library (.Net Core) for InvoiceManagementApp.Infrastructure. We will use IdentityServer library in infrastructure layer, that’s why it need to be a .net core library otherwise you will not be able to install IdentityServer on it.

Advertisements

The ApplicationDbContext should be in Infrastructure layer, but currently it is in presentation layer which is InvoiceManagementApp.Api. To move the ApplicationDbContext in infrastructure layer we need to install some nuget packages in InvoiceManagementApp.Infrastructure.

  • Microsoft.AspNetCore.ApiAuthorization.IdentityServer
  • Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools

Cut and paste the Data and Models folder from InvoiceManagementApp.Api to InvoiceManagementApp.Infrastructure. Delete the Migrations folder for now in Data folder. Then update the namespace of ApplicationDbContext and ApplicationUser to use InvoiceManagementApp.Infrastructure.

Add new class in InvoiceMangamentApp.Infrastructure and call it DependencyInjection update the code to look like the code below.

public static class DependencyInjection
    {
        public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    configuration.GetConnectionString("DefaultConnection"),
                    b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));

            services.AddDefaultIdentity<ApplicationUser>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddIdentityServer()
                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

            services.AddAuthentication()
                .AddIdentityServerJwt();

            return services;
        }
    }

Make sure your InvoiceManagementApp.Api are using latest version of packages. In InvoiceManagementApp.Api open the Nuget Package Manager then go to Updates tab click select all packages then click Update button.

Add reference of InvoiceManagementApp.Infrastructure in InvoiceManagementApp.Api. Then update Startup.cs ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
        {
            services.AddInfrastructure(Configuration);

            services.AddControllersWithViews();
            services.AddRazorPages();

            // In production, the React files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/build";
            });
        }

Open the file _LoginPartial.cshtml in InvoiceMangementApp.Api -> Pages -> Shared folder. Change the InvoiceManagementApp.Api.Models in using statement to InvoiceManagementApp.Infrastructure.Models;

Advertisements

Open Program.cs in InvoiceManagementApp.Api then change the code to the code below.

public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    var context = services.GetRequiredService<ApplicationDbContext>();
                    context.Database.Migrate();

                }
                catch (Exception ex)
                {
                    var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();

                    logger.LogError(ex, "An error occurred while migrating or seeding the database.");
                }
            }

            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }

Then open Package Manager Console then select InvoiceManagementApp.Infrastructure in Default Project then run the command fro add migration.

add-migration InitialMigration

Then update the database by running this command.

update-database

Run the application to check if the project is still working. If everything works fine, we can now proceed in building our clean architecture app by working on our Domain models. We will do that in the next article.

Advertisements

Next we will set up our Domain Entities and implement auditing in EF Core ASP.NET Core 3.1 Clean Architecture – Invoice Management App (Part 2 Auditing in EF Core with CreatedBy and LastModifiedBy)

Advertisements

RELATED ARTICLES:

ASP.NET Core 3.1 Clean Architecture – Invoice Management App (Part 1)

ASP.NET Core 3.1 Clean Architecture – Invoice Management App (Part 2 Auditing in EF Core with CreatedBy and LastModifiedBy)

ASP.NET Core 3.1 Clean Architecture – Invoice Management App (Part 3 MediatR and FluentValidation)

ASP.NET Core 3.1 Clean Architecture – Invoice Management App (Part 4 AutoMapper – Map object properties to another object)

ASP.NET Core 3.1 Clean Architecture – Invoice Management App (Part 5 NSwag – Setting up Swagger and Auto generate API client code)

ASP.NET Core 3.1 Clean Architecture – Invoice Management App (Part 6 React – How To Convert ReactJs To Typescript)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s