Skip to main content

dotnet-expert

.NET development principles and decision-making. .NET 8, ASP.NET Core, C# 12, dependency injection, best practices.

Informations de source

Dépôt
skeletorflet/opencode-kit
Dernière activité de la source
31 mars 2026 à 19:12
Langue détectée de SKILL.md
anglais
Étoiles
9
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
dotnet-expert
description
.NET development principles and decision-making. .NET 8, ASP.NET Core, C# 12, dependency injection, best practices.
# .NET Expert - Modern .NET 8 > .NET development principles and decision-making. > **Learn to THINK, not copy-paste patterns.** --- ## ⚠️ How to Use This Skill This skill teaches **decision-making principles** for .NET development. - ASK user for project type (web API, worker, blazor) - Choose minimal APIs vs controller-based - Don't use outdated .NET Framework patterns --- ## 1. Framework Selection ### Decision Tree ``` What are you building? │ ├── REST API │ ├── Minimal APIs (NEW .NET 6+) - Recommended for simple APIs │ └── Controller-based - Complex operations, heavy validation │ ├── Full-stack Web │ ├── Blazor Server - Server-rendered, WebSocket │ ├── Blazor WebAssembly - Client-side, PWA-ish │ └── ASP.NET Core MVC - Traditional Razor │ ├── Background Worker │ └── .NET Worker Services + Quartz/Hangfire │ ├── gRPC Services │ └── .NET gRPC (protobuf) │ ├── Desktop │ ├── WPF (.NET 8) │ ├── WinForms (legacy) │ └── MAUI (cross-platform) │ └── Microservices └── .NET 8 + Dapr (cloud-native patterns) ``` ### Comparison: Minimal APIs vs Controllers | Factor | Minimal APIs | Controllers | |--------|--------------|-------------| | **Boilerplate** | Very Low | Medium | | **Routing** | Inline/Fluent | Attribute-based | | **Validation** | Manual/FluentValidation | DataAnnotations | | **Best For** | Microservices, simple APIs | Enterprise, complex validation | | **OpenAPI/Swagger** | Built-in | Route-based | --- ## 2. Modern C# 12 Features ### Primary Constructors ```csharp // C# 12: Primary constructors (NEW!) public class UserService( IUserRepository userRepository, IEmailService emailService) { public User? GetById(int id) { return userRepository.FindById(id); } } // Or record with primary constructor (immutable) public record User(int Id, string Name, string Email); ``` ### Collection Expressions ```csharp // OLD: Array initializer var list = new List<int> { 1, 2, 3 }; int[] array = new int[] { 1, 2, 3 }; // C# 12: Collection expressions var list = [1, 2, 3]; int[] array = [1, 2, 3]; var dict = new Dictionary<string, int> { {"a", 1} }; var dict2 = ["a", 1 ]; ``` ### LINQ Improvements ```csharp // NEW in .NET: More efficient LINQ var result = items .Where(x => x.IsActive) .OrderBy(x => x.Name) .Select(x => x.ToDto()) .ToList(); // Materializes once // Use CountBy, ChunkBy for better performance var countByCategory = products.CountBy(p => p.Category); // Returns: IEnumerable<(Category, int)> ``` ### Pattern Matching ```csharp // Pattern matching with C# 12 public string Describe(object obj) => obj switch { int i => $"Integer: {i}", string s => $"String: {s.ToUpper()}", User { Name: "Admin" } => "Admin user!", User u => $"User: {u.Name}", null => "Null!", _ => $"Type: {obj.GetType().Name}" }; ``` --- ## 3. Dependency Injection ### .NET 8 DI (Built-in) ```csharp // Configure services (Program.cs) var builder = WebApplication.CreateBuilder(args); // Add services builder.Services.AddScoped<IUserRepository, UserRepository>(); builder.Services.AddTransient<IEmailService, EmailService>(); builder.Services.AddSingleton<IConfigService, ConfigService>(); // Use options pattern builder.Services.Configure<DatabaseOptions>( builder.Configuration.GetSection("Database")); // Build var app = builder.Build(); // Minimal API with DI app.MapGet("/users/{id}", (IUserRepository repo, int id) => repo.FindById(id)); ``` ### Constructor Injection ```csharp // ✅ RECOMMENDED in .NET public class UserService(IUserRepository repository) { private readonly IUserRepository _repo = repository; public User? GetById(int id) => _repo.FindById(id); } // Record-based service (C# 12) public record EmailService(SmtpConfig Config) : IEmailService { public async Task SendAsync(string to, string subject, string body) { // Implementation } } ``` --- ## 4. Minimal APIs (Recommended) ### Basic Pattern ```csharp // Program.cs - Minimal API var builder = WebApplication.CreateBuilder(args); // Add services builder.Services.AddDbContext<AppDbContext>(); builder.Services.AddScoped<IUserRepository, UserRepository>(); var app = builder.Build(); // Endpoints app.MapGet("/api/users", async (AppDbContext db) => await db.Users.ToListAsync()); app.MapGet("/api/users/{id}", async (int id, AppDbContext db) => await db.Users.FindAsync(id)); app.MapPost("/api/users", async (User user, AppDbContext db) => { db.Users.Add(user); await db.SaveChangesAsync(); return Results.Created($"/api/users/{user.Id}", user); }); app.Run(); ``` ### With Validation ```csharp // Using FluentValidation public record CreateUserRequest(string Name, string Email); app.MapPost("/api/users", async (CreateUserRequest request, IValidator<CreateUserRequest> validator, AppDbContext db) => { var validation = await validator.ValidateAsync(request); if (!validation.IsValid) return Results.BadRequest(validation.Errors); var user = new User { Name = request.Name, Email = request.Email }; db.Users.Add(user); await db.SaveChangesAsync(); return Results.Created($"/api/users/{user.Id}", user); }); ``` --- ## 5. Database Access ### Entity Framework Core ```csharp // DbContext public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {} public DbSet<User> Users => Set<User>(); public DbSet<Order> Orders => Set<Order>(); } // Entity (use primary constructor for EF Core 8) public class User { public int Id { get; set; } public string Name { get; set; } = ""; public string Email { get; set; } = ""; public DateTime CreatedAt { get; set; } } // Queries with LINQ var users = await context.Users .Where(u => u.IsActive) .OrderBy(u => u.Name) .Select(u => new UserDto(u.Id, u.Name)) .ToListAsync(); ``` ### Dapper for Performance ```csharp // Dapper - lightweight ORM public class UserRepository : IUserRepository { private readonly DbConnection _connection; public async Task<User?> FindById(int id) { return await _connection.QueryFirstOrDefaultAsync<User>( "SELECT * FROM Users WHERE Id = @Id", new { Id = id }); } } ``` ### Comparison | Approach | Best For | Performance | |----------|----------|-------------| | **EF Core** | Most CRUD, migrations | Good | | **Dapper** | Raw SQL, high performance | Excellent | | **ADO.NET** | Minimal overhead | Best | --- ## 6. Testing Patterns ### xUnit with Moq ```csharp // Unit test public class UserServiceTest { [Fact] public void GetById_WhenExists_ReturnsUser() { // Arrange var mockRepo = new Mock<IUserRepository>(); mockRepo.Setup(r => r.FindById(1)) .Returns(new User(1, "test@test.com")); var service = new UserService(mockRepo.Object); // Act var result = service.GetById(1); // Assert Assert.NotNull(result); Assert.Equal("test@test.com", result.Email); } } // Integration test public class UserApiTest : IClassFixture<WebApplicationFactory<Program>> { private readonly HttpClient _client; public UserApiTest(WebApplicationFactory<Program> factory) { _client = factory.CreateClient(); } [Fact] public async Task GetUsers_ReturnsOk() { var response = await _client.GetAsync("/api/users"); Assert.True(response.IsSuccessStatusCode); } } ``` ### Testing Tools | Tool | Purpose | |------|---------| | **xUnit** | Unit/Integration testing | | **Moq** | Mocking framework | | **FluentAssertions** | Fluent assertions | | **Testcontainers.Sqlite** | In-memory DB testing | | **WireMock** | HTTP mocking | --- ## 7. Configuration ### Options Pattern ```csharp // Configuration class public class DatabaseOptions { public string ConnectionString { get; set; } = ""; public int MaxConnections { get; set; } = 10; } // appsettings.json { "Database": { "ConnectionString": "Server=.;Database=mydb;", "MaxConnections": 20 } } // Registration builder.Services.Configure<DatabaseOptions>( builder.Configuration.GetSection("Database")); // Usage public class UserService( IOptions<DatabaseOptions> options) { public string ConnString => options.Value.ConnectionString; } ``` --- ## 8. Error Handling ### Global Exception Handler ```csharp // Program.cs app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { context.Response.StatusCode = 500; context.Response.ContentType = "application/json"; await context.Response.WriteAsync( "{\"error\": \"An unexpected error occurred\"}"); }); }); // Problem Details (RFC 7807) app.MapPost("/api/users", async ([FromBody] User user) => { try { // Process } catch (Exception ex) { return Results.Problem(detail: ex.Message, statusCode: 400); } }); ``` --- ## 9. Decision Checklist Before implementing: - [ ] **Minimal API or Controller? (match complexity)** - [ ] **EF Core or Dapper? (match performance needs)** - [ ] **Async/await for I/O operations?** - [ ] **Dependency injection configured?** - [ ] **Validation strategy chosen?** - [ ] **Testing approach defined?** - [ ] **Configuration via options pattern?** --- ## ❌ Anti-Patterns to Avoid ### ❌ DON'T: - Use synchronous I/O in API endpoints - Configure EF Core without tracking changes awareness - Use ViewBag/ViewData in minimal APIs - Skip health checks in microservices - Use .NET Framework patterns in .NET 8 - Skip connection string encryption for production ### ✅ DO: - Use Primary Constructors (C# 12) - Use records for DTOs and responses - Use Minimal APIs for simple services - Use IAsyncEnumerable for streaming - Configure health checks (/healthz) - Use FluentValidation for complex validation --- > **Remember:** .NET 8 is modern and productive. > Use Minimal APIs, records, and primary constructors. > **Think in modern .NET, not .NET Framework.**
Voir sur GitHub