مسیر C#/.NET و آداپتورهای پشته · فصل ۱ — Modern C#، ASP.NET Core، EF Core و Testing · 326

ASP.NET Core Web/API Engineering

دانش قدیمی یا پراکنده‌ی .NET دارد اما آن را با الگوهای مدرن API/data/testing/hosting همگام نکرده است. موضوع جاری: «ASP.NET Core Web/API Engineering». می‌تواند «ASP.NET Core Web/API Engineering» را در یک سرویس .NET محدود اجرا و با تست/diagnostics مناسب verify کند.

ASP.NET Core Web/API Engineering — en-US

خلاصهٔ درس

دانش قدیمی یا پراکنده‌ی .NET دارد اما آن را با الگوهای مدرن API/data/testing/hosting همگام نکرده است. موضوع جاری: «ASP.NET Core Web/API Engineering».

می‌تواند «ASP.NET Core Web/API Engineering» را در یک سرویس .NET محدود اجرا و با تست/diagnostics مناسب verify کند.

خروجی این درس

می‌تواند «ASP.NET Core Web/API Engineering» را در یک سرویس .NET محدود اجرا و با تست/diagnostics مناسب verify کند.

پیش‌نیازها

POST کار می‌کند، اما آیا API درست است؟

نمایش سفارش‌ها قانع‌کننده به نظر می‌رسد: POST /orders یک سفارش برمی‌گرداند و GET /orders/2 آن را می‌خواند. بعد، درخواست بدون احراز هویت هم سفارش می‌سازد. خطای اعتبارسنجی با کد 200 و یک رشتهٔ خطا می‌آید. تکرار POST پس از قطع پاسخ، دو سفارش ایجاد می‌کند. درخواست عادی موفق بوده، اما سه تعهد جدا نقض شده‌اند.

خروجی شما ASP.NET Core API Contract, Failure and Verification Matrix v1 است: ماتریسی که مسیر، ساختار داده، مجوز، خطا، درخواست تکراری، مستند و مشاهدهٔ آزمون را به هم متصل می‌کند. باید بتوانید توضیح دهید شواهد کدام بخش API را تأیید می‌کنند و چه چیزی مانع ادعای بیشتر است.

۶۰ دقیقهٔ فعال در نظر بگیرید: ۱۰ دقیقه مبانی، ۱۵ دقیقه مثال حل‌شده، ۱۵ دقیقه تشخیص هدایت‌شده، ۱۵ دقیقه انتقال PATCH و ۵ دقیقه دفاع از تصمیم. بخش اصلی به Python 3.10+ و JSON/CSVهای آماده نیاز دارد و بستهٔ خارجی نمی‌خواهد. pipeline_demo.py واقعاً مدل درون‌فرایندی پایتون را با درخواست مصنوعی اجرا می‌کند؛ پورت شبکه باز نمی‌کند، توکن واقعی را اعتبارسنجی نمی‌کند و اجرای ASP.NET Core نیست. قطعه‌های C# مرز متناظر در چارچوب را توضیح می‌دهند؛ پروژهٔ قابل build یا مدرک اجرای ناشر نیستند.

برای کسی که با C# و فراخوانی ناهمگام آشناست، به .NET برگشته و می‌خواهد مرز Web/API را آگاهانه و آزمون‌پذیر طراحی کند.

این درس سامانهٔ هویت عملیاتی، migration پایگاه داده، بستر اجرای worker یا آمادگی استقرار را پیاده نمی‌کند؛ هرکدام شاهد مخصوص خود را می‌خواهند.

نقطهٔ ورودتان را انتخاب کنید

NET-001 پیش‌نیاز الزامی و درس قبلی در ترتیب یادگیری است. پس از این درس، NET-003 به دسترسی به داده می‌پردازد. خروجی میزبانی و عیب‌یابی متعلق به NET-004 است؛ تکمیل ماتریس API آن خروجی را تکمیل نمی‌کند.

فرق ویژگی nullable در DTO و عضو اختیاری JSON را بگویید. توضیح دهید await منتظر چیست، مالک وابستگی scoped کیست و چرا exception خودبه‌خود پاسخ HTTP مناسبی نیست.

DTO شکل دادهٔ عبوری از یک مرز را بیان می‌کند و لازم نیست همان entity ذخیره‌شده باشد. binding مقدارهای درخواست را می‌سازد؛ validation قابل‌قبول‌بودن آن‌ها را بررسی می‌کند. وابستگی از طرف handler کار انجام می‌دهد؛ در محدودهٔ عمرش منتظر پایان کار بمانید. رسیدگی به خطا، خرابی منتخب را به پاسخ عمومی تبدیل می‌کند. برای بررسی فهم، توضیح دهید چرا عدد صفر می‌تواند بدون خطای binding خوانده شود، اما قاعدهٔ سفارش را نقض کند.

مسیر پایه: نگاشت فیلدها و هر دو مثال را بخوانید، سپس تمرین را باز کنید. مسیر ترمیم: نخستین تعهد شکسته را پیدا کنید، اما علت‌های دیگر را تا رفع‌شدن نگه دارید. مسیر باتجربه: مقایسهٔ گزینه‌ها را ببینید و به تمرین بروید. هر سه مسیر همان ماتریس، شواهد منفی و انتقال به زمینهٔ تازه را تحویل می‌دهند.

تعهد، پیاده‌سازی و مشاهده را جدا بشناسید

