πŸ“„

Csharp Advanced Patterns Production

Advanced 1 min read 200 words

Advanced Patterns Θ™i Production Strategies - Senior Level

Cuprins

  1. Architectural Patterns
  2. Concurrency Patterns
  3. Data Access Patterns
  4. Resilience Patterns
  5. Event-Driven Patterns
  6. Testing Strategies pentru Senior

Architectural Patterns

1. Layered Architecture - Enterprise Implementation

// ❌ Common mistakes
public class BadLayeredArchitecture
{
    // Controllers direct cu DbContext
    [ApiController]
    public class ProductController : ControllerBase
    {
        private readonly AppDbContext _db;

        [HttpGet("{id}")]
        public async Task<ActionResult<Product>> GetProduct(int id)
        {
            var product = await _db.Products.FindAsync(id); // Direct DB access
            return Ok(product); // Returning entity instead of DTO
        }
    }
}

// βœ… Proper implementation
public class ProperLayeredArchitecture
{
    // Layer 1: API Layer
    [ApiController]
    [Route("api/[controller]")]
    public class ProductController : ControllerBase
    {
        private readonly IProductService _productService;
        private readonly IMapper _mapper;

        [HttpGet("{id}")]
        [ProducesResponseType(typeof(ProductDTO), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<ActionResult<ProductDTO>> GetProductAsync(int id)
        {
            try
            {
                var product = await _productService.GetProductAsync(id);
                return Ok(_mapper.Map<ProductDTO>(product));
            }
            catch (ProductNotFoundException ex)
            {
                return NotFound(new { message = ex.Message });
            }
        }

        [HttpPost]
        [ProducesResponseType(typeof(ProductDTO), StatusCodes.Status201Created)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<ActionResult<ProductDTO>> CreateProductAsync(CreateProductRequest request)
        {
            // Validation through FluentValidation
            if (!ModelState.IsValid)
                return BadRequest(ModelState);

            var product = await _productService.CreateProductAsync(request);
            return CreatedAtAction(nameof(GetProductAsync), new { id = product.Id }, 
                _mapper.Map<ProductDTO>(product));
        }
    }

    // Layer 2: Service/Application Layer
    public interface IProductService
    {
        Task<Product> GetProductAsync(int id);
        Task<Product> CreateProductAsync(CreateProductRequest request);
        Task<Product> UpdateProductAsync(int id, UpdateProductRequest request);
        Task<bool> DeleteProductAsync(int id);
    }

    public class ProductService : IProductService
    {
        private readonly IProductRepository _repository;
        private readonly IEventPublisher _eventPublisher;
        private readonly ILogger<ProductService> _logger;
        private readonly IValidator<CreateProductRequest> _validator;

        public ProductService(
            IProductRepository repository,
            IEventPublisher eventPublisher,
            ILogger<ProductService> logger,
            IValidator<CreateProductRequest> validator)
        {
            _repository = repository;
            _eventPublisher = eventPublisher;
            _logger = logger;
            _validator = validator;
        }

        public async Task<Product> GetProductAsync(int id)
        {
            _logger.LogInformation("Fetching product {ProductId}", id);

            var product = await _repository.GetByIdAsync(id);
            if (product == null)
                throw new ProductNotFoundException($"Product {id} not found");

            return product;
        }

        public async Task<Product> CreateProductAsync(CreateProductRequest request)
        {
            // Validation
            var validationResult = await _validator.ValidateAsync(request);
            if (!validationResult.IsValid)
                throw new ValidationException(validationResult.Errors);

            _logger.LogInformation("Creating new product: {ProductName}", request.Name);

            var product = new Product
            {
                Name = request.Name,
                Price = request.Price,
                CategoryId = request.CategoryId,
                CreatedAt = DateTime.UtcNow
            };

            await _repository.AddAsync(product);

            // Publish domain event
            await _eventPublisher.PublishAsync(
                new ProductCreatedEvent { ProductId = product.Id });

            _logger.LogInformation("Product created successfully: {ProductId}", product.Id);

            return product;
        }

        public async Task<Product> UpdateProductAsync(int id, UpdateProductRequest request)
        {
            var product = await _repository.GetByIdAsync(id);
            if (product == null)
                throw new ProductNotFoundException();

            product.Name = request.Name ?? product.Name;
            product.Price = request.Price ?? product.Price;
            product.ModifiedAt = DateTime.UtcNow;

            await _repository.UpdateAsync(product);

            await _eventPublisher.PublishAsync(
                new ProductUpdatedEvent { ProductId = product.Id });

            return product;
        }

        public async Task<bool> DeleteProductAsync(int id)
        {
            var product = await _repository.GetByIdAsync(id);
            if (product == null)
                return false;

            product.IsDeleted = true;
            product.DeletedAt = DateTime.UtcNow;

            await _repository.UpdateAsync(product);

            await _eventPublisher.PublishAsync(
                new ProductDeletedEvent { ProductId = product.Id });

            return true;
        }
    }

    // Layer 3: Data Access Layer - Repository Pattern
    public interface IProductRepository
    {
        Task<Product> GetByIdAsync(int id);
        Task<List<Product>> GetAllAsync(ProductSpecification spec);
        Task<Product> AddAsync(Product product);
        Task<Product> UpdateAsync(Product product);
        Task DeleteAsync(int id);
    }

    public class ProductRepository : IProductRepository
    {
        private readonly AppDbContext _context;

        public async Task<Product> GetByIdAsync(int id)
        {
            return await _context.Products
                .AsNoTracking()
                .FirstOrDefaultAsync(p => p.Id == id && !p.IsDeleted);
        }

        public async Task<List<Product>> GetAllAsync(ProductSpecification spec)
        {
            return await _context.Products
                .Apply(spec)
                .ToListAsync();
        }

        public async Task<Product> AddAsync(Product product)
        {
            _context.Products.Add(product);
            await _context.SaveChangesAsync();
            return product;
        }

        public async Task<Product> UpdateAsync(Product product)
        {
            _context.Products.Update(product);
            await _context.SaveChangesAsync();
            return product;
        }

        public async Task DeleteAsync(int id)
        {
            var product = await _context.Products.FindAsync(id);
            if (product != null)
            {
                _context.Products.Remove(product);
                await _context.SaveChangesAsync();
            }
        }
    }

    // Layer 4: Data Access Layer - DbContext
    public class AppDbContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
        public DbSet<Category> Categories { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Global query filters
            modelBuilder.Entity<Product>()
                .HasQueryFilter(p => !p.IsDeleted);

            // Configure shadow properties
            modelBuilder.Entity<Product>()
                .Property<DateTime>("CreatedAt");
        }
    }
}

2. Vertical Slice Architecture

// Alternativă la layered - organizare per feature
public class VerticalSliceArchitecture
{
    // Feature folder structure:
    // Features/
    //   β”œβ”€β”€ Products/
    //   β”‚   β”œβ”€β”€ GetProduct/
    //   β”‚   β”‚   β”œβ”€β”€ GetProductQuery.cs
    //   β”‚   β”‚   β”œβ”€β”€ GetProductQueryHandler.cs
    //   β”‚   β”‚   β”œβ”€β”€ GetProductQueryValidator.cs
    //   β”‚   β”‚   └── ProductDTO.cs
    //   β”‚   β”œβ”€β”€ CreateProduct/
    //   β”‚   β”‚   β”œβ”€β”€ CreateProductCommand.cs
    //   β”‚   β”‚   β”œβ”€β”€ CreateProductCommandHandler.cs
    //   β”‚   β”‚   └── CreateProductValidator.cs
    //   β”‚   └── ProductController.cs
    //   └── Orders/
    //       β”œβ”€β”€ CreateOrder/
    //       └── ...

