System.ComponentModel.DataAnnotations استوار است، ساختاری کاملاً همگام (Synchronous) داشت. ⚙️این طراحی سنتی، پیادهسازی قواعد اعتبارسنجی پیچیدهای را که به عملیاتهای ورودی/خروجی (I/O-bound) وابسته بودند با چالش مواجه میکرد؛ سناریوهایی مانند:
✅ بررسی منحصربهفرد بودن نام کاربری در پایگاه داده
✅ استعلام وضعیت یک شناسه از طریق Web API خارجی
✅ سنجش موجودی انبار
توسعهدهندگان برای پیادهسازی این زیرساختها ناچار بودند یا به ابزارهای شخص ثالث مانند کتابخانه محبوب FluentValidation روی آورند، یا متدهای ناهمگام را به صورت ناامن و مسدودکننده (Thread Blocking) با استفاده از امضاهایی مانند
.Result یا .Wait() فراخوانی کنند. ⚠️این رویکرد نامناسب، مستقیماً ریسک بروز گلوگاه در پایگاه ریسمانها (Thread Pool Starvation) را افزایش میداد. 📉
در پی درخواستهای مکرر جامعه توسعهدهندگان، مایکروسافت بالاخره در NET 11 Preview 6. زیرساخت اعتبارسنجی ناهمگام را به صورت بومی به هسته فریمورک اضافه کرد تا به یکی از پررأیترین درخواستهای گیتهاب پاسخ دهد. 🎉
🆕 معماری و قابلیتهای جدید در NET 11.
این تغییرات زیرساختی، معماری اعتبارسنجی داتنت را متحول کرده است. 🔥
در این مکانیزم جدید، سه افزونه اساسی به فضای نام
System.ComponentModel.DataAnnotationsاضافه شده است که به توسعهدهندگان اجازه میدهد منطق ناهمگام خود را بدون مسدود کردن ریسمانها پیادهسازی کنند:
🟢 کلاس انتزاعی
AsyncValidationAttributeاین کلاس پایه جدید، جایگزین مستقیم
ValidationAttribute برای سناریوهای ناهمگام است و امکان نوشتن اتریبیوتهای سفارشی را با بازنویسی (Override) متد IsValidAsync فراهم میکند.🟢 اینترفیس
IAsyncValidatableObjectهمتای ناهمگام اینترفیس شناختهشدهی
IValidatableObject که به خودِ مدل یا DTO اجازه میدهد منطق اعتبارسنجی درونیاش را به صورت اسنک (Async) پیادهسازی کند.🟢 متدهای نوین در کلاس static اعتبارسنجی (
Validator)معرفی متدهای جدید از جمله:
✅
ValidateObjectAsync✅
TryValidateObjectAsync✅
ValidatePropertyAsync✅
ValidateValueAsyncجهت اجرای غیرمسدودکننده عملیات سنجش صحت دادهها. 🚀
🧩 پیادهسازی عملی اتریبیوت اعتبارسنجی ناهمگام
در نمونه کد زیر، شیوه تعریف یک قانون اعتبارسنجی ناهمگام جهت بررسی منحصربهفرد بودن نام کاربری به سادهترین شکل ممکن ارائه شده است. ✨
متد سنتی IsValid به صورت پیشفرض برای سازگاری عقبرو (Backward Compatibility) مقدار ValidationResult.Success را برمیگرداند و منطق اصلی در IsValidAsync به همراه پشتیبانی از CancellationToken پیادهسازی میشود.
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.DependencyInjection;
public sealed class UniqueUserNameAttribute : AsyncValidationAttribute
{
// سازگاری با خط لولههای همگام قدیمی
protected override ValidationResult? IsValid(object? value, ValidationContext context)
=> ValidationResult.Success;
// پیادهسازی اصلی برای خط لوله ناهمگام داتنت ۱۱
protected override async Task<ValidationResult?> IsValidAsync(
object? value, ValidationContext context, CancellationToken cancellationToken)
{
// دریافت مستقیم سرویسها از کانتینر DI با استفاده از Context موجود
var users = context.GetRequiredService<IUserStore>();
bool isTaken = await users.ExistsAsync((string?)value, cancellationToken);
return isTaken
? new ValidationResult("این نام کاربری قبلاً توسط کاربر دیگری انتخاب شده است.")
: ValidationResult.Success;
}
}
public class RegistrationRequest
{
[Required]
[UniqueUserName]
public string UserName { get; set; } = "";
}
🚀 اجرای اعتبارسنجی ناهمگام
جهت فراخوانی و اعتبارسنجی ناهمگام این مدل در خط لولههای دستی یا خارج از لایه کنترلر، موتور Validator متدهای الحاقی جدید خود را ارائه میدهد.
// اجرای فرآیند اعتبارسنجی ناهمگام بدون Block کردن Thread
var context = new ValidationContext(model, serviceProvider, items: null);
await Validator.ValidateObjectAsync(
model,
context,
validateAllProperties: true);