- TR (Turkce)
- Proje Tanitimi
- Paketler
- Kurulum
- Hizli Baslangic
- Temel Tipler
- Result Factory
- Severity (Oncelik Seviyeleri)
- Try/Catch Wrapper
- Fluent Builder API
- Custom Error Codes & Localization
- Extension Metotlari
- ASP.NET Core Entegrasyonu
- Logging (Otomatik Loglama)
- Mapping Destegi
- Pure (Minimal Surum)
- API Response (ToResponse)
- Program.cs Ornekleri
- Test Projesi
- Roadmap
- EN (English)
- Project Overview
- Packages
- Installation
- Quick Start
- Core Types
- Result Factory
- Severity Levels
- Try/Catch Wrapper
- Fluent Builder API
- Custom Error Codes & Localization
- Extension Methods
- ASP.NET Core Integration
- Logging (Auto-Logging)
- Mapping Support
- Pure (Minimal Version)
- API Response (ToResponse)
- Program.cs Examples
- Test Project
- Roadmap
TahaMucasiroglu.Return v2.0.0, C# dünyasinda metot ve servis cagrilariinizin donus degerlerini standartlastirmak icin tasarlanmis, kapsamli ve genisletilebilir bir kutuphanedir.
IReturn ve IReturn<T> arayuzleri ile hata, uyari, basari ve kritik durumlarini tek bir nesnede tutmanizi saglar.
- Kod tekrarini azaltmak: Her metodun farkli donus tipi yerine,
IReturn/IReturn<T>ile tek tip sonuc nesnesi dondurmek - Merkezi hata yonetimi: Hata mesaji, exception, error code, severity ve veri (
Data) tek bir objede toplanir - Otomatik loglama: Serilog veya MEL ile hic kod yazmadan tum islem sonuclarini loglamak
- Try/Catch Wrapper:Elle try/catch yazmadan guvenli metot cagrilari yapmak
- Fluent Builder API: Zincirleme metotlarla karmasik sonuc nesneleri olusturmak
- Custom Error Codes: Lokalizasyon destekli ozel hata kodlari tanimlamak
- SOLID & Clean Code: Immutable
recordyapilariyla thread-safe ve bakimi kolay altyapi
| Ozellik | Aciklama |
|---|---|
IReturn / IReturn<T> |
Standart donus arayuzleri |
SuccessReturn / ErrorReturn / WarningReturn / CriticalReturn |
Hazir record tipleri |
Result Factory |
Ok(), Fail(), Warn(), Critical() metodlari |
| Try/Catch Wrapper | Result.Try() ile guvenli metot cagrilari |
| Fluent Builder | Result.Create().WithSuccess().WithData(obj).Build() |
| Custom Error Codes | ReturnErrorCode enum + localization |
| Severity | Success, Warning, Error, Critical |
| Context | TraceId, Timestamp, Metadata |
| Logging | Serilog / MEL otomatik loglama |
| Mapping | Return.Map ile dahili mapping destegi |
| ASP.NET Core | Middleware + ToResponse() + IActionResult |
| Pure | Minimal, zero-overhead surum |
| Structs | GC-free struct alternatifleri |
| Paket | Surum | Aciklama |
|---|---|---|
TahaMucasiroglu.Return |
2.0.0 | Ana kutuphane |
TahaMucasiroglu.Return.Pure |
2.0.0 | Minimal surum (logging, context yok) |
TahaMucasiroglu.Return.Map |
2.0.0 | Expression tree tabanli mapping |
TahaMucasiroglu.Return.Logging |
2.0.0 | Serilog / MEL otomatik loglama |
TahaMucasiroglu.Return.AspNetCore |
2.0.0 | ASP.NET Core middleware + IActionResult |
# Ana kutuphane
dotnet add package TahaMucasiroglu.Return
# Pure (minimal)
dotnet add package TahaMucasiroglu.Return.Pure
# Mapping destegi
dotnet add package TahaMucasiroglu.Return.Map
# Logging destegi
dotnet add package TahaMucasiroglu.Return.Logging
# ASP.NET Core entegrasyonu
dotnet add package TahaMucasiroglu.Return.AspNetCoreusing Return.Abstract;
using Return.Factory;
// Basarili sonuc (data ile)
IReturn<string> success = Result.Ok("Merhaba Dunya");
Console.WriteLine(success.Status); // true
Console.WriteLine(success.Data); // "Merhaba Dunya"
// Basarisiz sonuc
IReturn error = Result.Fail("Bir hata olustu");
Console.WriteLine(error.Status); // false
Console.WriteLine(error.Message); // "Bir hata olustu"
// Data ile basarisiz sonuc
IReturn<int> notFound = Result.Fail<int>("Kullanici bulunamadi");
Console.WriteLine(notFound.Status); // false
Console.WriteLine(notFound.Data); // 0 (default)public interface IReturn
{
bool Status { get; }
Severity Severity { get; }
string? Message { get; }
Exception? Exception { get; }
int? ErrorCode { get; }
ReturnContext? Context { get; init; }
}public interface IReturn<T> : IReturn
{
T? Data { get; init; }
bool IsDataNull { get; }
bool IsDataNotNull { get; }
bool CheckStatusAndData { get; } // Status == true && Data != null
}using Return.Concrete;
// Basarili
new SuccessReturn();
new SuccessReturn("Islem basarili");
new SuccessReturn<string>("Merhaba");
// Hata
new ErrorReturn("Kayit bulunamadi");
new ErrorReturn<string>(default, "Kullanici yok");
// Uyari
new WarningReturn("Dusuk stok uyariisi");
// Kritik
new CriticalReturn("Veritabani baglantisi koptu");Result sinifi ile tipleri bilmeden hizlica sonuc olusturun:
using Return.Factory;
// Basarili
Result.Ok();
Result.Ok("Islem basarili");
Result.Ok(myData);
Result.Ok(myData, "Kayit olusturuldu");
// Hata
Result.Fail("Hata mesaji");
Result.Fail(exception);
Result.Fail("Hata", exception);
// Hata (generic)
Result.Fail<User>("Kullanici bulunamadi");
// Uyari
Result.Warn("Stok azaliyor");
Result.Warn(data, "Veri eski olabilir");
// Kritik
Result.Critical("Servis disarida");
Result.Critical("Baglanti hatasi", ex);public enum Severity
{
Success, // Basarili
Warning, // Uyari
Error, // Hata
Critical // Kritik
}Her IReturn nesnesi bir Severity degeri tasir:
var result = Result.Warn("Disk dolmak uzere");
Console.WriteLine(result.Severity); // WarningElle try/catch yazmadan guvenli metot cagrilari:
using Return.Factory;
// Sync
IReturn result = Result.Try(() => RiskyOperation());
IReturn<User> result = Result.Try(() => GetUser(id));
// Async
IReturn result = await Result.TryAsync(() => RiskyAsyncOperation());
IReturn<User> result = await Result.TryAsync(() => GetUserAsync(id));Ornek Kullanim (Servis Katmani):
public IReturn<Order> CreateOrder(CreateOrderRequest request)
{
return Result.Try(() =>
{
var order = new Order(request.ProductId, request.Quantity);
_repo.Add(order);
return Result.Ok(order, "Siparis olusturuldu");
});
}Zincirleme metotlarla karmasik sonuc nesneleri olusturun:
using Return.Factory;
var result = Result.Create()
.WithSuccess()
.WithData(user)
.WithMessage("Kullanici getirildi")
.WithTraceId()
.WithTimestamp()
.Build();
// => IReturn<User>
var error = Result.Create()
.WithError()
.WithMessage("Yetkisiz erisim")
.WithErrorCode(ReturnErrorCode.Unauthorized)
.WithContext("ip", "192.168.1.1")
.Build();
// => IReturn
var warning = Result.Create()
.WithWarning()
.WithData(stocks)
.WithMessage("Stok kritik seviyede")
.Build();
// => IReturn<List<Stock>>Hata kodlarini standartlastirin ve dil destegi ekleyin.
ReturnLanguageenum ile tum hata mesajlarinin dilini belirleyin.
using Return.Localization;
// Turkce
ReturnLocalization.Language = ReturnLanguage.Turkish;
// Ingilizce
ReturnLocalization.Language = ReturnLanguage.English;
// Sistem kulturunu kullan (varsayilan)
ReturnLocalization.Language = ReturnLanguage.Auto;Program.cs ornegi:
using Return.Localization;
var builder = WebApplication.CreateBuilder(args);
// Tum hata mesajlari Turkce olsun
ReturnLocalization.Language = ReturnLanguage.Turkish;
builder.Services.AddControllers();
// ...
var app = builder.Build();
app.MapControllers();
app.Run();using Return.Localization;
// Toplu kayit (EN/TR)
ReturnLocalization.Register(new Dictionary<int, (string en, string tr)>
{
[6001] = ("Payment failed", "Odeme basarisiz"),
[6002] = ("Insufficient balance", "Yetersiz bakiye"),
[6003] = ("Order expired", "Siparis suresi doldu")
});
// Kullanim - dil ayarina gore otomatik cozumlenir
var result = Result.Fail(6001);
// ReturnLanguage.Turkish => "Odeme basarisiz"
// ReturnLanguage.English => "Payment failed"| Deger | Aciklama |
|---|---|
ReturnLanguage.Auto |
Sistem kulturunu kullanir (varsayilan) |
ReturnLanguage.English |
Tum mesajlar Ingilizce |
ReturnLanguage.Turkish |
Tum mesajlar Turkce |
Ileride yeni diller eklendiginde enum'a
German,Frenchgibi degerler eklenir.
| Kod Araligi | Kategori | Ornekler |
|---|---|---|
| 1001-1999 | Not Found | NotFound, AlreadyExists, DataIsNull |
| 2001-2999 | Validation | ValidationError, InvalidFormat, RequiredFieldMissing |
| 3001-3999 | Auth | Unauthorized, Forbidden, TokenExpired |
| 4001-4999 | System | DatabaseError, ConnectionFailed, Timeout |
| 5001-5999 | Business | BusinessRuleViolation, OperationCancelled, Conflict |
| 9001 | General | Unknown |
using Return.Extensions;
var result = Result.Ok(user);
// Kontrol
result.IsSuccess(); // true
result.IsError(); // false
// Veri alma
var data = result.GetDataOrDefault(new User());
// Pattern matching
result.Match(
onSuccess: r => Console.WriteLine("Basarili"),
onError: r => Console.WriteLine("Hata")
);
// Callback
result.OnSuccess(r => ProcessUser(r.Data));
result.OnError(r => LogError(r.Message));
// Transformasyon
var name = result.Map(u => u.Name); // IReturn<string>
var orders = result.Bind(u => GetOrders(u.Id)); // IReturn<List<Order>>
// Side effect
result.Tap(r => Console.WriteLine(r.Data.Name));
// Kosul
result.Ensure(r => r.Data.IsActive, "Kullanici pasif");using Return.Extensions;
var tasks = new[]
{
GetUserAsync(1),
GetUserAsync(2),
GetUserAsync(3)
};
// Tumunu bekle
var all = await tasks.WhenAllReturn();
// Ilk biteni bekle
var first = await tasks.WhenAnyReturn();
// Birlestir
var combined = await tasks.CombineAllAsync();// Program.cs
using Return.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
// Exception handler - tum exception'lari IReturn formatinda doner
builder.Services.AddControllers();
var app = builder.Build();
app.UseReturnExceptionHandler(); // Global exception handling
app.UseReturnResponse(); // IReturn response serialization
app.MapControllers();
app.Run();using Return.Extensions;
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var result = _service.GetById(id);
return result.Status ? Ok(result.ToResponse()) : NotFound(result.ToResponse());
}ToResponse() ciktisi:
{
"status": true,
"message": "Blog created",
"errorCode": null,
"severity": "Success",
"data": { "id": 1, "title": "Merhaba", "author": "Taha" }
}using Return.AspNetCore.Results;
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var result = _service.GetById(id);
return new ReturnResult<User>(result);
// Success -> 200, Error -> 500, Critical -> 503
}Return.Logging ile tum IReturn islemleri otomatik loglanir. Service katmaninda hic log kodu yazmaniza gerek yok.
Ornek:
Test/AutoMapper_Serilog_Return/Api/Program.cs
using Api.Services;
using Blog.Domain.Interfaces;
using Blog.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Return.Logging;
using Serilog;
using Api.Mapping;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services.AddControllers();
builder.Services.AddDbContext<BlogDbContext>(opt =>
opt.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=BlogDb;Trusted_Connection=True;"));
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
builder.Services.AddAutoMapper(typeof(BlogProfile));
builder.Services.AddScoped<IBlogService, BlogService>();
// Return.Logging - tum IReturn islemlerini otomatik logla
builder.Services.AddReturnLogging();
var app = builder.Build();
app.MapControllers();
app.Run("http://localhost:5001");Ornek:
Test/AutoMapper_Serilog_Return/Api/Services/BlogService.cs
using Return.Abstract;
using Return.Factory;
public class BlogService : IBlogService
{
private readonly IBlogRepository _repo;
public IReturn<List<BlogDto>> GetAll()
{
var blogs = _repo.GetAll();
var dtos = _mapper.Map<List<BlogDto>>(blogs);
return Result.Ok(dtos);
// Return.Logging otomatik logluyor!
}
public IReturn<BlogDto> GetById(int id)
{
var blog = _repo.GetById(id);
if (blog is null) return Result.Fail<BlogDto>($"Blog {id} not found");
return Result.Ok(_mapper.Map<BlogDto>(blog));
}
}Return.Map, expression tree tabanli yuksek performansli mapping saglar.
Ornek:
Test/Default_None_Return/Api/Program.cs
using Return.Map.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
// Return.Map - dahili mapping destegi
builder.Services.AddReturnMapper();
builder.Services.AddScoped<IBlogService, BlogService>();
var app = builder.Build();
app.MapControllers();
app.Run();Ornek:
Test/Default_None_Return/Api/Services/BlogService.cs
public IReturn<List<BlogDto>> GetAll()
{
var blogs = _repo.GetAll();
var dtos = blogs.Select(b => new BlogDto
{
Id = b.Id, Title = b.Title,
Content = b.Content, Author = b.Author,
CreatedAt = b.CreatedAt
}).ToList();
return Result.Ok(dtos);
}Return.Pure, logging, context, severity, error code gibi ozellikleri icermez. Manuel kontrol isteyen projeler icin idealdir.
| Ozellik | Return (Full) | Pure |
|---|---|---|
| Logging | Otomatik | Manuel |
| Context/TraceId | Var | Yok |
| Severity | Var | Yok |
| ErrorCode | Var | Yok |
| Result Factory | Var | Yok (dogrudan new) |
| Struct tipler | Var | Yok |
Ornek:
Test/AutoMapper_Serilog_Pure/Api/Services/BlogService.cs
using Return.Pure.Concrete;
using Return.Pure.Abstract;
using Microsoft.Extensions.Logging;
public class BlogService : IBlogService
{
private readonly IBlogRepository _repo;
private readonly ILogger<BlogService> _logger;
public IReturn<BlogDto> GetById(int id)
{
try
{
var blog = _repo.GetById(id);
if (blog is null)
return new ErrorReturn<BlogDto>(default, $"Blog {id} not found");
return new SuccessReturn<BlogDto>(_mapper.Map<BlogDto>(blog));
}
catch (Exception ex)
{
_logger.LogError(ex, "GetById failed");
return new ErrorReturn<BlogDto>(default, ex.Message);
}
}
}Ornek:
Test/AutoMapper_Serilog_Pure/Api/Controllers/BlogController.cs
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var r = _svc.GetById(id);
return r.Status
? Ok(new { status = true, data = r.Data })
: NotFound(new { status = false, message = r.Message });
}Full Return ile controller'da ToResponse() cagirilir, data otomatik serialize olur:
// Return Full - ToResponse() ile otomatik JSON
[HttpGet]
public IActionResult GetAll() => Ok(_service.GetAll().ToResponse());Cikti:
{
"status": true,
"message": null,
"errorCode": null,
"severity": "Success",
"data": [
{ "id": 1, "title": "Blog 1", "content": "...", "author": "Taha" }
]
}Pure'da response'u kendiniz olusturursunuz:
// Pure - Manuel response olusturma
[HttpGet]
public IActionResult GetAll()
{
var r = _svc.GetAll();
return Ok(new { status = true, data = r.Data });
}Tum kombinasyonlar icin Test/ klasorunde 18 canli proje bulunur. En sik kullanilan 3 kurulum:
Kaynak:
Test/AutoMapper_Serilog_Return/Api/Program.cs
using Api.Services;
using Api.Mapping;
using Blog.Domain.Interfaces;
using Blog.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Return.Logging;
using Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services.AddControllers();
builder.Services.AddDbContext<BlogDbContext>(opt =>
opt.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=BlogDb;Trusted_Connection=True;"));
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
builder.Services.AddAutoMapper(typeof(BlogProfile));
builder.Services.AddScoped<IBlogService, BlogService>();
builder.Services.AddReturnLogging();
var app = builder.Build();
app.MapControllers();
app.Run();Kaynak:
Test/Default_None_Return/Api/Program.cs
using Api.Services;
using Blog.Domain.Interfaces;
using Blog.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Return.Map.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<BlogDbContext>(opt =>
opt.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=BlogDb;Trusted_Connection=True;"));
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
builder.Services.AddReturnMapper();
builder.Services.AddScoped<IBlogService, BlogService>();
var app = builder.Build();
app.MapControllers();
app.Run();Kaynak:
Test/AutoMapper_Serilog_Pure/Api/Program.cs
using Api.Services;
using Blog.Domain.Interfaces;
using Blog.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Serilog;
using AutoMapper;
using Api.Mapping;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services.AddControllers();
builder.Services.AddDbContext<BlogDbContext>(opt =>
opt.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=BlogDb;Trusted_Connection=True;"));
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
builder.Services.AddAutoMapper(typeof(BlogProfile));
builder.Services.AddScoped<IBlogService, BlogService>();
var app = builder.Build();
app.MapControllers();
app.Run();Test/ klasorunde 18 farkli kombinasyonla Blog CRUD uygulamasi bulunur:
| Kombinasyon | Adedi | Aciklama |
|---|---|---|
| AutoMapper x Serilog x Return/Pure | 2 | Reflection mapping + structed logging |
| AutoMapper x MEL x Return/Pure | 2 | Reflection mapping + Microsoft logging |
| AutoMapper x None x Return/Pure | 2 | Reflection mapping, log yok |
| Mapster x Serilog x Return/Pure | 2 | Code-gen mapping + structed logging |
| Mapster x MEL x Return/Pure | 2 | Code-gen mapping + Microsoft logging |
| Mapster x None x Return/Pure | 2 | Code-gen mapping, log yok |
| Default x Serilog x Return/Pure | 2 | Return.Map + structed logging |
| Default x MEL x Return/Pure | 2 | Return.Map + Microsoft logging |
| Default x None x Return/Pure | 2 | Return.Map, log yok |
Her proje ayri port ve ayri veritabani kullanir. Tumu build ve CRUD testlerinden gecmistir.
Benchmark sonuclari icin: Test/Blog.Benchmark/RESULTS.md
Kapsamli Benchmark: Tum Return tipleri, mapper'lar, validation, logging, struct vs record, Pure vs Full karsilastirmalari icin → Benchmark.md
- Core IReturn / IReturn arayuzleri
- Result Factory (Ok, Fail, Warn, Critical)
- Severity (Success, Warning, Error, Critical)
- Context (TraceId, Timestamp, Metadata)
- Try/Catch Wrapper (sync + async)
- Fluent Builder API
- Custom Error Codes & Localization (EN/TR)
- Logging (Serilog + MEL)
- Return.Map (Expression tree mapping)
- Return.Pure (Minimal surum)
- Return.AspNetCore (Middleware + IActionResult)
- ToResponse() JSON serialization
- Struct tipler (GC-free)
- Extension metotlari (Match, Bind, Map, Tap, Ensure)
- Async extension'lar (WhenAll, WhenAny)
- 18 kombinasyonlu canli test projeleri
- BenchmarkDotNet performans testi
- Swagger/OpenAPI entegrasyonu
- CLI araclari (dotnet return init)
- Daha fazla validation destegi
TahaMucasiroglu.Return v2.0.0 is a comprehensive and extensible library designed to standardize return values of method and service calls in C#.
With IReturn and IReturn<T> interfaces, it encapsulates error, warning, success, and critical states in a single object.
- Reduce code duplication: Return a single result object using
IReturn/IReturn<T>instead of different return types - Centralized error handling: Error message, exception, error code, severity, and data (
Data) in one object - Automatic logging: Log all operation results with Serilog or MEL without writing any logging code
- Try/Catch Wrapper: Safe method calls without manual try/catch blocks
- Fluent Builder API: Build complex result objects with chained method calls
- Custom Error Codes: Define custom error codes with localization support
- SOLID & Clean Code: Thread-safe and maintainable infrastructure with immutable
recordtypes
| Feature | Description |
|---|---|
IReturn / IReturn<T> |
Standard return interfaces |
SuccessReturn / ErrorReturn / WarningReturn / CriticalReturn |
Predefined record types |
Result Factory |
Ok(), Fail(), Warn(), Critical() methods |
| Try/Catch Wrapper | Safe method calls with Result.Try() |
| Fluent Builder | Result.Create().WithSuccess().WithData(obj).Build() |
| Custom Error Codes | ReturnErrorCode enum + localization |
| Severity | Success, Warning, Error, Critical |
| Context | TraceId, Timestamp, Metadata |
| Logging | Serilog / MEL automatic logging |
| Mapping | Built-in mapping via Return.Map |
| ASP.NET Core | Middleware + ToResponse() + IActionResult |
| Pure | Minimal, zero-overhead version |
| Structs | GC-free struct alternatives |
| Package | Version | Description |
|---|---|---|
TahaMucasiroglu.Return |
2.0.0 | Core library |
TahaMucasiroglu.Return.Pure |
2.0.0 | Minimal version (no logging, context) |
TahaMucasiroglu.Return.Map |
2.0.0 | Expression tree-based mapping |
TahaMucasiroglu.Return.Logging |
2.0.0 | Serilog / MEL automatic logging |
TahaMucasiroglu.Return.AspNetCore |
2.0.0 | ASP.NET Core middleware + IActionResult |
# Core library
dotnet add package TahaMucasiroglu.Return
# Pure (minimal)
dotnet add package TahaMucasiroglu.Return.Pure
# Mapping support
dotnet add package TahaMucasiroglu.Return.Map
# Logging support
dotnet add package TahaMucasiroglu.Return.Logging
# ASP.NET Core integration
dotnet add package TahaMucasiroglu.Return.AspNetCoreusing Return.Abstract;
using Return.Factory;
// Success with data
IReturn<string> success = Result.Ok("Hello World");
Console.WriteLine(success.Status); // true
Console.WriteLine(success.Data); // "Hello World"
// Error
IReturn error = Result.Fail("An error occurred");
Console.WriteLine(error.Status); // false
Console.WriteLine(error.Message); // "An error occurred"
// Error with generic type
IReturn<int> notFound = Result.Fail<int>("User not found");
Console.WriteLine(notFound.Status); // false
Console.WriteLine(notFound.Data); // 0 (default)public interface IReturn
{
bool Status { get; }
Severity Severity { get; }
string? Message { get; }
Exception? Exception { get; }
int? ErrorCode { get; }
ReturnContext? Context { get; init; }
}public interface IReturn<T> : IReturn
{
T? Data { get; init; }
bool IsDataNull { get; }
bool IsDataNotNull { get; }
bool CheckStatusAndData { get; } // Status == true && Data != null
}using Return.Concrete;
// Success
new SuccessReturn();
new SuccessReturn("Operation successful");
new SuccessReturn<string>("Hello");
// Error
new ErrorReturn("Record not found");
new ErrorReturn<string>(default, "User not found");
// Warning
new WarningReturn("Low stock warning");
// Critical
new CriticalReturn("Database connection lost");Create results without knowing concrete types:
using Return.Factory;
// Success
Result.Ok();
Result.Ok("Operation successful");
Result.Ok(myData);
Result.Ok(myData, "Record created");
// Error
Result.Fail("Error message");
Result.Fail(exception);
Result.Fail("Error", exception);
// Error (generic)
Result.Fail<User>("User not found");
// Warning
Result.Warn("Stock running low");
Result.Warn(data, "Data may be stale");
// Critical
Result.Critical("Service unavailable");
Result.Critical("Connection failed", ex);public enum Severity
{
Success, // Operation succeeded
Warning, // Warning condition
Error, // Error occurred
Critical // Critical failure
}Every IReturn object carries a Severity value:
var result = Result.Warn("Disk space running low");
Console.WriteLine(result.Severity); // WarningSafe method calls without manual try/catch blocks:
using Return.Factory;
// Sync
IReturn result = Result.Try(() => RiskyOperation());
IReturn<User> result = Result.Try(() => GetUser(id));
// Async
IReturn result = await Result.TryAsync(() => RiskyAsyncOperation());
IReturn<User> result = await Result.TryAsync(() => GetUserAsync(id));Service Layer Example:
public IReturn<Order> CreateOrder(CreateOrderRequest request)
{
return Result.Try(() =>
{
var order = new Order(request.ProductId, request.Quantity);
_repo.Add(order);
return Result.Ok(order, "Order created");
});
}Build complex result objects with chained method calls:
using Return.Factory;
var result = Result.Create()
.WithSuccess()
.WithData(user)
.WithMessage("User retrieved")
.WithTraceId()
.WithTimestamp()
.Build();
// => IReturn<User>
var error = Result.Create()
.WithError()
.WithMessage("Unauthorized access")
.WithErrorCode(ReturnErrorCode.Unauthorized)
.WithContext("ip", "192.168.1.1")
.Build();
// => IReturn
var warning = Result.Create()
.WithWarning()
.WithData(stocks)
.WithMessage("Stock at critical level")
.Build();
// => IReturn<List<Stock>>Standardize error codes with multi-language support.
Set the language for all error messages using the
ReturnLanguageenum.
using Return.Localization;
// Turkish
ReturnLocalization.Language = ReturnLanguage.Turkish;
// English
ReturnLocalization.Language = ReturnLanguage.English;
// Use system culture (default)
ReturnLocalization.Language = ReturnLanguage.Auto;Program.cs example:
using Return.Localization;
var builder = WebApplication.CreateBuilder(args);
// All error messages in Turkish
ReturnLocalization.Language = ReturnLanguage.Turkish;
builder.Services.AddControllers();
// ...
var app = builder.Build();
app.MapControllers();
app.Run();using Return.Localization;
// Bulk registration (EN/TR)
ReturnLocalization.Register(new Dictionary<int, (string en, string tr)>
{
[6001] = ("Payment failed", "Odeme basarisiz"),
[6002] = ("Insufficient balance", "Yetersiz bakiye"),
[6003] = ("Order expired", "Siparis suresi doldu")
});
// Usage - resolves automatically based on language setting
var result = Result.Fail(6001);
// ReturnLanguage.Turkish => "Odeme basarisiz"
// ReturnLanguage.English => "Payment failed"| Value | Description |
|---|---|
ReturnLanguage.Auto |
Uses system culture (default) |
ReturnLanguage.English |
All messages in English |
ReturnLanguage.Turkish |
All messages in Turkish |
When new languages are added in the future, values like
German,Frenchwill be added to the enum.
| Code Range | Category | Examples |
|---|---|---|
| 1001-1999 | Not Found | NotFound, AlreadyExists, DataIsNull |
| 2001-2999 | Validation | ValidationError, InvalidFormat, RequiredFieldMissing |
| 3001-3999 | Auth | Unauthorized, Forbidden, TokenExpired |
| 4001-4999 | System | DatabaseError, ConnectionFailed, Timeout |
| 5001-5999 | Business | BusinessRuleViolation, OperationCancelled, Conflict |
| 9001 | General | Unknown |
using Return.Extensions;
var result = Result.Ok(user);
// Checks
result.IsSuccess(); // true
result.IsError(); // false
// Get data
var data = result.GetDataOrDefault(new User());
// Pattern matching
result.Match(
onSuccess: r => Console.WriteLine("Success"),
onError: r => Console.WriteLine("Error")
);
// Callbacks
result.OnSuccess(r => ProcessUser(r.Data));
result.OnError(r => LogError(r.Message));
// Transformations
var name = result.Map(u => u.Name); // IReturn<string>
var orders = result.Bind(u => GetOrders(u.Id)); // IReturn<List<Order>>
// Side effects
result.Tap(r => Console.WriteLine(r.Data.Name));
// Conditions
result.Ensure(r => r.Data.IsActive, "User is inactive");using Return.Extensions;
var tasks = new[]
{
GetUserAsync(1),
GetUserAsync(2),
GetUserAsync(3)
};
// Wait for all
var all = await tasks.WhenAllReturn();
// Wait for first
var first = await tasks.WhenAnyReturn();
// Combine
var combined = await tasks.CombineAllAsync();// Program.cs
using Return.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseReturnExceptionHandler(); // Global exception handling -> IReturn JSON
app.UseReturnResponse(); // IReturn response serialization
app.MapControllers();
app.Run();using Return.Extensions;
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var result = _service.GetById(id);
return result.Status ? Ok(result.ToResponse()) : NotFound(result.ToResponse());
}ToResponse() output:
{
"status": true,
"message": "Blog created",
"errorCode": null,
"severity": "Success",
"data": { "id": 1, "title": "Hello", "author": "Taha" }
}using Return.AspNetCore.Results;
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var result = _service.GetById(id);
return new ReturnResult<User>(result);
// Success -> 200, Error -> 500, Critical -> 503
}With Return.Logging, all IReturn operations are logged automatically. No logging code needed in your service layer.
Reference:
Test/AutoMapper_Serilog_Return/Api/Program.cs
using Api.Services;
using Blog.Domain.Interfaces;
using Blog.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Return.Logging;
using Serilog;
using Api.Mapping;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services.AddControllers();
builder.Services.AddDbContext<BlogDbContext>(opt =>
opt.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=BlogDb;Trusted_Connection=True;"));
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
builder.Services.AddAutoMapper(typeof(BlogProfile));
builder.Services.AddScoped<IBlogService, BlogService>();
// Return.Logging - automatically log all IReturn operations
builder.Services.AddReturnLogging();
var app = builder.Build();
app.MapControllers();
app.Run("http://localhost:5001");Reference:
Test/AutoMapper_Serilog_Return/Api/Services/BlogService.cs
using Return.Abstract;
using Return.Factory;
public class BlogService : IBlogService
{
private readonly IBlogRepository _repo;
public IReturn<List<BlogDto>> GetAll()
{
var blogs = _repo.GetAll();
var dtos = _mapper.Map<List<BlogDto>>(blogs);
return Result.Ok(dtos);
// Return.Logging handles the logging automatically!
}
public IReturn<BlogDto> GetById(int id)
{
var blog = _repo.GetById(id);
if (blog is null) return Result.Fail<BlogDto>($"Blog {id} not found");
return Result.Ok(_mapper.Map<BlogDto>(blog));
}
}Return.Map provides expression tree-based high-performance mapping.
Reference:
Test/Default_None_Return/Api/Program.cs
using Return.Map.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
// Return.Map - built-in mapping support
builder.Services.AddReturnMapper();
builder.Services.AddScoped<IBlogService, BlogService>();
var app = builder.Build();
app.MapControllers();
app.Run();Return.Pure excludes logging, context, severity, error codes. Ideal for projects that want manual control.
| Feature | Return (Full) | Pure |
|---|---|---|
| Logging | Automatic | Manual |
| Context/TraceId | Yes | No |
| Severity | Yes | No |
| ErrorCode | Yes | No |
| Result Factory | Yes | No (use new directly) |
| Struct types | Yes | No |
Reference:
Test/AutoMapper_Serilog_Pure/Api/Services/BlogService.cs
using Return.Pure.Concrete;
using Return.Pure.Abstract;
using Microsoft.Extensions.Logging;
public class BlogService : IBlogService
{
private readonly IBlogRepository _repo;
private readonly ILogger<BlogService> _logger;
public IReturn<BlogDto> GetById(int id)
{
try
{
var blog = _repo.GetById(id);
if (blog is null)
return new ErrorReturn<BlogDto>(default, $"Blog {id} not found");
return new SuccessReturn<BlogDto>(_mapper.Map<BlogDto>(blog));
}
catch (Exception ex)
{
_logger.LogError(ex, "GetById failed");
return new ErrorReturn<BlogDto>(default, ex.Message);
}
}
}Reference:
Test/AutoMapper_Serilog_Pure/Api/Controllers/BlogController.cs
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
var r = _svc.GetById(id);
return r.Status
? Ok(new { status = true, data = r.Data })
: NotFound(new { status = false, message = r.Message });
}With Full Return, call ToResponse() in your controller. Data is automatically serialized:
// Full Return - automatic JSON via ToResponse()
[HttpGet]
public IActionResult GetAll() => Ok(_service.GetAll().ToResponse());Output:
{
"status": true,
"message": null,
"errorCode": null,
"severity": "Success",
"data": [
{ "id": 1, "title": "Blog 1", "content": "...", "author": "Taha" }
]
}With Pure, you build the response yourself:
// Pure - manual response construction
[HttpGet]
public IActionResult GetAll()
{
var r = _svc.GetAll();
return Ok(new { status = true, data = r.Data });
}The Test/ directory contains 18 live projects with all combinations. Here are the 3 most common setups:
Source:
Test/AutoMapper_Serilog_Return/Api/Program.cs
using Api.Services;
using Api.Mapping;
using Blog.Domain.Interfaces;
using Blog.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Return.Logging;
using Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services.AddControllers();
builder.Services.AddDbContext<BlogDbContext>(opt =>
opt.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=BlogDb;Trusted_Connection=True;"));
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
builder.Services.AddAutoMapper(typeof(BlogProfile));
builder.Services.AddScoped<IBlogService, BlogService>();
builder.Services.AddReturnLogging();
var app = builder.Build();
app.MapControllers();
app.Run();Source:
Test/Default_None_Return/Api/Program.cs
using Api.Services;
using Blog.Domain.Interfaces;
using Blog.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Return.Map.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<BlogDbContext>(opt =>
opt.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=BlogDb;Trusted_Connection=True;"));
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
builder.Services.AddReturnMapper();
builder.Services.AddScoped<IBlogService, BlogService>();
var app = builder.Build();
app.MapControllers();
app.Run();Source:
Test/AutoMapper_Serilog_Pure/Api/Program.cs
using Api.Services;
using Blog.Domain.Interfaces;
using Blog.Infrastructure;
using Microsoft.EntityFrameworkCore;
using Serilog;
using AutoMapper;
using Api.Mapping;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();
builder.Services.AddControllers();
builder.Services.AddDbContext<BlogDbContext>(opt =>
opt.UseSqlServer(@"Server=(localdb)\MSSQLLocalDB;Database=BlogDb;Trusted_Connection=True;"));
builder.Services.AddScoped<IBlogRepository, BlogRepository>();
builder.Services.AddAutoMapper(typeof(BlogProfile));
builder.Services.AddScoped<IBlogService, BlogService>();
var app = builder.Build();
app.MapControllers();
app.Run();The Test/ directory contains 18 Blog CRUD applications with different combinations:
| Combination | Count | Description |
|---|---|---|
| AutoMapper x Serilog x Return/Pure | 2 | Reflection mapping + structured logging |
| AutoMapper x MEL x Return/Pure | 2 | Reflection mapping + Microsoft logging |
| AutoMapper x None x Return/Pure | 2 | Reflection mapping, no logging |
| Mapster x Serilog x Return/Pure | 2 | Code-gen mapping + structured logging |
| Mapster x MEL x Return/Pure | 2 | Code-gen mapping + Microsoft logging |
| Mapster x None x Return/Pure | 2 | Code-gen mapping, no logging |
| Default x Serilog x Return/Pure | 2 | Return.Map + structured logging |
| Default x MEL x Return/Pure | 2 | Return.Map + Microsoft logging |
| Default x None x Return/Pure | 2 | Return.Map, no logging |
Each project uses a separate port and database. All have passed build and CRUD live tests (18/18).
For benchmark results: Test/Blog.Benchmark/RESULTS.md
Comprehensive Benchmark: All Return types, mappers, validation, logging, struct vs record, Pure vs Full comparisons → Benchmark.md
- Core IReturn / IReturn interfaces
- Result Factory (Ok, Fail, Warn, Critical)
- Severity (Success, Warning, Error, Critical)
- Context (TraceId, Timestamp, Metadata)
- Try/Catch Wrapper (sync + async)
- Fluent Builder API
- Custom Error Codes & Localization (EN/TR)
- Logging (Serilog + MEL)
- Return.Map (Expression tree mapping)
- Return.Pure (Minimal version)
- Return.AspNetCore (Middleware + IActionResult)
- ToResponse() JSON serialization
- Struct types (GC-free)
- Extension methods (Match, Bind, Map, Tap, Ensure)
- Async extensions (WhenAll, WhenAny)
- 18-combination live test projects
- BenchmarkDotNet performance tests
- Swagger/OpenAPI integration
- CLI tools (dotnet return init)
- Extended validation support