This project is a simple CRUD application built with ASP.NET Core, following Clean Architecture principles and implementing patterns such as CQRS, DDD, and TDD.
The solution is structured as follows:
- Core Layer: Contains domain models, repository interfaces, and application logic.
- Infrastructure Layer: Handles database interactions and external services.
- API Layer: Serves as the presentation layer, exposing endpoints and integrating Swagger for API documentation.
- Tests Layer: Includes unit and integration tests to support TDD and BDD practices.
Define the Customer entity with the specified properties:
public class Customer
{
public Guid Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public DateTime DateOfBirth { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string BankAccountNumber { get; set; }
}Implement validation rules using FluentValidation:
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(c => c.Firstname).NotEmpty();
RuleFor(c => c.Lastname).NotEmpty();
RuleFor(c => c.DateOfBirth).LessThan(DateTime.Now);
RuleFor(c => c.PhoneNumber).Must(IsValidPhoneNumber).WithMessage("Invalid phone number.");
RuleFor(c => c.Email).NotEmpty().EmailAddress();
RuleFor(c => c.BankAccountNumber).Matches(@"^\d{10,18}$").WithMessage("Invalid bank account number.");
}
private bool IsValidPhoneNumber(string phoneNumber)
{
var phoneUtil = PhoneNumbers.PhoneNumberUtil.GetInstance();
try
{
var parsedPhone = phoneUtil.Parse(phoneNumber, "US");
return phoneUtil.IsValidNumberForRegion(parsedPhone, "US");
}
catch
{
return false;
}
}
}Utilize Entity Framework Core to configure the database schema, ensuring uniqueness constraints:
modelBuilder.Entity<Customer>()
.HasIndex(c => new { c.Firstname, c.Lastname, c.DateOfBirth })
.IsUnique();
modelBuilder.Entity<Customer>()
.HasIndex(c => c.Email)
.IsUnique();Data Storage Optimization Store PhoneNumber as varchar(15) to minimize storage space. Apply appropriate database constraints through migrations.
CQRS Implementation Implement the CQRS pattern using MediatR:
Commands: Handle Create, Update, and Delete operations. Queries: Handle data retrieval operations. Controller Example
[ApiController]
[Route("api/[controller]")]
public class CustomersController : ControllerBase
{
private readonly IMediator _mediator;
public CustomersController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<IActionResult> Create(CreateCustomerCommand command)
{
var result = await _mediator.Send(command);
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
}
[HttpGet("{id}")]
public async Task<IActionResult> GetById(Guid id)
{
var result = await _mediator.Send(new GetCustomerByIdQuery(id));
return Ok(result);
}
}Swagger Integration Add Swagger for API documentation:
services.AddSwaggerGen();Create a docker-compose.yml file to set up the PostgreSQL database service:
version: '3.4'
services:
database:
image: postgres:latest
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: customersdb
ports:
- "5432:5432"
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:Unit Tests: Use xUnit to test validations and domain services. Integration Tests: Utilize TestServer for API endpoint testing.
Maintain clean and descriptive commit messages to reflect your work progress:
git commit -m "feat: add customer entity and validation rules"
git commit -m "test: add unit tests for customer validation"
git commit -m "chore: add Swagger and update API documentation"Repository Setup Clone the existing repository and retain commit history:
git clone --mirror https://github.com/mohrmz/crud-test-csharp.git
cd crud-test-csharp
git remote add origin https://github.com/your-username/your-repo.git
git push -u origin --allPull Request After implementing the features, create a pull request for code review.