قرارداد HTTP می‌گوید کلاینت چه می‌فرستد و چه می‌گیرد. pipeline ترتیب مسیریابی، هویت، بررسی مجوز، binding و کار handler را مشخص می‌کند. سند OpenAPI عملیات و ساختار داده را توصیف می‌کند. مشاهدهٔ آزمون یک اجرا را زیر میزبان و تنظیمات مشخص ثبت می‌کند. هیچ‌کدام جای دیگری را نمی‌گیرد.

ممکن است POST مستند باشد، اما مجوزش اعمال نشود. ممکن است مجوز درست اعمال شود، اما مستند قدیمی باشد. ممکن است تست مستقیماً handler را صدا بزند و از middlewareای بگذرد که ادعای آزمودنش را دارد. پیش از پرسیدن «قبول شد؟» بپرسید «این مشاهده از کدام مرز عبور کرد؟».

معادل متنی نمودار: نیاز و قرارداد HTTP را تعریف کنید؛ احراز هویت، مجوز و اعتبارسنجی را بررسی کنید؛ نسخهٔ پیاده‌سازی را مشخص کنید؛ OpenAPI را بسازید و مقایسه کنید؛ میزبان آزمونِ نام‌دار را با حالت‌های عادی و منفی اجرا کنید؛ پاسخ و اثر جانبی را ببینید. شاهد ناقص یا قدیمی یعنی HOLD. تناقض یعنی تعمیر و اجرای دوباره با حفظ HOLD. شواهد کامل فقط VERIFIED_SYNTHETIC در محدودهٔ SYNTHETIC_ONLY را مجاز می‌کنند، نه تأیید اجرای چارچوب یا استقرار.

NET-002-F1 — بازیابی مرز. تفاوت مسیر ثبت‌شده در OpenAPI و مجوز اعمال‌شده چیست؟ یک مشاهده نام ببرید که فراخوانی مستقیم handler اثباتش نمی‌کند. اگر یکی را مدرک کل pipeline دانستید، به چهار نوع رکورد بالا برگردید.

پیش از حکم، ماتریس را بخوانید

پرسشفیلدهای پاسخ‌دهندهشاهد لازم
کدام عملیات؟endpoint_id، http_method، route_templateدرخواست و revision دقیق
چه داده‌ای عبور می‌کند؟schema ورودی/خروجی، قرارداد status، قاعدهٔ validationبدنه، وضعیت و media type
چه کسی اجازه دارد؟وضعیت احراز هویت، سیاست مجوزحالت بدون هویت و بدون مجوز؛ صفر نوشتن
در تکرار یا خرابی چه می‌شود؟تعهد idempotency، مرز وابستگیمشاهدهٔ replay، تعارض و خرابی
آیا شاهد به همین زمینه تعلق دارد؟مستند، میزبان، تنظیمات، دو digest، بازبینی و شناسهٔ auditcapture و تاریخ معتبر

فایل کامل NET-002-T1.csv دارای ۲۲ ستون و یک ردیف برای هر حالت baseline است. field_map.json نشان می‌دهد هر ستون از کجای fixture قابل‌مشاهده می‌آید؛ integration_test_case شناسهٔ حالت در مدل است، نه ادعای اجرای تست ASP.NET. جدول کوتاه مثال کمک‌خوان است و جای خروجی کامل را نمی‌گیرد.

UNKNOWN یعنی ورودی تعیین‌کننده ناشناخته است. UNVERIFIED یعنی شاهد، ادعا را برقرار نکرده؛ UNSUPPORTED یعنی قرارداد یا محیط از ادعا پشتیبانی نمی‌کند. STALE شاهد مربوط به زمان یا زمینهٔ نامناسب است. FAILED انتظار نقض‌شده را ثبت می‌کند و REVIEW_REQUIRED تصمیم را باز نگه می‌دارد. هر بُعد بحرانی حل‌نشده به HOLD می‌انجامد؛ با میانگین‌گرفتن از نوزده بررسی سبز ناپدید نمی‌شود.

یک درخواست منفی می‌تواند آزمون موفق داشته باشد: ردکردن POST بدون هویت با challenge تعریف‌شده و بدون نوشتن، رفتار مورد انتظار است. این با پذیرفتن ناخواستهٔ همان درخواست فرق دارد.

مرز را آگاهانه پیاده کنید

DTO، binding و اعتبارسنجی

POST تمرین دقیقاً customerReference و quantity صحیح را می‌پذیرد. عضو مفقود یا اضافی، JSON خراب و quantity رشته‌ای پاسخ 400 دارند؛ media type پشتیبانی‌نشده 415 می‌گیرد. مرجع غیرخالی با حداکثر ۴۰ نویسه و quantity بین ۱ تا ۲۰ قواعد دامنه‌اند؛ نقض آن‌ها با ورودی دارای ساختار معتبر، 422 می‌دهد. این‌ها تصمیم‌های صریح تمرین‌اند و همگی پیش‌فرض ASP.NET نیستند.

مثلاً { "customerReference": "desk-7", "quantity": 0 } به اعتبارسنجی دامنه می‌رسد، اما حق ساخت سفارش ندارد. رشتهٔ "2" حالت دیگری برای binding است. طول مرجع از رشتهٔ اصلی JSON، با احتساب فاصلهٔ ابتدا و انتها، محاسبه می‌شود؛ مرجع کوتاه پذیرفته‌شده بدون تغییر ذخیره می‌شود و رشتهٔ فقط‌فاصله رد می‌شود. مدل ما عضو ناشناخته را رد می‌کند؛ اگر همین رفتار را در C# می‌خواهید، serializer را جداگانه تنظیم و آزمون کنید.

