🌍 مثالهای واقعی از Extension Memberها
در Web APIها، معمولاً نیاز داریم اطلاعاتی از HttpContext استخراج کنیم.
بهجای تکرار کدهای مشابه، میتوانیم extension بنویسیم تا کد تمیزتر شود ✨
public static class ApiHttpContextExtensions
{
extension(HttpContext context)
{
public string CorrelationId =>
context.Request.Headers["X-Correlation-ID"].FirstOrDefault()
?? Guid.NewGuid().ToString();
public string ClientIp =>
context.Request.Headers["X-Forwarded-For"].FirstOrDefault()
?? context.Connection.RemoteIpAddress?.ToString()
?? "Unknown";
public bool IsApiRequest =>
context.Request.Path.StartsWithSegments("/api");
public string? GetBearerToken()
{
var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
if (authHeader?.StartsWith("Bearer ") == true)
{
return authHeader.Substring("Bearer ".Length).Trim();
}
return null;
}
public T? GetQueryParameter<T>(string key)
{
if (context.Request.Query.TryGetValue(key, out var value))
{
try
{
return (T?)Convert.ChangeType(value.ToString(), typeof(T));
}
catch
{
return default;
}
}
return default;
}
public void AddResponseHeader(string key, string value)
{
context.Response.Headers[key] = value;
}
}
extension(HttpContext)
{
public static bool IsValidPath(string path) =>
!string.IsNullOrWhiteSpace(path) && path.StartsWith("/");
}
}
حالا middleware و controllerها بسیار خواناتر میشوند 🧼
public class RequestLoggingMiddleware(
RequestDelegate next,
ILogger<RequestLoggingMiddleware> logger)
{
public async Task InvokeAsync(HttpContext context)
{
_logger.LogInformation(
"Request {Method} {Path} from {ClientIp} with CorrelationId {CorrelationId}",
context.Request.Method,
context.Request.Path,
context.ClientIp,
context.CorrelationId);
context.AddResponseHeader("X-Correlation-ID", context.CorrelationId);
await _next(context);
}
}
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
[HttpGet]
public IActionResult GetOrders(HttpContext httpContext)
{
var pageSize = httpContext.GetQueryParameter<int?>("pageSize") ?? 10;
var pageNumber = httpContext.GetQueryParameter<int?>("page") ?? 1;
var orders = orderService.GetPaged(pageNumber, pageSize);
return Ok(orders);
}
}
📌 نتیجه؟
کد خواناتر 📖، تمیزتر 🧹 و بدون تکرار منطق پیچیدهی استخراج header و query parameterها، با defaultهای معقول ✅