Creating Entities HelloWorld.ProductService.Entities.Products Product & CatalogBrand Using PostgreSQL with EF Core dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL Creating the DbContext namespace HelloWorld.ProductService.EntityFrameworks { public class ProductServiceDbContext(DbContextOptions<ProductServiceDbContext> options) : DbContext(options) { protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); } } } Creating Entity Configuration Classes namespace HelloWorld.ProductService.EntityFrameworks.EntityConfigurations.Products { public class ProductEntityTypeConfiguration : IEntityTypeConfiguration<Product> { public void Configure(EntityTypeBuilder<Product> builder) { builder.ToTable("Products"); builder.Property(x => x.Name).HasMaxLength(32); builder.HasOne(x => x.Brand).WithMany(); } } } Database Connection String { "ConnectionStrings": { "ProductDatabase": "Host=localhost;Port=5432;Database=ProductService;Username=postgres;Password=postgres" } } Registering the DbContext builder.Services.AddDbContext<ProductServiceDbContext>(options => { options.UseNpgsql(builder.Configuration.GetConnectionString(DbConstants.ConnectionStringName)); }); Migrating the Database dotnet tool install --global dotnet-ef dotnet add package Microsoft.EntityFrameworkCore.Design dotnet ef migrations add InitialCreate --output-dir EntityFrameworks/Migrations dotnet ef database update Creating Models namespace HelloWorld.ProductService.Models.Products { public class ProductCreateRequest { public required string Name { get; init; } public string? Description { get; init; } public decimal Price { get; init; } public int BrandId { get; init; } public string? ImageUrl { get; init; } } } Creating Automatic Mappings namespace HelloWorld.ProductService.AutoMapper { public class ProductsMapConfiguration : Profile { public ProductsMapConfiguration() { CreateMap<ProductCreateRequest, Product>(); CreateMap<ProductUpdateRequest, Product>(); CreateMap<Product, ProductListItem>().AfterMap((src, dest) => dest.BrandName = src.Brand.Name); CreateMap<Product, ProductDetailsResponse>(); CreateMap<BrandCreateRequest, Brand>(); CreateMap<BrandUpdateRequest, Brand>(); CreateMap<Brand, BrandDetailsResponse>(); CreateMap<Brand, BrandListItem>(); } } } Creating Validators namespace HelloWorld.ProductService.Validations.Products { public class BrandUpdateRequestValidator : AbstractValidator<BrandUpdateRequest> { public BrandUpdateRequestValidator() { RuleFor(x => x.Id).GreaterThan(0); RuleFor(x => x.Name).NotNull().NotEmpty().Length(8, 32); } } } Creating Controllers namespace HelloWorld.ProductService.Controllers { [Route("api/[controller]")] [ApiController] public class ProductsController : ControllerBase } Defining Permissions namespace HelloWorld.ProductService.PermissionProviders { public static class CatalogPermissions public class CatalogPermissionDefiitionProvider : IPermissionDefinitionProvider } Localizing Permissions CatalogPermissionDefinitionProvider.en-US.resx CatalogPermissionDefinitionProvider.zh-CN.resx Localizing Entity Properties namespace HelloWorld.ProductService.Entities.Products { public class Product { [Display(Name = "ProductName")] public string Name { get; set; } } } Repetitive Work Repetitive work can be reduced with code generation tools, such as Visual Studio plugins, T4 templates, Roslyn, and so on.