ASP.NET Core 10 برای Minimal API از validation با AddValidation پشتیبانی می‌کند؛ کنترلر دارای [ApiController] پاسخ خودکار اعتبارسنجی مدل دارد. پیش‌فرض کنترلر 400 است، نه 422 دامنه‌ای ما. مشخص کنید مالک هر قاعده، سازوکار چارچوب است یا منطق صریح handler، و پاسخ حاصل را بیازمایید. اعتبارسنجی، API مبتنی بر کنترلر

DTO در C# می‌تواند شکل انتقال را بیان کند:

public sealed record CreateOrderRequest(string CustomerReference, int Quantity);
public sealed record OrderResponse(int Id, string CustomerReference, int Quantity);

این تعریف‌ها به‌تنهایی همهٔ درخواست‌های خراب یا نامعتبر معنایی را رد نمی‌کنند. در پروژه‌ای که جداگانه تنظیم شده، اعتبارسنجی صریح دامنه می‌تواند Results.Problem(statusCode: 422, title: "Order validation failed") برگرداند. قرارداد کامل بدنهٔ خطای ما type، instance و شناسهٔ trace هم می‌خواهد؛ این قطعهٔ کوتاه مدرک تنظیم آن فیلدها نیست.

هویت، سپس مجوز، سپس کار

احراز هویت مشخص می‌کند فراخواننده کیست؛ authorization تعیین می‌کند چه کاری اجازه دارد. این بخش برای GET مجوز Orders.Read و برای POST/PATCH مجوز Orders.Write می‌خواهد. درخواست بدون هویت 401 با WWW-Authenticate: Bearer می‌گیرد؛ شخص احرازشدهٔ فاقد مجوز 403 می‌گیرد. این‌ها حالت‌های قراردادی ما هستند. تست باید نشان دهد پیش از رد درخواست، نوشتنی رخ نداده است. امنیت Minimal API، معنای HTTP

در پروژه‌ای که احراز هویت Bearer آن از قبل درست تنظیم شده، ثبت سیاست و اعمال آن دو کار جدا هستند:

builder.Services.AddAuthorization(options => {
    options.AddPolicy("Orders.Write", policy => policy
        .RequireAuthenticatedUser().RequireClaim("permission", "Orders.Write"));
});
// پس از ساخت app؛ CreateOrder هندلر همان پروژه است.
app.MapPost("/orders", CreateOrder)
    .RequireAuthorization("Orders.Write")
    .Produces<OrderResponse>(201)
    .ProducesProblem(422);

برای خواندن هم سیاست متناسب را تعریف و اعمال کنید. متدهای metadata پاسخ مورد انتظار را توصیف می‌کنند؛ validation را پیاده نمی‌کنند. در محصول واقعی، authentication handler باید اعتبارنامه را بررسی و claims را برقرار کند. تمرین پایتون به‌جای آن یک principal مصنوعی و مشخص را در حافظه دریافت می‌کند؛ این سازوکار را به header احراز هویت تحت کنترل کلاینت تبدیل نکنید.

رد مدل به این ترتیب است: رسیدگی به exception، مسیریابی، احراز هویت، مجوز، binding، validation و handler. رد درخواست، کار مراحل بعدی را متوقف می‌کند. این رد، تمرین را توضیح می‌دهد و توصیف همهٔ ترتیب‌های ممکن middleware و filter در ASP.NET نیست. در برنامهٔ واقعی، pipeline تنظیم‌شده و پوشش exception را بیازمایید؛ نام‌های نوشته‌شده در فهرست metadata کافی نیستند.

خطا بخشی از قرارداد پاسخ است

404 حالت منتخب سفارش مفقود است؛ 409 استفادهٔ دوباره از یک کلید idempotency با درخواست متفاوت را نشان می‌دهد؛ 500 خرابی غیرمنتظرهٔ وابستگی است. بدنهٔ خطا با کد 200 خلاف قرارداد ما خبر می‌دهد. وضعیت HTTP، content type، بدنه و اثر را با هم بررسی کنید.

AddProblemDetails پشتیبانی Problem Details را ثبت می‌کند؛ رسیدگی به exception و middleware وضعیت، تحت تنظیمات و content negotiation خود از آن استفاده می‌کنند. این‌ها بدنهٔ خطایی را که قبلاً با 200 نوشته شده، خودکار به پاسخ شکست مطلوب تبدیل نمی‌کنند. آزمون را با Accept پشتیبانی‌شدهٔ JSON اجرا کنید. رسیدگی به خطای API

بدنهٔ امن و ثابت تمرین type، title، status، instance و traceId می‌خواهد؛ status بدنه و HTTP باید یکسان باشند و دادهٔ خصوصی exception نباید بیرون برود. این مجموعهٔ الزامی و فهرست مجاز، طراحی تمرین است؛ ادعا نمی‌کنیم RFC 9457 همهٔ پنج فیلد را همواره الزامی می‌داند. Problem Details اجازهٔ extension می‌دهد و شناسهٔ trace ما یکی از آن‌هاست. مشخصات Problem Details

یک header، POST را idempotent نمی‌کند