    // Query
    public class GetProductQuery : IRequest<ProductDTO>
    {
        public int Id { get; set; }
    }

    public class GetProductQueryHandler : IRequestHandler<GetProductQuery, ProductDTO>
    {
        private readonly AppDbContext _context;
        private readonly IMapper _mapper;

        public async Task<ProductDTO> Handle(GetProductQuery request, CancellationToken cancellationToken)
        {
            var product = await _context.Products
                .AsNoTracking()
                .FirstOrDefaultAsync(p => p.Id == request.Id, cancellationToken);

            if (product == null)
                throw new ProductNotFoundException();

            return _mapper.Map<ProductDTO>(product);
        }
    }

    // Controller
    [ApiController]
    [Route("api/[controller]")]
    public class ProductController : ControllerBase
    {
        private readonly IMediator _mediator;

        [HttpGet("{id}")]
        public async Task<ActionResult<ProductDTO>> GetProduct(int id)
        {
            var result = await _mediator.Send(new GetProductQuery { Id = id });
            return Ok(result);
        }
    }
}

Concurrency Patterns

1. Optimistic Concurrency Control

public class OptimisticConcurrencyPattern
{
    // Entity with concurrency token
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }

        [Timestamp]
        public byte[] RowVersion { get; set; } // Concurrency token
    }

