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.