سیاست ما کلید را به فراخواننده، method و path محدود می‌کند و به JSON تجزیه‌شده و canonical درخواست متصل می‌سازد. درخواست معتبر اول یک سفارش می‌سازد. تکرار همان کلید و بدنه، 201، بدنه و Location نخست را بدون نوشتن اضافی برمی‌گرداند. بدنهٔ متفاوت با همان کلید 409 می‌گیرد. فراخوانندهٔ دیگر فضای کلید جدا دارد. حالت تکرار هم‌زمان نیز باید فقط یک سفارش بسازد.

api_model.py جست‌وجو، ایجاد و ثبت replay را در یک قفل فرایندی محافظت می‌کند. سازوکار واقعی اما محدود است: با restart نقشه را از دست می‌دهد و با فرایند دیگر هماهنگ نمی‌شود. نه idempotency پایدار را ثابت می‌کند و نه اثر بیرونی دقیقاً یک‌بار را. طراحی واقعی باید ذخیره‌سازی، نگهداری کلید، بازیابی خرابی و هماهنگی را با هم تعیین کند. POST خودبه‌خود idempotent نیست؛ معنای عمومی idempotency به اثر مورد نظر مربوط است، نه لزوماً پاسخ یکسان در همهٔ APIها. پاسخ replay اینجا یک سیاست محلی است. معنای متدهای HTTP

مستند و حالت اجراشده را مقایسه کنید

در ASP.NET Core 10، بستهٔ داخلی OpenAPI با AddOpenApi و MapOpenApi تولید سند را پشتیبانی می‌کند؛ خانوادهٔ پیش‌فرض سند در .NET 10، OpenAPI 3.1 است. دسترسی به endpoint مستندات را آگاهانه تنظیم کنید. تولید مسیر یا اعلان security، مجوز endpoint را اعمال نمی‌کند. OpenAPI در ASP.NET

مولد ما snapshot با نسخهٔ OpenAPI 3.1.1 را از metadata پایتون می‌نویسد. schema درخواست، پاسخ موفق و خطا، header کلید الزامی و security هر عملیات را ببینید و سند را با پیاده‌سازی متصل به آن مقایسه کنید. این خروجی مولد مایکروسافت یا گواهی انطباق کامل با OpenAPI نیست. OpenAPI 3.1.1

برای شاهد اجرای واقعی چارچوب، پروژهٔ تستِ آماده می‌تواند از WebApplicationFactory<Program> و کلاینت HTTP عبوری از test server استفاده کند. هنگام بررسی رد درخواست، redirect خودکار را غیرفعال کنید، test authentication handler مشخص بگذارید و وابستگی دورریختنی جایگزین کنید. درخواست‌ها را از میزبان عبور دهید، نه اینکه مستقیم handler را صدا بزنید. حتی این تست‌ها issuer واقعی توکن، TLS، reverse proxy یا استقرار را ثابت نمی‌کنند. تست یکپارچگی ASP.NET

دو مثال را از روی شواهد حل کنید

بستهٔ تمرین را باز کنید و در پوشهٔ learner اجرا کنید:

python pipeline_demo.py
python generate_openapi.py implementation.baseline.json openapi.rebuilt.json
python run_checks.py --inventory

مدل ۱۹ حالت baseline، از جمله یک جفت درخواست هم‌زمان، را اجرا می‌کند. هر حالت از یک سفارش اولیه شروع می‌شود؛ درخواست‌های چندگانهٔ داخل همان حالت وضعیت مشترک دارند. درخواست‌ها و پاسخ‌های مورد انتظار را در contracts.json بخوانید و خروجی واقعی را با fixtures/baseline.json مقایسه کنید. مقدار مورد انتظار، مشخصات آزمون است؛ مشاهده نیست.

بخش ماتریسbaseline قابل‌مشاهدهدلیل نتیجه
post_created201؛ Location برابر /orders/2؛ یک نوشتنبدنهٔ ایجادشده و ردیف نهایی هم‌خوان‌اند
post_unauthenticated401؛ challenge نوع Bearer؛ صفر نوشتنرد درخواست پیش از binding و handler
post_invalid422؛ problem امن و نوع‌دار؛ صفر نوشتنقاعدهٔ دامنه و پاسخ منطبق‌اند
post_replay / post_concurrentدو پاسخ 201؛ یک نوشتنسفارش یکسان و شمار اثر مشترک
authorization_removedسیاست POST در نسخهٔ پیشنهادی حذف شدهcapture و OpenAPI قبلی به آن متصل نیستند

مثال ۱: baseline. CreateOrder، POST و /orders، سپس schemaهای CreateOrder/Order را پیدا کنید. همهٔ وضعیت‌های قراردادی و قاعدهٔ اعتبارسنجی را مقایسه کنید. حالت بدون هویت، بدون مجوز، replay، بدنهٔ متفاوت با کلید یکسان و خرابی وابستگی را ببینید؛ ردیف اول کافی نیست. digest قرارداد با profile منتخب و digest پیاده‌سازی با metadata نسخه منطبق است؛ منبع مدل، مستند و captureها هویت‌های لازم را دارند. بازبینی، مصنوعی و در 2026-09-12 معتبر است. فیلدهای context_id، contract_digest، implementation_digest و test_host_source_sha256 آن با زمینه، profile منتخب، metadata نسخه و منبع مدل برابرند. اتصال مفقود یا ناسازگارِ بازبینی، حتی با وجود owner و capture_ref، وضعیت CONTEXT_STALE / STALE دارد. قواعد قابل‌مشاهده از VERIFIED_SYNTHETIC در SYNTHETIC_ONLY پشتیبانی می‌کنند، نه از جملهٔ «ASP.NET اجرا شد».