    // DbContext configuration
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .Property(p => p.RowVersion)
            .IsRowVersion();
    }

    // Update with concurrency handling
    public async Task UpdateProductAsync(int id, UpdateProductRequest request)
    {
        var product = await _context.Products.FindAsync(id);

        product.Name = request.Name;
        product.Price = request.Price;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            // Handle conflict - versiune veche vs noua
            var databaseEntry = ex.Entries.Single();
            var clientValues = (Product)databaseEntry.Entity;
            var databaseValues = (Product)databaseEntry.CurrentValues.ToObject();

            // Strategy 1: Client wins
            databaseEntry.OriginalValues.SetValues(databaseValues);
            await _context.SaveChangesAsync();

            // Strategy 2: Database wins
            databaseEntry.CurrentValues.SetValues(databaseValues);

            // Strategy 3: Merge
            databaseEntry.CurrentValues["Name"] = clientValues.Name;
            databaseEntry.OriginalValues.SetValues(databaseValues);
            await _context.SaveChangesAsync();

            throw new ConcurrencyException("Another user modified this record");
        }
    }
}

2. Pessimistic Locking

public class PessimisticLockingPattern
{
    // Using explicit transactions
    public async Task SafeTransferAsync(Account from, Account to, decimal amount)
    {
        using (var transaction = _context.Database.BeginTransaction(
            IsolationLevel.RepeatableRead))
        {
            try
            {
                // Lock source account
                var sourceAccount = await _context.Accounts
                    .FromSqlInterpolated($"SELECT * FROM Accounts WITH (UPDLOCK) WHERE Id = {from.Id}")
                    .FirstOrDefaultAsync();

                if (sourceAccount.Balance < amount)
                    throw new InsufficientFundsException();

                sourceAccount.Balance -= amount;

                // Lock destination account
                var destAccount = await _context.Accounts
                    .FromSqlInterpolated($"SELECT * FROM Accounts WITH (UPDLOCK) WHERE Id = {to.Id}")
                    .FirstOrDefaultAsync();

                destAccount.Balance += amount;

                await _context.SaveChangesAsync();
                await transaction.CommitAsync();
            }
            catch
            {
                await transaction.RollbackAsync();
                throw;
            }
        }
    }
}

Data Access Patterns

1. Unit of Work Pattern

public class UnitOfWorkPattern
{
    // Interface
    public interface IUnitOfWork : IDisposable, IAsyncDisposable
    {
        IRepository<Product> Products { get; }
        IRepository<Order> Orders { get; }
        IRepository<Category> Categories { get; }

