نظرة عامة على مسار ASP.NET Core
افهموا كيفية مرور الطلبات عبر مسار middleware وHttpContext، وكيفية بناء الاستجابات تدريجيًا.
نظرة عامة على مسار ASP.NET Core درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 4 دروس في المجموع.
مسار معالجة الطلبات
يمر كل طلب HTTP في ASP.NET Core عبر مسار البرمجية الوسيطة. ويمكن لكل جزء من البرمجية الوسيطة فحص الطلب أو تعديله أو إيقافه مبكرًا أو تمريره إلى المكوّن التالي. ويُعد فهم هذا المسار أمرًا أساسيًا لبناء تطبيقات ASP.NET Core.
HttpContext: غلاف الطلب
يحمل HttpContext كل ما يتعلق بالطلب والاستجابة: الرؤوس وملفات تعريف الارتباط والمحتوى ومطالبات المستخدم ومعلومات الاتصال ورمز الإلغاء. وتعمل جميع البرمجيات الوسيطة عليه.
app.Use(async (context, next) =>
{
// Read request info
var method = context.Request.Method;
var path = context.Request.Path;
var headers = context.Request.Headers;
var user = context.User.Identity?.Name;
// Write to response
context.Response.Headers.Append("X-Processed-By", "MyMiddleware");
await next(context); // forward to next middleware
});ترتيب تسجيل البرمجيات الوسيطة
تُشغَّل البرمجيات الوسيطة بالترتيب الذي سُجّلت به. وتُفك الاستجابة بالترتيب العكسي، مثل المكدس. والترتيب مهم للغاية: يجب تشغيل المصادقة قبل التخويل، والتوجيه قبل مطابقة نقاط النهاية.
// Typical order for an ASP.NET Core app:
app.UseExceptionHandler("/error"); // outermost — catches everything
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors("policy");
app.UseAuthentication(); // must be before Authorization
app.UseAuthorization();
app.UseRateLimiter();
app.UseOutputCache();
// MapHub, MapControllers, MapGet etc.
app.Run();Use وRun وMap
تضيف ثلاث طرائق برمجيات وسيطة: Use التي تستدعي التالي، وRun النهائية التي لا تستدعي التالي مطلقًا، وMap التي تفرّع المسار بناءً على المسار.
// Use: passes to next
app.Use(async (ctx, next) =>
{
Console.WriteLine("Before");
await next(ctx);
Console.WriteLine("After");
});
// Run: terminal — no next
app.Run(async ctx =>
await ctx.Response.WriteAsync("Terminal"));
// Map: branch on path prefix
app.Map("/api", apiApp =>
apiApp.Run(async ctx =>
await ctx.Response.WriteAsync("API branch")));محتوى الطلب والاستجابة
محتوى الطلب والاستجابة عبارة عن تدفقات. وتتم قراءة محتوى الطلب مرة واحدة فقط؛ لذلك فعّل التخزين المؤقت لمحتوى الطلب إذا احتجت إلى قراءته عدة مرات، مثلًا في عدة برمجيات وسيطة.
app.Use(async (ctx, next) =>
{
// Enable buffering so body can be read multiple times
ctx.Request.EnableBuffering();
using var reader = new StreamReader(
ctx.Request.Body,
leaveOpen: true);
var body = await reader.ReadToEndAsync();
ctx.Request.Body.Position = 0; // rewind for next middleware
Console.WriteLine($"Body: {body}");
await next(ctx);
});الإيقاف المبكر لمسار التنفيذ
يمكن للبرمجية الوسيطة إيقاف المسار مبكرًا من خلال كتابة الاستجابة وعدم استدعاء next. ويفيد ذلك في بوابات المصادقة وفحوصات الصحة وصفحات الصيانة.
app.Use(async (ctx, next) =>
{
if (ctx.Request.Path == "/maintenance")
{
ctx.Response.StatusCode = 503;
await ctx.Response.WriteAsync("Service under maintenance");
return; // short-circuit — next is NOT called
}
await next(ctx);
});واجهة IMiddleware
لإنشاء برمجية وسيطة قائمة على فئة وتحتاج إلى DI، نفّذ IMiddleware. سجّل التنفيذ في DI واستخدم app.UseMiddleware<T>().
public class RequestTimingMiddleware : IMiddleware
{
private readonly ILogger<RequestTimingMiddleware> _logger;
public RequestTimingMiddleware(ILogger<RequestTimingMiddleware> l) => _logger = l;
public async Task InvokeAsync(HttpContext ctx, RequestDelegate next)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
await next(ctx);
_logger.LogInformation("{Method} {Path}: {Ms}ms",
ctx.Request.Method, ctx.Request.Path, sw.ElapsedMilliseconds);
}
}
// Register:
builder.Services.AddTransient<RequestTimingMiddleware>();
app.UseMiddleware<RequestTimingMiddleware>();فئات البرمجيات الوسيطة التقليدية
بديلًا عن ذلك، أنشئ فئة تحتوي على طريقة InvokeAsync(HttpContext, RequestDelegate). ويحقن الإطار التبعيات، بما فيها المفوّض التالي، عبر المُنشئ.
public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private readonly string _key;
// RequestDelegate injected by framework
public ApiKeyMiddleware(RequestDelegate next, IConfiguration cfg)
{
_next = next;
_key = cfg["ApiKey"] ?? "";
}
public async Task InvokeAsync(HttpContext ctx)
{
if (ctx.Request.Headers["X-Api-Key"] != _key)
{
ctx.Response.StatusCode = 401;
return;
}
await _next(ctx);
}
}تعديل الاستجابات بعد Next
تُشغَّل الشيفرة التي تأتي بعد await next(ctx) عقب بدء كتابة الاستجابة. ويمكنك إضافة رؤوس الاستجابة قبل next، لكن لا يمكنك تعديل رمز الحالة أو محتوى الاستجابة بعد ذلك.
app.Use(async (ctx, next) =>
{
// Before: add response headers (safe)
ctx.Response.OnStarting(() =>
{
ctx.Response.Headers.Append("X-Request-Id",
Guid.NewGuid().ToString("N"));
return Task.CompletedTask;
});
await next(ctx);
// After: response may already be sent
// SAFE: logging, metrics
// UNSAFE: changing status code or writing body
Console.WriteLine($"Response status: {ctx.Response.StatusCode}");
});من واقع عملي: برمجية وسيطة لمعرّف الارتباط
برمجية وسيطة لمعرّف ارتباط مخصّصة للإنتاج، تضيف معرّف تتبّع إلى كل طلب لأغراض التتبّع الموزّع وتسجيل السجلات.
public class CorrelationIdMiddleware
{
private readonly RequestDelegate _next;
private const string Header = "X-Correlation-Id";
public CorrelationIdMiddleware(RequestDelegate next) => _next = next;
public async Task InvokeAsync(HttpContext ctx)
{
var correlationId = ctx.Request.Headers[Header].FirstOrDefault()
?? Guid.NewGuid().ToString("N");
ctx.Items["CorrelationId"] = correlationId;
ctx.Response.OnStarting(() =>
{
ctx.Response.Headers.Append(Header, correlationId);
return Task.CompletedTask;
});
using (Serilog.Context.LogContext.PushProperty("CorrelationId", correlationId))
await _next(ctx);
}
}تحقق سريع
ما الفرق بين app.Use() وapp.Run() عند إضافة برمجية وسيطة؟
مراجعة: نظرة عامة على مسار ASP.NET Core
أهم النقاط:
- تُشغَّل البرمجيات الوسيطة بترتيب التسجيل، وتُفك الاستجابات بالترتيب العكسي
- Use ← تستدعي التالي؛ Run ← نهائية؛ Map ← تفرّع يعتمد على المسار
- يحتوي HttpContext على الطلب والاستجابة والمستخدم ورمز الإلغاء
- فعّل التخزين المؤقت لقراءة محتوى الطلب عدة مرات
- تتيح واجهة IMiddleware إنشاء برمجيات وسيطة قائمة على الفئات ومتوافقة مع DI
- أضف رؤوس الاستجابة باستخدام OnStarting()؛ ولا تغيّر الحالة بعد next
الأسئلة الشائعة
هل درس «نظرة عامة على مسار ASP.NET Core» مجاني؟
نعم — نص درس «نظرة عامة على مسار ASP.NET Core» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.
ماذا ستتعلم في «نظرة عامة على مسار ASP.NET Core»؟
افهموا كيفية مرور الطلبات عبر مسار middleware وHttpContext، وكيفية بناء الاستجابات تدريجيًا. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟
لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «نظرة عامة على مسار ASP.NET Core»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟
نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- نظرة عامة على مسار ASP.NET Core
- كتابة Middleware مخصّص
- الإيقاف المبكر والتفرّع
- ترتيب Middleware وMiddleware المضمّن