مثال ۲: حذف مجوز. در authorization_removed.json مقدار /implementation/endpoints/1/authorization_policy خالی است، ولی مستند هنوز مسیر POST دارد. نقض سیاست، AUTHORIZATION_GAP با FAILED است؛ اختلاف پیاده‌سازی هم FAILED است. captureهای قبلی CONTEXT_STALE و سند قبلی OPENAPI_STALE ایجاد می‌کنند که هر دو STALE هستند. مجموعهٔ کامل کدها عبارت است از AUTHORIZATION_GAP، CONTEXT_STALE، IMPLEMENTATION_MISMATCH و OPENAPI_STALE؛ وضعیت کلی HOLD است.

کمینهٔ تعمیر، بازگرداندن سیاست لازم روی endpoint درست، مشخص‌کردن نسخهٔ اصلاح‌شده، تولید دوبارهٔ مستند، اجرای حالت‌های عادی و منفیِ متاثر و بازبینی همان زمینه است. ویرایش digest در capture قدیمی، اجرای دوباره نیست. با pipeline_demo.py --fixture fixtures/authorization_removed.json --case post_unauthenticated ببینید چرا مدل تغییرکرده ناامن است. capture تاریخی کپی‌شدهٔ fixture و این نمونهٔ منفی تازه به دو پرسش متفاوت جواب می‌دهند؛ هر دو را نگه دارید.

تعهد نقض‌شده را پیدا کنید

error_as_200 پاسخ مشاهده‌شدهٔ سفارش نامعتبر را به وضعیت موفق HTTP با رشتهٔ خطا تبدیل کرده است. حتی پیام مفید هم نقض معنای پاسخ را جبران نمی‌کند. schema_drift یک عضو الزامی درخواست را تغییر می‌دهد، اما مستند و capture قبلی را نگه می‌دارد. idempotency_missing سازوکار replay را حذف می‌کند. missing_capture برچسب PASS دارد، ولی ارجاع capture قابل استفاده ندارد. برچسب به‌تنهایی دلیل موفقیت هیچ‌کدام نیست.

auth_side_effect هنگام درخواست بدون هویت یک نوشتن ثبت می‌کند؛ بررسی صرف 401 آن را نمی‌بیند. error_disclosure علامت مصنوعی stack خصوصی را به بدنهٔ خرابی اضافه می‌کند؛ حتی 500 درست، افشای آن را توجیه نمی‌کند. بدنه‌های تو‌در‌تو را بررسی و همهٔ علت‌ها را حفظ کنید. stale_review از موعد بازبینی گذشته؛ شاهد تاریخی با سکوت به شاهد روز تبدیل نمی‌شود.

NET-002-F2 — تشخیص حالت منفی. در error_as_200 فیلد پاسخِ خلاف قرارداد، پیامد آن برای کلاینت، کوچک‌ترین تعمیر و حالت نیازمند اجرای مجدد را تعیین کنید. اگر فقط متن پیام را عوض می‌کنید، به معنای خطا برگردید.

برخی علت‌ها عمداً هم‌پوشانی دارند. مشاهدهٔ replay خراب می‌تواند هم پاسخ و هم idempotency را نقض کند. هر دو بُعد را نگه دارید: یکی نتیجهٔ عمومی را توضیح می‌دهد و دیگری تعهد اثر تکراری را. ارزیابی، مجموعهٔ کامل علت‌های شناخته‌شده را بررسی می‌کند؛ حکم کلی درست با علت‌های حذف‌شده ناقص است.

برای خوانندهٔ باتجربهٔ .NET

برگرداندن شیء مطلوب از action کنترلر، رفتار تمام میزبان را ثابت نمی‌کند. مشخص کنید تست از کدام filter، validation مدل، authentication handler و middleware خطا عبور می‌کند. انتقال از کنترلر به Minimal API محل تنظیم قراردادها و validation را تغییر می‌دهد؛ جابه‌جایی مکانیکی handler همهٔ پاسخ‌ها را حفظ نمی‌کند.

شناسه‌های تمرین را دقیق بخوانید. implementation_digest هش JSON canonical مربوط به metadata است، نه اسمبلی کامپایل‌شده یا قطعه‌های C#. فیلد test_host_source_sha256 منبع پایتون اجراشده را مشخص می‌کند. contract_digest هش profile منتخب است؛ contracts_sha256 در submission کل مشخصات عمومی، از جمله انتظارهای آزمون، را متصل می‌کند. هش ارتباط و تغییر را نشان می‌دهد؛ حقیقت یا اختیار بازبین را ایجاد نمی‌کند.

مسیریاب مدل فقط مسیر رقمی غیرمنفیِ محدود این تمرین را می‌پذیرد؛ آزمون انطباق قید int در ASP.NET، سرریز، URL decoding یا همهٔ اولویت‌های مسیریابی نیست. principal، store و کلید timeout آن ابزار آزمون‌اند. برای ادعای واقعی ASP.NET، شاهد مدل را با مدرک میزبان و تنظیمات واقعی، سند تولیدشده و آزمون HTTP جایگزین کنید. نتیجهٔ آموزشی مدل را به‌صورت رکورد جدا حفظ کنید.