        Task<int> SaveChangesAsync();
        Task BeginTransactionAsync();
        Task CommitTransactionAsync();
        Task RollbackTransactionAsync();
    }

    // Implementation
    public class UnitOfWork : IUnitOfWork
    {
        private readonly AppDbContext _context;
        private readonly Dictionary<Type, object> _repositories = new();
        private IDbContextTransaction _transaction;

        public UnitOfWork(AppDbContext context)
        {
            _context = context;
        }

        public IRepository<Product> Products =>
            GetRepository<Product>();

        public IRepository<Order> Orders =>
            GetRepository<Order>();

        public IRepository<Category> Categories =>
            GetRepository<Category>();

        private IRepository<T> GetRepository<T>() where T : class
        {
            var type = typeof(T);
            if (!_repositories.ContainsKey(type))
            {
                _repositories[type] = new Repository<T>(_context);
            }

            return (IRepository<T>)_repositories[type];
        }

        public async Task<int> SaveChangesAsync()
        {
            return await _context.SaveChangesAsync();
        }

        public async Task BeginTransactionAsync()
        {
            _transaction = await _context.Database.BeginTransactionAsync();
        }

        public async Task CommitTransactionAsync()
        {
            try
            {
                await SaveChangesAsync();
                await _transaction?.CommitAsync();
            }
            catch
            {
                await _transaction?.RollbackAsync();
                throw;
            }
            finally
            {
                _transaction?.Dispose();
            }
        }

        public async Task RollbackTransactionAsync()
        {
            try
            {
                await _transaction?.RollbackAsync();
            }
            finally
            {
                _transaction?.Dispose();
            }
        }

        public void Dispose()
        {
            _transaction?.Dispose();
            _context?.Dispose();
        }

        public async ValueTask DisposeAsync()
        {
            if (_transaction != null)
                await _transaction.DisposeAsync();

            if (_context != null)
                await _context.DisposeAsync();
        }
    }

    // Usage
    public class OrderService
    {
        private readonly IUnitOfWork _unitOfWork;

        public async Task CreateOrderWithProductsAsync(CreateOrderRequest request)
        {
            await _unitOfWork.BeginTransactionAsync();
            try
            {
                var order = new Order { CustomerId = request.CustomerId };
                _unitOfWork.Orders.Add(order);

                foreach (var line in request.Lines)
                {
                    var product = await _unitOfWork.Products
                        .GetByIdAsync(line.ProductId);

                    // Decrease inventory
                    product.StockQuantity -= line.Quantity;
                    _unitOfWork.Products.Update(product);
                }

                await _unitOfWork.CommitTransactionAsync();
            }
            catch
            {
                await _unitOfWork.RollbackTransactionAsync();
                throw;
            }
        }
    }
}

Resilience Patterns

1. Retry with Exponential Backoff

public class RetryPattern
{
    private readonly IAsyncPolicy<HttpResponseMessage> _retryPolicy;

    public RetryPattern()
    {
        _retryPolicy = Policy
            .Handle<HttpRequestException>()
            .Or<TimeoutException>()
            .OrResult<HttpResponseMessage>(r => 
                r.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable ||
                r.StatusCode == System.Net.HttpStatusCode.GatewayTimeout ||
                r.StatusCode == System.Net.HttpStatusCode.RequestTimeout)
            .WaitAndRetryAsync(
                retryCount: 3,
                sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)),
                onRetry: (outcome, timespan, retryCount, context) =>
                {
                    Console.WriteLine($"Retry attempt {retryCount} after {timespan.TotalSeconds}s");
                });
    }

    public async Task<T> GetAsync<T>(string url)
    {
        var response = await _retryPolicy.ExecuteAsync(async () =>
            await _httpClient.GetAsync(url));

        var content = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<T>(content);
    }
}

2. Bulkhead Pattern - Isolation

