A lightweight, modern Result pattern implementation for .NET applications with functional programming support. Provides type-safe error handling with HTTP status code integration, eliminating exception-based control flow.
- Why Result Pattern?
- Features
- Installation
- Quick Start
- Usage Examples
- ASP.NET Core Integration
- Advanced Patterns
- API Reference
- Best Practices
- Contributing
- License
public User GetUser(int id)
{
var user = _repository.Find(id);
if (user == null)
throw new NotFoundException("User not found"); // Exception for control flow ❌
return user;
}public Result<User> GetUser(int id)
{
var user = _repository.Find(id);
return user != null
? Result<User>.Success(user)
: Result<User>.Fail("User not found", statusCode: HttpStatusCode.NotFound); // Explicit ✅
}✅ Explicit Error Handling: Success/failure is part of the method signature
✅ No Hidden Exceptions: All failure paths are visible
✅ Type-Safe: Compile-time guarantees for error handling
✅ Functional Composition: Chain operations with Map/Bind
✅ Better Testability: No need to test exception paths
✅ Performance: No exception overhead for expected failures
✅ HTTP Integration: Built-in status code support for web APIs
- 🎯 Strongly-typed result handling with
Result<T>and non-genericResult - 🔒 Immutable records for Success/Failure states
- 🌐 HTTP status code integration for web APIs
- 📝 Custom messages and data payload support
- 🎨 Generic error types (
Result<TData, TError>) for domain-specific errors - ⚡ Functional programming support:
Match,Map,Bind - 🛡️ Exception handling with
Trypattern - ✅ Validation aggregation with
Validate - 🔗 Fluent API with
WithStatusCode,WithMessage - 🔄 Implicit conversion from data to
Result<T> - 📚 XML documentation for IntelliSense
- 🔐 Null safety with nullable reference types
- 🚀 .NET 8.0 & 9.0 compatible
dotnet add package ErginWebDev.ResultRequirements:
- .NET 8.0 or later (.NET 8.0 and .NET 9.0 are both supported)
- No additional dependencies required
using System.Net;
using ErginWebDev.Result;
// Success with data
var successResult = Result<User>.Success(user, "User created successfully", HttpStatusCode.Created);
// Success with default message and status
var simpleSuccess = Result<User>.Success(user);
// Implicit conversion
Product product = GetProduct();
Result<Product> result = product; // Automatically converts to Success
// Failure with message
var failResult = Result<User>.Fail("User not found", statusCode: HttpStatusCode.NotFound);
// Failure with validation errors
var errors = new List<string> { "Email is required", "Password is too short" };
var validationResult = Result<User>.Fail("Validation failed", errors, HttpStatusCode.UnprocessableEntity);// For operations without return value
var result = Result.Try(() => File.Delete("file.txt"), "Failed to delete file");
// For operations with return value
var userResult = Result<User>.Try(() => _repository.GetById(id), "User not found");
if (userResult.Success)
{
Console.WriteLine($"User found: {userResult.Data.Name}");
}var message = result.Match(
onSuccess: user => $"Welcome, {user.Name}!",
onFailure: errors => $"Error: {string.Join(", ", errors)}"
);
// In ASP.NET Core controllers
return result.Match(
onSuccess: data => Ok(data),
onFailure: errors => BadRequest(new { errors })
);// Map: Transform the data
var emailResult = userResult.Map(user => user.Email);
// Bind: Chain operations that return Result
var orderTotal = userResult
.Bind(user => GetOrders(user.Id))
.Bind(orders => CalculateTotal(orders))
.WithStatusCode(HttpStatusCode.OK);var validationResult = Result.Validate(
() => ValidateEmail(request.Email),
() => ValidatePassword(request.Password),
() => ValidateAge(request.Age)
);
if (validationResult.IsFailure)
{
return BadRequest(validationResult.Errors); // All errors collected
}var result = Result<User>.Success(user)
.WithStatusCode(HttpStatusCode.Created)
.WithMessage("User successfully registered");// Define custom error type
public record ValidationError(string Field, string Message, string Code);
// Use typed errors
var errors = new[]
{
new ValidationError("Email", "Email is required", "REQUIRED"),
new ValidationError("Password", "Password too short", "MIN_LENGTH")
};
var result = Result<User, ValidationError>.Fail("Validation failed", errors);
// Access typed errors
foreach (var error in result.Errors)
{
Console.WriteLine($"{error.Field}: {error.Message} ({error.Code})");
}
// Try with error factory
var orderResult = Result<Order, ValidationError>.Try(
() => CreateOrder(request),
errorFactory: ex => new ValidationError("Order", ex.Message, "CREATION_FAILED")
);var result = GetUser(userId);
if (result.Success)
{
Console.WriteLine($"Success: {result.Message}");
Console.WriteLine($"Status Code: {result.StatusCode}");
// Access result.Data for Result<T>
if (result.Data != null)
{
Console.WriteLine($"User: {result.Data.Name}");
}
}
else
{
Console.WriteLine($"Failed: {result.Message}");
Console.WriteLine($"Status Code: {result.StatusCode}");
foreach (var error in result.Errors)
{
Console.WriteLine($"- {error}");
}
}using Microsoft.AspNetCore.Mvc;
using ErginWebDev.Result;
using System.Net;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
var result = _productService.GetProduct(id);
// Using Match pattern
return result.Match(
onSuccess: product => Ok(product),
onFailure: errors => NotFound(new { message = result.Message, errors })
);
}
[HttpPost]
public IActionResult CreateProduct(CreateProductRequest request)
{
var result = _productService.CreateProduct(request);
if (result.Success)
return StatusCode((int)result.StatusCode, result.Data);
return StatusCode((int)result.StatusCode, new
{
message = result.Message,
errors = result.Errors
});
}
[HttpPut("{id}")]
public IActionResult UpdateProduct(int id, UpdateProductRequest request)
{
// Chain validations and operations
var result = Result.Validate(
() => ValidateProductId(id),
() => ValidateRequest(request)
)
.Bind(_ => _productService.UpdateProduct(id, request));
return result.Match(
onSuccess: () => Ok(result.Message),
onFailure: errors => BadRequest(new { errors })
);
}
[HttpDelete("{id}")]
public IActionResult DeleteProduct(int id)
{
var result = _productService.DeleteProduct(id);
if (result.IsFailure)
return StatusCode((int)result.StatusCode, new { result.Message, result.Errors });
return NoContent();
}
}using ErginWebDev.Result;
using System.Net;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// GET endpoint
app.MapGet("/api/products/{id}", (int id, IProductService service) =>
{
var result = service.GetProduct(id);
return result.Match(
onSuccess: product => Results.Ok(product),
onFailure: errors => Results.NotFound(new { message = result.Message, errors })
);
});
// POST endpoint
app.MapPost("/api/products", (CreateProductRequest request, IProductService service) =>
{
var result = service.CreateProduct(request);
if (result.Success)
return Results.Created($"/api/products/{result.Data.Id}", result.Data);
return Results.BadRequest(new { result.Message, result.Errors });
});
// PUT endpoint with validation
app.MapPut("/api/products/{id}", (int id, UpdateProductRequest request, IProductService service) =>
{
var result = Result<string>.Try(
() => service.UpdateProduct(id, request),
"Failed to update product"
);
return result.Match(
onSuccess: message => Results.Ok(new { message }),
onFailure: errors => Results.BadRequest(new { errors })
);
});
// DELETE endpoint
app.MapDelete("/api/products/{id}", (int id, IProductService service) =>
{
var result = service.DeleteProduct(id);
return result.IsFailure
? Results.BadRequest(new { result.Message, result.Errors })
: Results.NoContent();
});
app.Run();public interface IProductService
{
Result<Product> GetProduct(int id);
Result<Product> CreateProduct(CreateProductRequest request);
Result<string> UpdateProduct(int id, UpdateProductRequest request);
Result DeleteProduct(int id);
}
public class ProductService : IProductService
{
private readonly IProductRepository _repository;
public ProductService(IProductRepository repository)
{
_repository = repository;
}
public Result<Product> GetProduct(int id)
{
// Using Try pattern for exception handling
return Result<Product>.Try(
() => _repository.GetById(id),
$"Product with ID {id} not found"
);
}
public Result<Product> CreateProduct(CreateProductRequest request)
{
// Validation first
var validationResult = ValidateProduct(request);
if (validationResult.IsFailure)
return Result<Product>.Fail(validationResult.Message, validationResult.Errors);
// Create product
var product = new Product
{
Name = request.Name,
Price = request.Price
};
_repository.Add(product);
return Result<Product>.Success(
product,
"Product created successfully",
HttpStatusCode.Created
);
}
public Result<string> UpdateProduct(int id, UpdateProductRequest request)
{
var product = _repository.GetById(id);
if (product == null)
return Result<string>.Fail("Product not found", statusCode: HttpStatusCode.NotFound);
product.Name = request.Name;
product.Price = request.Price;
_repository.Update(product);
return Result<string>.Success(message: "Product updated successfully");
}
public Result DeleteProduct(int id)
{
return Result.Try(
() => _repository.Delete(id),
"Failed to delete product"
);
}
private Result ValidateProduct(CreateProductRequest request)
{
return Result.Validate(
() => string.IsNullOrEmpty(request.Name)
? Result.Fail("Name is required")
: Result.Success(),
() => request.Price <= 0
? Result.Fail("Price must be greater than zero")
: Result.Success()
);
}
}public class UserRepository : IUserRepository
{
private readonly DbContext _context;
public Result<User> GetById(int id)
{
var user = _context.Users.Find(id);
return user != null
? Result<User>.Success(user)
: Result<User>.Fail("User not found", statusCode: HttpStatusCode.NotFound);
}
public Result<User> Create(User user)
{
return Result<User>.Try(
() =>
{
_context.Users.Add(user);
_context.SaveChanges();
return user;
},
"Failed to create user"
);
}
}public record DomainError(string Code, string Message, string? Field = null);
public class Order
{
public Result<Order, DomainError> Ship()
{
if (Status != OrderStatus.Paid)
{
var error = new DomainError("ORDER_NOT_PAID", "Cannot ship unpaid order");
return Result<Order, DomainError>.Fail("Shipping failed", new[] { error });
}
Status = OrderStatus.Shipped;
ShippedAt = DateTime.UtcNow;
return Result<Order, DomainError>.Success(this, "Order shipped successfully");
}
public Result<Order, DomainError> AddItem(OrderItem item)
{
if (item.Quantity <= 0)
{
var error = new DomainError("INVALID_QUANTITY", "Quantity must be positive", "Quantity");
return Result<Order, DomainError>.Fail("Invalid item", new[] { error });
}
Items.Add(item);
return Result<Order, DomainError>.Success(this);
}
}public class UserService
{
public async Task<Result<User>> GetUserAsync(int id)
{
return await Result<User>.Try(
async () => await _repository.GetByIdAsync(id),
"User not found"
);
}
public async Task<Result<User>> CreateUserAsync(CreateUserRequest request)
{
// Validate
var validationResult = await ValidateUserAsync(request);
if (validationResult.IsFailure)
return Result<User>.Fail(validationResult.Message, validationResult.Errors);
// Create
var user = new User { Email = request.Email };
await _repository.AddAsync(user);
return Result<User>.Success(user, "User created", HttpStatusCode.Created);
}
}Success(bool): Indicates if the operation was successfulIsFailure(bool): Indicates if the operation failed (computed from!Success)Message(string?): Optional message describing the resultData(T?): Payload data (only inResult<T>andResult<TData, TError>)Errors(IReadOnlyList or IReadOnlyList): Immutable collection of errorsStatusCode(HttpStatusCode): HTTP status code (defaults to 200 OK for success, 400 BadRequest for failures)
Match<TResult>: Pattern matching for success/failure casesMap<TNew>: Transform the data if successfulBind<TNew>: Chain operations that return ResultWithStatusCode: Create new Result with different status codeWithMessage: Create new Result with different messageTry: Static method for exception handlingValidate: Static method for aggregating multiple validations (Result only)
Factory Methods:
Result.Success(string? message = null, HttpStatusCode statusCode = HttpStatusCode.OK)- Creates a successful resultResult.Fail(string message, IEnumerable<string>? errors = null, HttpStatusCode statusCode = HttpStatusCode.BadRequest)- Creates a failed resultResult.Try(Action action, string? errorMessage = null)- Executes action and returns Success/Fail based on exceptionsResult.Validate(params Func<Result>[] validations)- Aggregates multiple validation results
Instance Methods:
Match<TResult>(Func<TResult> onSuccess, Func<IReadOnlyList<string>, TResult> onFailure)- Pattern matchingWithStatusCode(HttpStatusCode statusCode)- Returns new Result with different status codeWithMessage(string? message)- Returns new Result with different message
Factory Methods:
Result<T>.Success(T? data = default, string? message = null, HttpStatusCode statusCode = HttpStatusCode.OK)- Creates a successful result with dataResult<T>.Fail(string message, IEnumerable<string>? errors = null, HttpStatusCode statusCode = HttpStatusCode.BadRequest)- Creates a failed resultResult<T>.Try(Func<T> func, string? errorMessage = null)- Executes function and returns Success/Fail based on exceptions
Instance Methods:
Match<TResult>(Func<T, TResult> onSuccess, Func<IReadOnlyList<string>, TResult> onFailure)- Pattern matchingMap<TNew>(Func<T, TNew> mapper)- Transforms data if successfulBind<TNew>(Func<T, Result<TNew>> binder)- Chains Result-returning operationsWithStatusCode(HttpStatusCode statusCode)- Returns new Result with different status codeWithMessage(string? message)- Returns new Result with different message
Operators:
implicit operator Result<T>(T data)- Implicitly converts data to Success result
Factory Methods:
Result<TData, TError>.Success(TData? data = default, string? message = null, HttpStatusCode statusCode = HttpStatusCode.OK)- Creates a successful resultResult<TData, TError>.Fail(string message, IEnumerable<TError>? errors = null, HttpStatusCode statusCode = HttpStatusCode.BadRequest)- Creates a failed result with typed errorsResult<TData, TError>.Try(Func<TData> func, string? errorMessage = null, Func<Exception, TError>? errorFactory = null)- Executes function with typed error conversion
Instance Methods:
Match<TResult>(Func<TData, TResult> onSuccess, Func<IReadOnlyList<TError>, TResult> onFailure)- Pattern matchingMap<TNewData>(Func<TData, TNewData> mapper)- Transforms data if successfulBind<TNewData>(Func<TData, Result<TNewData, TError>> binder)- Chains operationsWithStatusCode(HttpStatusCode statusCode)- Returns new Result with different status codeWithMessage(string? message)- Returns new Result with different message
Operators:
implicit operator Result<TData, TError>(TData data)- Implicitly converts data to Success result
- Use
Matchfor cleaner controller actions - Use
Tryfor operations that might throw exceptions - Use
Validatefor aggregating multiple validation errors - Use
Map/Bindfor chaining operations - Use typed errors (
Result<T, TError>) for domain-specific error handling - Return specific HTTP status codes for different failure scenarios
- Don't catch exceptions manually when
Trycan handle it - Don't check
result.SuccesswhenMatchis more appropriate - Don't create results with constructors (they're private)
- Don't mutate results (they're immutable records)
All the examples above demonstrate the library's capabilities. See Quick Start section for immediate usage.
Contributions are welcome! This is an open-source project.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Clone the repository
git clone https://github.com/ErginWebDev/Result.git
# Build the project
cd Result
dotnet build src/Result.sln
# Create NuGet package
cd src/ErginWebDev.Result
dotnet pack -c Release- GitHub: https://github.com/ErginWebDev/Result
- NuGet: https://www.nuget.org/packages/ErginWebDev.Result
- Issues: https://github.com/ErginWebDev/Result/issues
This project is licensed under the MIT License - see the LICENSE file for details.
- Neden Result Pattern?
- Özellikler
- Kurulum
- Hızlı Başlangıç
- ASP.NET Core Entegrasyonu
- Gelişmiş Kullanım
- En İyi Pratikler
public User GetUser(int id)
{
var user = _repository.Find(id);
if (user == null)
throw new NotFoundException("Kullanıcı bulunamadı"); // Kontrol akışı için exception ❌
return user;
}public Result<User> GetUser(int id)
{
var user = _repository.Find(id);
return user != null
? Result<User>.Success(user)
: Result<User>.Fail("Kullanıcı bulunamadı", statusCode: HttpStatusCode.NotFound); // Açık ✅
}✅ Açık Hata Yönetimi: Başarı/başarısızlık metod imzasının bir parçası
✅ Gizli Exception Yok: Tüm hata yolları görünür
✅ Tip Güvenli: Derleme zamanı hata yönetimi garantisi
✅ Fonksiyonel Kompozisyon: Map/Bind ile operasyon zincirleme
✅ Daha İyi Test Edilebilirlik: Exception yollarını test etmeye gerek yok
✅ Performans: Beklenen hatalar için exception maliyeti yok
✅ HTTP Entegrasyonu: Web API'ler için yerleşik status code desteği
- 🎯 Strongly-typed result yönetimi
Result<T>ve non-genericResultile - 🔒 Immutable record'lar ile Başarı/Başarısızlık durumları
- 🌐 HTTP status code entegrasyonu web API'ler için
- 📝 Özel mesajlar ve data payload desteği
- 🎨 Generic error tipleri (
Result<TData, TError>) domain-specific hatalar için - ⚡ Fonksiyonel programlama desteği:
Match,Map,Bind - 🛡️ Exception yönetimi
Trypattern ile - ✅ Validation birleştirme
Validateile - 🔗 Fluent API
WithStatusCode,WithMessageile - 🔄 Implicit dönüşüm data'dan
Result<T>'ye - 📚 XML dokümantasyon IntelliSense için
- 🔐 Null güvenlik nullable reference types ile
- 🚀 .NET 8.0 & 9.0 uyumlu
dotnet add package ErginWebDev.ResultGereksinimler:
- .NET 8.0 veya üzeri (.NET 8.0 ve .NET 9.0 her ikisi de desteklenir)
- Ek bağımlılık gerekmez
using System.Net;
using ErginWebDev.Result;
// Veri ile başarılı sonuç
var successResult = Result<User>.Success(user, "Kullanıcı başarıyla oluşturuldu", HttpStatusCode.Created);
// Basit başarı
var simpleSuccess = Result<User>.Success(user);
// Implicit dönüşüm
Product product = GetProduct();
Result<Product> result = product; // Otomatik Success'e dönüşür
// Hata mesajı ile başarısız sonuç
var failResult = Result<User>.Fail("Kullanıcı bulunamadı", statusCode: HttpStatusCode.NotFound);
// Validation hataları ile
var errors = new List<string> { "Email gerekli", "Şifre çok kısa" };
var validationResult = Result<User>.Fail("Validation başarısız", errors, HttpStatusCode.UnprocessableEntity);// Dönüş değeri olmayan operasyonlar için
var result = Result.Try(() => File.Delete("file.txt"), "Dosya silinemedi");
// Dönüş değeri olan operasyonlar için
var userResult = Result<User>.Try(() => _repository.GetById(id), "Kullanıcı bulunamadı");
if (userResult.Success)
{
Console.WriteLine($"Kullanıcı bulundu: {userResult.Data.Name}");
}var message = result.Match(
onSuccess: user => $"Hoşgeldin, {user.Name}!",
onFailure: errors => $"Hata: {string.Join(", ", errors)}"
);
// ASP.NET Core controller'larda
return result.Match(
onSuccess: data => Ok(data),
onFailure: errors => BadRequest(new { errors })
);// Map: Veriyi dönüştür
var emailResult = userResult.Map(user => user.Email);
// Bind: Result dönen operasyonları zincirle
var orderTotal = userResult
.Bind(user => GetOrders(user.Id))
.Bind(orders => CalculateTotal(orders))
.WithStatusCode(HttpStatusCode.OK);var validationResult = Result.Validate(
() => ValidateEmail(request.Email),
() => ValidatePassword(request.Password),
() => ValidateAge(request.Age)
);
if (validationResult.IsFailure)
{
return BadRequest(validationResult.Errors); // Tüm hatalar toplandı
}var result = Result<User>.Success(user)
.WithStatusCode(HttpStatusCode.Created)
.WithMessage("Kullanıcı başarıyla kaydedildi");// Özel error tipi tanımla
public record ValidationError(string Field, string Message, string Code);
// Typed error'ları kullan
var errors = new[]
{
new ValidationError("Email", "Email gerekli", "REQUIRED"),
new ValidationError("Password", "Şifre çok kısa", "MIN_LENGTH")
};
var result = Result<User, ValidationError>.Fail("Validation başarısız", errors);
// Typed error'lara eriş
foreach (var error in result.Errors)
{
Console.WriteLine($"{error.Field}: {error.Message} ({error.Code})");
}using Microsoft.AspNetCore.Mvc;
using ErginWebDev.Result;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
public ProductsController(IProductService productService)
{
_productService = productService;
}
[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
var result = _productService.GetProduct(id);
return result.Match(
onSuccess: product => Ok(product),
onFailure: errors => NotFound(new { message = result.Message, errors })
);
}
[HttpPost]
public IActionResult CreateProduct(CreateProductRequest request)
{
var result = _productService.CreateProduct(request);
if (result.Success)
return StatusCode((int)result.StatusCode, result.Data);
return StatusCode((int)result.StatusCode, new
{
message = result.Message,
errors = result.Errors
});
}
}using ErginWebDev.Result;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/api/products/{id}", (int id, IProductService service) =>
{
var result = service.GetProduct(id);
return result.Match(
onSuccess: product => Results.Ok(product),
onFailure: errors => Results.NotFound(new { message = result.Message, errors })
);
});
app.MapPost("/api/products", (CreateProductRequest request, IProductService service) =>
{
var result = service.CreateProduct(request);
if (result.Success)
return Results.Created($"/api/products/{result.Data.Id}", result.Data);
return Results.BadRequest(new { result.Message, result.Errors });
});
app.Run();public class ProductService : IProductService
{
private readonly IProductRepository _repository;
public Result<Product> GetProduct(int id)
{
return Result<Product>.Try(
() => _repository.GetById(id),
$"ID {id} olan ürün bulunamadı"
);
}
public Result<Product> CreateProduct(CreateProductRequest request)
{
// Önce validation
var validationResult = ValidateProduct(request);
if (validationResult.IsFailure)
return Result<Product>.Fail(validationResult.Message, validationResult.Errors);
var product = new Product { Name = request.Name, Price = request.Price };
_repository.Add(product);
return Result<Product>.Success(
product,
"Ürün başarıyla oluşturuldu",
HttpStatusCode.Created
);
}
private Result ValidateProduct(CreateProductRequest request)
{
return Result.Validate(
() => string.IsNullOrEmpty(request.Name)
? Result.Fail("İsim gerekli")
: Result.Success(),
() => request.Price <= 0
? Result.Fail("Fiyat sıfırdan büyük olmalı")
: Result.Success()
);
}
}public class UserRepository : IUserRepository
{
private readonly DbContext _context;
public Result<User> GetById(int id)
{
var user = _context.Users.Find(id);
return user != null
? Result<User>.Success(user)
: Result<User>.Fail("Kullanıcı bulunamadı", statusCode: HttpStatusCode.NotFound);
}
public Result<User> Create(User user)
{
return Result<User>.Try(
() =>
{
_context.Users.Add(user);
_context.SaveChanges();
return user;
},
"Kullanıcı oluşturulamadı"
);
}
}public record DomainError(string Code, string Message, string? Field = null);
public class Order
{
public Result<Order, DomainError> Ship()
{
if (Status != OrderStatus.Paid)
{
var error = new DomainError("ORDER_NOT_PAID", "Ödenmemiş sipariş kargoya verilemez");
return Result<Order, DomainError>.Fail("Kargolama başarısız", new[] { error });
}
Status = OrderStatus.Shipped;
ShippedAt = DateTime.UtcNow;
return Result<Order, DomainError>.Success(this, "Sipariş kargoya verildi");
}
}public class UserService
{
public async Task<Result<User>> GetUserAsync(int id)
{
return await Result<User>.Try(
async () => await _repository.GetByIdAsync(id),
"Kullanıcı bulunamadı"
);
}
public async Task<Result<User>> CreateUserAsync(CreateUserRequest request)
{
var validationResult = await ValidateUserAsync(request);
if (validationResult.IsFailure)
return Result<User>.Fail(validationResult.Message, validationResult.Errors);
var user = new User { Email = request.Email };
await _repository.AddAsync(user);
return Result<User>.Success(user, "Kullanıcı oluşturuldu", HttpStatusCode.Created);
}
}- Controller aksiyonları için
Matchkullanın - Exception fırlatabilecek operasyonlar için
Trykullanın - Çoklu validation hataları için
Validatekullanın - Operasyon zincirleme için
Map/Bindkullanın - Domain-specific hata yönetimi için typed error'lar (
Result<T, TError>) kullanın - Farklı hata senaryoları için spesifik HTTP status code'lar dönün
Trykullanabileceğiniz yerde manuel exception yakalamayınMatchdaha uygunkenresult.Successkontrolü yapmayın- Constructor ile result oluşturmayın (private'dırlar)
- Result'ları mutate etmeyin (immutable record'lardır)
Detaylı API dokümantasyonu için API Reference bölümüne bakın.
Katkılar memnuniyetle karşılanır! Bu açık kaynak bir projedir.
- Repository'yi fork'layın
- Feature branch oluşturun (
git checkout -b feature/harika-ozellik) - Değişikliklerinizi commit edin (
git commit -m 'Harika özellik eklendi') - Branch'inizi push edin (
git push origin feature/harika-ozellik) - Pull Request açın
# Repository'yi klonlayın
git clone https://github.com/ErginWebDev/Result.git
# Projeyi build edin
cd Result
dotnet build src/Result.sln
# NuGet paketi oluşturun
cd src/ErginWebDev.Result
dotnet pack -c Release- GitHub: https://github.com/ErginWebDev/Result
- NuGet: https://www.nuget.org/packages/ErginWebDev.Result
- Issues: https://github.com/ErginWebDev/Result/issues
Bu proje MIT Lisansı altında lisanslanmıştır - detaylar için LICENSE dosyasına bakın.
Made with ❤️ by ErginWebDev