سبک و سازوکار را متناسب انتخاب کنید

گزینهموقعیت مناسبهزینه یا مرز
Minimal APIبخش کوچک با mapping آشکار و سیاست صریح endpointبا رشد برنامه، validation، metadata و خطا را یکدست نگه دارید
کنترلرقراردادهای action و filterهای موجود برنامه را منظم می‌کنندپاسخ ناشی از convention و filter را در میزبان بیازمایید
نقشهٔ replay فرایندینمایش دورریختنی به کنترل تکرار قابل مشاهده نیاز داردتضمین restart، چند نمونه یا اثر بیرونی پایدار ندارد
طراحی replay پایدارمحصول وعدهٔ retry میان خرابی و نمونه‌ها می‌دهدطراحی ذخیره‌سازی، تراکنش و نگهداری خارج از تمرین لازم است

Minimal API و کنترلر هر دو رویکردهای پشتیبانی‌شده‌اند. انتخاب به سازمان برنامه و قرارداد آزمون‌پذیر مربوط است، نه حکم همیشگی دربارهٔ سرعت. برای baseline دو عملیاتی، metadata نوع Minimal API را با سیاست آشکار انتخاب کرده‌ایم. معرفی Minimal API

پیش از کپی‌کردن helper پاسخ، قرارداد خطا را انتخاب کنید. روشن کنید خرابی وابستگی پیش از اثر رخ می‌دهد یا پس از آن؛ status به‌تنهایی کار انجام‌شده را برنمی‌گرداند. اگر شواهد این فرق را روشن نمی‌کنند، UNVERIFIED را حفظ و مشاهدهٔ مشخص خرابی را مطالبه کنید؛ تراکنش جبرانی اختراع نکنید.

تمرین کنید، سپس قرارداد را تغییر دهید

برای پاسخ هدایت‌شده ابتدا قالب بسازید:

python run_checks.py --template fixtures/error_as_200.json submission.json --as-of 2026-09-12
python run_checks.py --check fixtures/error_as_200.json submission.json

میان این دو فرمان، تصمیم، مسئله‌های نوع‌دار، JSON pointerها، استدلال، کمینهٔ تعمیر و محرک بازبینی را بنویسید. قالب ورودی، policy، کل contracts و تاریخ را متصل می‌کند، ولی پاسخ را خالی می‌گذارد و فایل موجود را بازنویسی نمی‌کند. STRUCTURE_PASS_SEMANTICS_UNREVIEWED فقط شکل و ارجاع‌های پاسخ را تأیید می‌کند؛ درستی معنایی و توضیح هنوز به بررسی نیاز دارند. تغییرهای دیگر را مستقل و با نام پاسخ جدا حل کنید؛ ورودی‌های اصلی را نگه دارید.

انتقال: PATCH و وابستگی پس‌زمینه. فایل transfer_patch.json با کپی metadata مربوط به POST و نگه‌داشتن captureهای revision اول، PATCH /orders/{id} را اضافه کرده است. ماتریس را از profile نوع GET_POST_PATCH_R2 دوباره بسازید. media type سفارشی application/vnd.maknow.order-patch+json است؛ نه JSON Patch و نه JSON Merge Patch. حذف quantity از بدنه، مقدار فعلی را نگه می‌دارد؛ null صریح 422 می‌گیرد؛ رشته یا عضو ناشناخته 400 می‌گیرد. مقدار معتبر، مقدار مطلق را تعیین می‌کند و تعیین دوبارهٔ مقدار فعلی بی‌اثر است. معنای ایجاد و replay در POST را کپی نکنید.

عملیات تازه، سرویس فقط‌خواندنی موجودی را بررسی می‌کند که داده‌اش توسط worker تازه‌سازی پس‌زمینه نگهداری می‌شود. برای تغییر، پیش از نوشتن محلی probe انجام دهید. بودجهٔ طراحی ۱۰۰ میلی‌ثانیه است؛ timeout تزریق‌شده 503 با صفر نوشتن محلی می‌دهد و خرابی غیرمنتظره 500 با صفر نوشتن می‌دهد. حذف فیلد و تعیین مقدار یکسان، probe ندارند. مدل پایتون این نتیجه‌ها را تزریق می‌کند؛ deadline واقعی ۱۰۰ میلی‌ثانیه را اندازه‌گیری یا اعمال نمی‌کند و worker را اجرا نمی‌کند. deadline، cancellation و رفتار سرویس واقعی تأییدنشده می‌مانند.

هر ۱۲ حالت افزودهٔ PATCH را به کار ببرید: مقدار تازه، حذف فیلد، null، timeout، سفارش مفقود، بدون هویت، بدون مجوز، بازهٔ نامعتبر، media type نادرست، نوع نادرست، خرابی غیرمنتظره و مقدار یکسان. هدف کامل، ۱۹ حالت baseline را هم نگه می‌دارد. پیامد هر مشاهدهٔ مفقود یا قدیمی را توضیح دهید، همهٔ سندها، captureها و بازبینی‌های نیازمند تازه‌سازی را تعیین کنید و کوچک‌ترین تعمیر را پیشنهاد دهید. پاسخ درست باید fixture معیوب فعلی را از شاهد لازم پس از تعمیر تفکیک کند. حکم پرشدهٔ انتقال ارائه نشده است.