public class BulkheadPattern
{
    public class IsolatedServiceClient
    {
        private readonly IAsyncPolicy _bulkheadPolicy;
        private readonly HttpClient _httpClient;

        public IsolatedServiceClient()
        {
            // Limit concurrent calls to external service
            _bulkheadPolicy = Policy.BulkheadAsync(
                maxParallelization: 10, // Max 10 concurrent calls
                maxQueuingActions: 5);   // Queue up to 5 more
        }

        public async Task<T> GetAsync<T>(string url)
        {
            return await _bulkheadPolicy.ExecuteAsync(async () =>
            {
                var response = await _httpClient.GetAsync(url);
                var content = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<T>(content);
            });
        }
    }
}

Event-Driven Patterns

1. Domain Events

public class DomainEventsPattern
{
    // Domain Event base
    public abstract class DomainEvent
    {
        public DateTime OccurredAt { get; } = DateTime.UtcNow;
        public string AggregateId { get; protected set; }
    }

    // Concrete events
    public class OrderCreatedEvent : DomainEvent
    {
        public string CustomerId { get; set; }
        public decimal Total { get; set; }
        public List<OrderLineDTO> Lines { get; set; }
    }

    public class OrderShippedEvent : DomainEvent
    {
        public string TrackingNumber { get; set; }
        public string CarrierName { get; set; }
    }

    // Publisher
    public interface IDomainEventPublisher
    {
        Task PublishAsync<T>(T @event) where T : DomainEvent;
        Task PublishAllAsync(IEnumerable<DomainEvent> events);
    }

    public class DomainEventPublisher : IDomainEventPublisher
    {
        private readonly IMediator _mediator;

        public async Task PublishAsync<T>(T @event) where T : DomainEvent
        {
            await _mediator.Publish(@event);
        }

        public async Task PublishAllAsync(IEnumerable<DomainEvent> events)
        {
            foreach (var @event in events)
            {
                await _mediator.Publish(@event);
            }
        }
    }

    // Handler
    public class OrderCreatedEventHandler : INotificationHandler<OrderCreatedEvent>
    {
        private readonly IEmailService _emailService;
        private readonly ILogger<OrderCreatedEventHandler> _logger;

        public async Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
        {
            _logger.LogInformation("Order created: {OrderId}", notification.AggregateId);

            await _emailService.SendOrderConfirmationAsync(
                notification.CustomerId,
                notification.Total);
        }
    }
}

2. Outbox Pattern - Garantie Delivery

public class OutboxPattern
{
    // Outbox entity
    public class OutboxEvent
    {
        public long Id { get; set; }
        public string EventType { get; set; }
        public string EventData { get; set; }
        public DateTime CreatedAt { get; set; }
        public DateTime? PublishedAt { get; set; }
    }

    // Save to outbox
    public async Task PublishOrderAsync(Order order, IEnumerable<DomainEvent> events)
    {
        var transaction = await _context.Database.BeginTransactionAsync();
        try
        {
            _context.Orders.Add(order);

            foreach (var @event in events)
            {
                _context.OutboxEvents.Add(new OutboxEvent
                {
                    EventType = @event.GetType().Name,
                    EventData = JsonConvert.SerializeObject(@event),
                    CreatedAt = DateTime.UtcNow
                });
            }

            await _context.SaveChangesAsync();
            await transaction.CommitAsync();
        }
        catch
        {
            await transaction.RollbackAsync();
            throw;
        }
    }

    // Background job - publish outbox events
    public class PublishOutboxEventsJob
    {
        private readonly AppDbContext _context;
        private readonly IEventPublisher _eventPublisher;

