اگر با Asp.Net MVC کار کرده باشید به احتمال زیاد این کلمه برای شما آشناست. زمانی که یک ریکوئست به برنامه‌های Asp.Net MVC ارسال می‌شود، اطلاعات مربوط به ریکوئست مانند Uri,Headers, RemoteAddress و ... درون HttpContext.Current قرار دارند. اطلاعات HttpContext.Current بر روی thread جاری قرار دارد و زمانی که یک متد async را به صورت ConfigureAwait(false) فراخوانی می‌کنید احتمال اینکه thread دیگری ادامه‌ی کارها را انجام دهد بسیاز زیاد است و اکثرا به همین صورت می‌باشد و اگر thread عوض شود اطلاعات مربوط به HttpContext.Current از بین می‌رود چونکه thread عوض شده است. برای این کار در جاهایی که شما به اطلاعات HttpContext.Current نیاز دارید باید از ConfigureAwait(true) استفاده کنید. برای مثال در اکشن زیر ابتدا اطلاعات ریکوئست را دریافت میکنیم و سپس یک متد async را به صورت ConfigureAwait(false) فراخوانی می‌کنیم و سپس مجدد اطلاعات ریکوئست را از HttpContext دریافت می‌کنیم.

public class ValuesController : ApiController
{
    public async Task<IHttpActionResult> Get()
    {
        var beforeConfigureAwaitFalse = HttpContext.Current.Request.Url.AbsoluteUri;

        await DoSomething().ConfigureAwait(false);

        var afterConfigureAwaitFalse = HttpContext.Current?.Request?.Url?.AbsoluteUri ?? "null";

        return Json(new
        {
            beforeConfigureAwaitFalse,
            afterConfigureAwaitFalse
        });
    }

    private async Task DoSomething()
    {
        await Task.Delay(1000);
    }
}

اگر برنامه را اجرا کنید به اکشن موردنظر را فراخوانی کنید، اکثرا مقدارمتغییر afterConfigureAwaitFalse برابر null خواهد بود زیرا زمانی که از ConfigureAwait(false) استفاده می‌کنیم اطلاعات HttpContext جاری Capture نمی‌شود و thread بعدی که ادامه‌ی کار را انجام می‌دهد فاقد اطلاعات HttpContext می‎‌باشد و خروجی زیر را دریافت می‌کنید:

{
  "beforeConfigureAwaitFalse": "https://localhost:44338/api/values",
  "afterConfigureAwaitFalse": "null"
}

اما اگر مقدار ConfigureAwait(false) را به ConfigureAwait(true) تغییر دهید، اطلاعات مربوط به HttpContext جاری Capture می‌شود و توسط SynchronizationContext به thread جدید که ادامه‌ی کار را انجام می‌دهد تعلق می‌گیرد.
اکنون اگر کد زیر را اجرا نمایید:

public async Task<IHttpActionResult> Get()
{
    var beforeConfigureAwaitFalse = HttpContext.Current.Request.Url.AbsoluteUri;

    await DoSomething().ConfigureAwait(true);

    var afterConfigureAwaitFalse = HttpContext.Current?.Request?.Url?.AbsoluteUri ?? "null";

    return Json(new
    {
        beforeConfigureAwaitFalse,
        afterConfigureAwaitFalse
    });
}

همیشه خروجی زیر را دریافت خواهید کرد:

{
  "beforeConfigureAwaitFalse": "https://localhost:44338/api/values",
  "afterConfigureAwaitFalse": "https://localhost:44338/api/values"
}

نکته: به صورت پیشفرض اگر متد ConfigureAwait را فراخوانی نکنید، HttpContext جاری Capture می‌شود.

;)

Powered by Froala Editor

نظرات

سایر نظرات
  • مجید سلیمانی نژاد

    چقدر خوب و ساده توضیح دادید ممنون از شما ، توی سایت های دیگه خیلی موضوع رو پیچونده بودند و خب جمله ای هست که میگه اگه نتونی چیزی رو ساده توضیح بدهی قطعا خودتم اونو متوجه نشدی

    ارسال شده در تاریخ یکشنبه، ۱۴ اسفند ۱۴۰۱
    • admin

      خواهش میکنم مجید جان

      ارسال شده در تاریخ چهارشنبه، ۱۷ اسفند ۱۴۰۱