برای آزمایش اختیاری مدل، metadata را کپی و profile هدف را پیاده کنید، OpenAPI آن را دوباره بسازید و درخواست‌های تازه را اجرا کنید. انتظارها را مطابق رفتار خراب بازنویسی نکنید. یک کار پس‌زمینهٔ واقعاً تغییردهنده، قرارداد صریح پذیرش/وضعیت، outbox یا سازگاری دیگری می‌خواهد؛ probe فقط‌خواندنی اینجا آن تصمیم را حل نمی‌کند.

NET-002-F3 — بررسی انتقال. چرا timeout حالت تازهٔ خطا و اثر می‌خواهد؟ توضیح دهید چرا برگرداندن 201 از قرارداد کپی‌شدهٔ POST، به‌روزرسانی جزئی را برقرار نمی‌کند. اگر revision قدیمی را بدون ساخت دوبارهٔ شواهد استفاده می‌کنید، به profile هدف برگردید.

آنچه واقعاً ثابت شده را نگه دارید

پاسخ شامل هویت fixture و زمینه، fixture_sha256، policy_sha256، contracts_sha256، تاریخ ارزیابی، محدوده، readiness state، مسئله‌های نوع‌دار با pointer، استدلال، کمینهٔ تعمیر و محرک بازبینی است. نحو pointer همان JSON Pointer است؛ index آرایه را از فایل واقعی بردارید و در نام عضو، ~ را با ~0 و / را با ~1 بنویسید. pointer شاهد را مشخص می‌کند، نه مقدار جایگزین اختراعی را.

contracts.json درخواست و نتیجهٔ مورد انتظار را می‌دهد. مدل مشاهده تولید می‌کند. fixture مشاهده‌های منتخب و تغییرهای عمدی را نگه می‌دارد. checker عمومی ساختار و اتصال را بررسی می‌کند؛ ارزیابی معنایی مدرس، قواعد قابل‌مشاهده و مجموعهٔ کامل علت‌ها را مقایسه می‌کند. یک انسان باید بدون دسترسی به استدلال پنهان بتواند توضیح شما را بازتولید کند. این چهار کار را یکی ندانید.

شاهد صفر نوشتن و ردیف نهایی را کنار حالت‌های احراز هویت، validation، replay و timeout نگه دارید. برچسب PASS بدون این شاهد کافی نیست. تنظیمات و میزبان واقعی را هم ثبت کنید: مدل پایتون، میزبان تست ASP.NET و سرویس مستقر سه محدودهٔ متفاوت‌اند. اجرای واقعی چارچوب با وضعیت UNVERIFIED حتی پس از پذیرش تمرین مصنوعی قابل‌مشاهده می‌ماند.

هوش مصنوعی می‌تواند رکوردهای داده‌شده را مرتب کند، digest حساب کند و پرسش بنویسد؛ حق ندارد اجرا، اختیار اعتبارنامه، capture روز، اجازهٔ مالک یا تأیید استقرار اختراع کند. تغییر پیاده‌سازی، schema، سیاست، مرز وابستگی، نسخهٔ چارچوب یا انقضای بازبینی، ارزیابی متصل به زمینهٔ تازه می‌خواهد.

از ماتریس دفاع کنید

NET-002-S1 — بازیابی. مرز API متعلق به این درس را توضیح دهید، مستند را از اعمال تعهد جدا کنید و یک خروجی مجاور نام ببرید. وضعیتی را مشخص کنید که بدون شاهد اجرا باید حل‌نشده بماند.

NET-002-S2 — کاربرد. ماتریس کامل baseline را بسازید و نتیجهٔ محدودش را توجیه کنید. چرا رد POST بدون هویت آزمون منفی موفق است و چرا اعتبارسنجی اعتبارنامهٔ واقعی را ثابت نمی‌کند؟

NET-002-S3 — تشخیص. حذف مجوز POST با باقی‌ماندن مسیر OpenAPI را تشخیص دهید. هر بُعد نامعتبر، پیامد کلاینت/داده، کوچک‌ترین تعمیر و شاهد تازهٔ لازم را تعیین کنید. چرا عوض‌کردن هش، اجرای مفقود را ایجاد نمی‌کند؟

NET-002-S4 — انتقال. تصمیم transfer_patch را از شواهد خودش بازسازی کنید. تفاوت حذف فیلد و null، media/schema و وضعیت موفق، اثر timeout و خرابی وابستگی فقط‌خواندنی و همهٔ مشاهده‌های وابسته به revision و نیازمند تجدید را توضیح دهید. نتیجهٔ baseline را کپی نکنید.

هر پنج بُعد rubric باید کافی باشند: هویت/قرارداد، اتصال دقیق شواهد، شاهد منفی، تصمیم محدود و انتقال. حکم کلی درست با علت‌های ناقص در بُعد مربوط مردود است؛ فهرست کامل کدها بدون توضیح علت و پیامد هم کافی نیست. خطای مرز را با مدل ذهنی، خطای پاسخ را با توضیح فنی و انتقال کپی‌شده را با ماتریس تازه ترمیم کنید.

منابع و تازگی

ده منبع اولیه در 2026-09-12 بررسی شدند. موعد بازبینی 2026-10-18 است یا زودتر، اگر چارچوب، schema یا امنیت تغییر مرتبطی کند. sources.json و source_links.md در بستهٔ تمرین، لینک و مرز ادعای منابع را نگه می‌دارند. مستندات به ASP.NET Core 10 مقیدند؛ پیش‌فرض نسخهٔ جدیدتر را بی‌اعلان جایگزین نکنید.