        public async Task ExecuteAsync()
        {
            var unpublishedEvents = await _context.OutboxEvents
                .Where(e => e.PublishedAt == null)
                .OrderBy(e => e.CreatedAt)
                .ToListAsync();

            foreach (var outboxEvent in unpublishedEvents)
            {
                try
                {
                    var @event = JsonConvert.DeserializeObject(
                        outboxEvent.EventData,
                        Type.GetType(outboxEvent.EventType));

                    await _eventPublisher.PublishAsync(@event);

                    outboxEvent.PublishedAt = DateTime.UtcNow;
                    _context.Update(outboxEvent);
                    await _context.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    // Log error, retry logic
                    Console.WriteLine($"Error publishing event: {ex.Message}");
                }
            }
        }
    }
}

Testing Strategies pentru Senior

1. Test Pyramid Architecture

public class TestPyramid
{
    // Unit Tests (bottom - 70%)
    [TestClass]
    public class ProductServiceUnitTests
    {
        private Mock<IProductRepository> _mockRepository;
        private ProductService _service;

        [TestInitialize]
        public void Setup()
        {
            _mockRepository = new Mock<IProductRepository>();
            _service = new ProductService(_mockRepository.Object);
        }

        [TestMethod]
        public async Task GetProduct_WithValidId_ReturnsProduct()
        {
            // Arrange
            var productId = 1;
            var product = new Product { Id = productId, Name = "Test" };
            _mockRepository
                .Setup(r => r.GetByIdAsync(productId))
                .ReturnsAsync(product);

            // Act
            var result = await _service.GetProductAsync(productId);

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(productId, result.Id);
        }
    }

    // Integration Tests (middle - 20%)
    [TestClass]
    public class ProductRepositoryIntegrationTests
    {
        private DbContext _context;

        [TestInitialize]
        public void Setup()
        {
            var options = new DbContextOptionsBuilder<AppDbContext>()
                .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
                .Options;

            _context = new AppDbContext(options);
        }

        [TestMethod]
        public async Task AddProduct_SavesSuccessfully()
        {
            // Arrange
            var product = new Product { Name = "Test Product", Price = 100 };

            // Act
            _context.Products.Add(product);
            await _context.SaveChangesAsync();

            // Assert
            var saved = await _context.Products.FirstOrDefaultAsync(p => p.Name == "Test Product");
            Assert.IsNotNull(saved);
        }
    }

    // End-to-End Tests (top - 10%)
    [TestClass]
    public class ProductApiEndToEndTests
    {
        private HttpClient _client;
        private WebApplicationFactory<Program> _factory;

        [TestInitialize]
        public void Setup()
        {
            _factory = new WebApplicationFactory<Program>();
            _client = _factory.CreateClient();
        }

        [TestMethod]
        public async Task CreateProduct_WithValidData_Returns201()
        {
            // Arrange
            var request = new CreateProductRequest { Name = "Test", Price = 100 };
            var content = new StringContent(
                JsonConvert.SerializeObject(request),
                Encoding.UTF8,
                "application/json");

            // Act
            var response = await _client.PostAsync("/api/products", content);

            // Assert
            Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
        }
    }
}

2. TestBed Pattern - Complex Scenarios

public class TestBedPattern
{
    // Setup complex test environment
    public class OrderServiceTestBed
    {
        private readonly IServiceProvider _serviceProvider;
        private readonly AppDbContext _context;
        private readonly Mock<IEventPublisher> _eventPublisher;
        private readonly Mock<IPaymentService> _paymentService;

        public OrderServiceTestBed()
        {
            var services = new ServiceCollection();

            // Register all dependencies
            services.AddDbContext<AppDbContext>(options =>
                options.UseInMemoryDatabase(Guid.NewGuid().ToString()));

            services.AddScoped<OrderService>();
            services.AddScoped<IProductRepository, ProductRepository>();

            _eventPublisher = new Mock<IEventPublisher>();
            services.AddScoped(sp => _eventPublisher.Object);

            _paymentService = new Mock<IPaymentService>();
            services.AddScoped(sp => _paymentService.Object);

            _serviceProvider = services.BuildServiceProvider();
            _context = _serviceProvider.GetRequiredService<AppDbContext>();

            SeedData();
        }

