-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Project example: Users/Infrastructure/RabbitMQConnection.cs
Reference: Refactoring Guru Singleton C#
Ps. The class was instantiated as Lazy in order to have a delayed loading since it is not used everywhere in the system. In addition, Lazy supports multi-threading by default, meaning that even in an environment with several threads there will only be one instance of the class.
Project example: Clean Architecture/Users/Infrastructure/RabbitMQConnection.cs
Reference: Async OOP 2: Constructors
Project example: Users/Application/UseCases/User/ReadUser.cs
// ReadUser.cs
internal sealed class ReadUser(IUserRepository userRepository) : IReadUser
{
private readonly IUserRepository _userRepository = userRepository;
public async Task<(UserException?, User?)> ExecuteAsync(Guid userId)
{
try
{
return (null, await _userRepository.GetById(userId));
}
catch (Exception ex)
{
return (new UserException("An error occurred while getting a user.", ex), null);
}
}
}
Reference: Try/Catch Considered Harmful
Project example: Projects/Application/Validations/Project/ValidateUpdateProjectAttributes.cs
Reference: Specification Design Pattern
Ps. The pattern wasn't followed in its entirety by creating a separate class, as this implementation would have added too much complexity to the simplicity of the class. But its idea of having separate validations was kept.
Project example: Users/Infrastructure/Repositories/UserRepository.cs
public async Task<User?> Delete(Guid userId)
{
var user = await _context.Users.FindAsync(userId);
if (user == null) return null;
_context.Users.Remove(user);
await _context.SaveChangesAsync();
return user;
}
Project example: Projects/Application/Validations/Project/ValidateUpdateProjectAttributes.cs
// ValidateUpdateProjectAttributes.cs
bool hasProjectDto = context.ActionArguments.TryGetValue("projectDTO", out var projectDtoObject);
bool isProjectUpdateDto = projectDtoObject is ProjectUpdateDTO;
bool isValidProjectDto = hasProjectDto && isProjectUpdateDto;
Project example: Users/Domain/Entities/OutboxMessage.cs
// Entity of DB Users
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
namespace Users.Domain.Entities
{
[Index(nameof(OutboxMessageId))]
public class OutboxMessage
{
[Key]
public Guid OutboxMessageId { get; init; } = Guid.NewGuid();
[Required(ErrorMessage = "OutboxMessage payload is required")]
public required string Payload { get; set; }
public DateTime CreatedAt { get; init; } = DateTime.UtcNow;
public bool Processed { get; set; }
}
}
- Projects
- It is designed using Clean Architecture.
- Users
- It is designed using Clean Architecture.
- Each service has its own database.
- The Outbox standard was implemented to ensure consistency between the data of the Projects and Users services.
- If there is an error when saving data in the Users database, it will perform a rollback.
- The occasional inconsistency (of milliseconds) of the data is acceptable in this scenario, which is why queues are used.
- Monitoring with Application Insights
- Rule to not return null values in response body
- Message Broker with RabbitMQ
- Asynchronous Programming
Reference: https://renatogroffe.medium.com/dicas-de-performance-para-apis-rest-no-asp-net-core-f2f3c66042c8
Rules: Retry 3 times to connection and to read/get datas in queue, durable queues
- sendUserIdToProject
- sendUserIdToProjectDLQ