FACT رفتار مستند پلتفرم یا پروتکل است. INFERENCE نتیجهٔ مجاز از مشاهده‌های داده‌شده است. DESIGN سیاست وضعیت، ساختار سخت‌گیرانه، قواعد replay، فهرست امن بدنه، نام وضعیت‌ها و بودجهٔ ۱۰۰ میلی‌ثانیه در تمرین است. قاعدهٔ پذیرش محدود، DESIGN است و گواهی مایکروسافت یا IETF نیست. مستند بیرونی مدرک اجرای مفقود نمی‌سازد. تغییرهای بازبینی‌شده را در نسخهٔ تازه منتشر کنید و ورودی، منبع و مشاهدهٔ تاریخ‌دار این نسخه را نگه دارید.

ارزیابی

پاسخ‌نامه‌ی این درس در بسته‌ی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار می‌فرستد.

ملاک‌های ارزیابی (rubric)

هر پنج بُعد باید کافی باشند. Every critical dimension must be sufficient; averaging cannot erase a failure.

بُعد / Dimensionکافی / Sufficientناکافی / Insufficient
هویت و قرارداد / Identity and contractمرز HTTP، مستند و اجرا جداست / Distinguishes contract, document and executionمسیر مستند را مجوز اعمال‌شده می‌داند / Treats path metadata as enforcement
اتصال / Bindingfixture، policy، contracts، منبع مدل، زمان و زمینه دقیق / Exact input, policy, full contracts, source, date and contextهش را جای مشاهده می‌گذارد / Substitutes hash editing for a run
منفی / Negative evidenceپاسخ و اثر با همهٔ علت‌های نوع‌دار / Responses and effects with complete typed causesفقط status یا PASS / Status or PASS label only
تصمیم / Decisionحکم محدود، تعمیر حداقلی، محرک بازبینی / Bounded state, minimal repair, review triggerادعای اجرای چارچوب یا تولید بدون شاهد / Unsupported framework or production claim
انتقال / TransferPATCH، omission/null، رسانه، timeout و اثر تازه / Rebuilds PATCH, omission/null, media, timeout and effectsرفتار POST کپی شده / Copies POST behavior

کد درست بدون استدلال کافی نیست. A correct code list without causal reasoning is insufficient. Python execution is not ASP.NET execution; an injected timeout does not establish measured deadline enforcement.

منابع و تازگی

· TOOL_VOLATILE
Microsoft ASP.NET Core 10 Minimal APIs reference for routing, binding, responses, filters, authorization and related API mechanics.
· TOOL_VOLATILE
Microsoft documentation for built-in OpenAPI generation in ASP.NET Core, including .NET 10 OpenAPI 3.1 support.
· TOOL_VOLATILE
Microsoft guidance for API exception handling and Problem Details behavior in ASP.NET Core.
·
Identity, policies and middleware
·
WebApplicationFactory and disposable test host
·
Controller conventions and default 400
·
Minimal API validation in .NET 10
·
Problem Details fields and extensions, not exercise whitelist
·
HTTP status and idempotent method semantics
·
OpenAPI document syntax, not runtime verification

مطالعهٔ موارد (case studies)

فایل‌های آزمایشگاه

نیاز: Python 3.10+ با کتابخانهٔ استاندارد. فرمان‌ها را در همین پوشه اجرا کنید.

python pipeline_demo.py
python generate_openapi.py implementation.baseline.json openapi.rebuilt.json
python run_checks.py --inventory
python run_checks.py --template fixtures/error_as_200.json submission.json --as-of 2026-09-12
python run_checks.py --check fixtures/error_as_200.json submission.json

میان دو فرمان آخر، تصمیم، همهٔ مسئله‌های نوع‌دار، pointer، استدلال، تعمیر و محرک بازبینی را تکمیل کنید. STRUCTURE_PASS_SEMANTICS_UNREVIEWED فقط شکل و اتصال را تأیید می‌کند. فایل خروجی موجود بازنویسی نمی‌شود؛ برای تکرار نام تازه انتخاب کنید.

policy.json قواعد را می‌دهد و contracts.json درخواست و انتظار قابل‌مشاهده را. جدول کامل، نگاشت فیلد، منابع و ارزیابی در resources هستند. baseline و authorization_removed حل‌شده، error_as_200 هدایت‌شده و transfer_patch مستقل‌اند. باقی تغییرها تمرین تشخیص‌اند. حکم نهایی انتقال را خودتان بسازید؛ ورودی‌ها را حفظ کنید.

pipeline_demo واقعاً مدل پایتون را اجرا می‌کند؛ نه ASP.NET، نه پورت HTTP و نه اعتبارسنجی توکن واقعی. با --fixture و --case نام فایل و حالت هدف را انتخاب کنید. metadata غلط واقعاً رفتار مدل را تغییر می‌دهد. capture قدیمیِ fixture را با اجرای تازه یکی ندانید. Timeout تزریق‌شده، اندازه‌گیری deadline واقعی ۱۰۰ میلی‌ثانیه نیست؛ سرویس پس‌زمینه اجرا نشده است. aspnetcore_reference.cs قطعه‌های پروژه‌ای جداست، نه پروژهٔ قابل build. تاریخ نمونه تاریخی است؛ برای ادعای روز، تاریخ واقعی و وضعیت منقضی را حفظ کنید.