        private void SeedData()
        {
            _context.Categories.Add(new Category { Id = 1, Name = "Electronics" });
            _context.Products.Add(new Product 
            { 
                Id = 1, 
                Name = "Laptop", 
                Price = 1000, 
                CategoryId = 1 
            });
            _context.SaveChanges();
        }

        public async Task<Order> CreateOrderAsync()
        {
            var orderService = _serviceProvider.GetRequiredService<OrderService>();
            return await orderService.CreateOrderAsync(new CreateOrderRequest 
            { 
                CustomerId = "CUST1",
                Lines = new[] { new { ProductId = 1, Quantity = 2 } }
            });
        }

        public void VerifyEventPublished<T>(Times times = null) where T : DomainEvent
        {
            times ??= Times.Once();
            _eventPublisher.Verify(
                p => p.PublishAsync(It.IsAny<T>()),
                times);
        }
    }
}

Production Monitoring Strategies

1. Distributed Tracing

public class DistributedTracingStrategy
{
    // Setup OpenTelemetry
    public class TraceConfiguration
    {
        public static void ConfigureTracing(IServiceCollection services)
        {
            services
                .AddOpenTelemetry()
                .WithTracing(tracerProvider =>
                {
                    tracerProvider
                        .AddAspNetCoreInstrumentation()
                        .AddHttpClientInstrumentation()
                        .AddSqlClientInstrumentation()
                        .AddEntityFrameworkCoreInstrumentation()
                        .AddJaegerExporter(options =>
                        {
                            options.AgentHost = "localhost";
                            options.AgentPort = 6831;
                        });
                });
        }
    }

    // Custom activity creation
    public class CustomActivityService
    {
        private const string ActivitySourceName = "ProductService";
        private readonly ActivitySource _activitySource;

        public CustomActivityService()
        {
            _activitySource = new ActivitySource(ActivitySourceName);
        }

        public async Task<Product> ProcessProductAsync(int id)
        {
            using (var activity = _activitySource.StartActivity("ProcessProduct"))
            {
                activity?.SetTag("product.id", id);

                var product = await FetchProductAsync(id);
                activity?.SetTag("product.price", product.Price);

                return product;
            }
        }
    }
}

2. Metrics Collection

public class MetricsCollectionStrategy
{
    public class MetricsService
    {
        private readonly Counter<int> _requestCounter;
        private readonly Histogram<double> _responseTimeHistogram;
        private readonly UpDownCounter<int> _activeConnections;

        public MetricsService(IMeterFactory meterFactory)
        {
            var meter = meterFactory.Create("ProductService");

            _requestCounter = meter.CreateCounter<int>(
                "http.requests",
                description: "Total HTTP requests");

            _responseTimeHistogram = meter.CreateHistogram<double>(
                "http.response_time",
                unit: "ms",
                description: "HTTP response time");

            _activeConnections = meter.CreateUpDownCounter<int>(
                "db.connections.active",
                description: "Active database connections");
        }

        public void RecordRequest(string method, double responseTime)
        {
            _requestCounter.Add(1, new KeyValuePair<string, object>("method", method));
            _responseTimeHistogram.Record(responseTime);
        }

        public void IncrementConnections()
        {
            _activeConnections.Add(1);
        }

        public void DecrementConnections()
        {
            _activeConnections.Add(-1);
        }
    }
}

Concluzie

DiferenΘ›iatorii unui Senior Developer:

  1. Design Thinking - Arquitecturi scalabile Θ™i maintainabile
  2. Performance Awareness - Profilering Θ™i optimizare constant
  3. Production Readiness - Error handling, monitoring, resilience
  4. Testing Discipline - Pirația testelor corespunzătoare
  5. Mentoring Capacity - Explică și transmite cunoștințe
  6. Business Understanding - Nu doar cod, dar Θ™i context

Date: 2025 C# Version: 12+ .NET Version: 8+