Runtime: يقوم HttpClient بإلقاء TaskCanceledException عند انتهاء المهلة

تم إنشاؤها على ٢٥ مايو ٢٠١٧  ·  119تعليقات  ·  مصدر: dotnet/runtime

يقوم HttpClient بإلقاء TaskCanceledException عند انتهاء المهلة في بعض الظروف. يحدث هذا لنا عندما يكون الخادم تحت عبء ثقيل. تمكنا من حل المشكلة عن طريق زيادة المهلة الافتراضية. يلتقط مؤشر ترابط منتدى MSDN التالي جوهر المشكلة ذات الخبرة: https://social.msdn.microsoft.com/Forums/en-US/d8d87789-0ac9-4294-84a0-91c9fa27e353/bug-in-httpclientgetasync-should-throw -webexception-not-taskcanceledexception؟ forum = netfxnetcom & prof = required

شكرا

area-System.Net.Http enhancement

التعليق الأكثر فائدة

Karelz يضيف ملاحظة كعميل آخر متأثر بهذا الاستثناء المضلل :)

ال 119 كومينتر

awithy ما هو إصدار .NET Core الذي تستخدمه؟

1.1

سواء كان التصميم الصحيح أم لا ، يتم طرح استثناءات OperationCanceledException بسبب المهلات (و TaskCanceledException هو عملية OperationCanceledException).
cc:davidsh

وجد فريقنا هذا غير بديهي ، لكن يبدو أنه يعمل وفقًا لما هو مُصمم. لسوء الحظ ، عندما وصلنا إلى هذا ، أهدرنا بعض الوقت في محاولة العثور على مصدر للإلغاء. إن الاضطرار إلى التعامل مع هذا السيناريو بشكل مختلف عن إلغاء المهمة أمر قبيح جدًا (أنشأنا معالجًا مخصصًا لإدارة هذا). يبدو أن هذا أيضًا عبارة عن استخدام مفرط للإلغاء كمفهوم.

شكرا مرة أخرى لاستجابتك السريعة.

يبدو أنه حسب التصميم + لم يكن هناك سوى 2 من العملاء شكوى في آخر 6 أشهر أو أكثر.
إغلاق.

Karelz يضيف ملاحظة كعميل آخر متأثر بهذا الاستثناء المضلل :)

شكرًا على المعلومات ، يرجى التصويت أيضًا على أعلى مشاركة (يمكن فرز المشكلات وفقًا لها) ، شكرًا!

سواء كان التصميم الصحيح أم لا ، حسب التصميم ، يتم طرح استثناءات عملية إلغاء الحظر للمهلة

هذا هو تصميم سيء IMO. لا توجد طريقة لمعرفة ما إذا كان الطلب قد تم إلغاؤه بالفعل (على سبيل المثال ، تم إلغاء رمز الإلغاء الذي تم تمريره إلى SendAsync ) أو ما إذا كانت المهلة قد انقضت. في الحالة الأخيرة ، سيكون من المنطقي إعادة المحاولة ، بينما في الحالة الأولى لن تكون كذلك. هناك TimeoutException سيكون مثاليًا لهذه الحالة ، فلماذا لا تستخدمه؟

نعم ، ألقى هذا أيضًا بفريقنا في حلقة. هناك سلسلة Stack Overflow كاملة مخصصة لمحاولة التعامل معها: https://stackoverflow.com/questions/10547895/how-can-i-tell-when-httpclient-has-timed-out/32230327#32230327

لقد نشرت حلًا بديلًا منذ بضعة أيام: https://www.thomaslevesque.com/2018/02/25/better-timeout-handling-with-httpclient/

رائع شكرا.

إعادة الفتح نظرًا لأن الاهتمام أصبح أكبر الآن - أصبح مؤشر ترابط StackOverflow الآن 69 صوتًا مؤيّدًا.

cc @ dotnet / ncl

أي أخبار ؟ لا يزال يحدث في dotnet core 2.0

إنه مدرج في قائمتنا لأهم المشاكل لما بعد 2.1. لن يتم إصلاحه في 2.0 / 2.1 بالرغم من ذلك.

لدينا العديد من الخيارات التي يجب القيام بها عند حدوث المهلة:

  1. ضع TimeoutException بدلاً من TaskCanceledException .

    • المؤيد: من السهل التمييز بين المهلة وإجراء الإلغاء الصريح في وقت التشغيل

    • Con: تغيير الأعطال الفنية - تم طرح نوع جديد من الاستثناءات.

  2. قم برمي TaskCanceledException مع استثناء داخلي كـ TimeoutException

    • المؤيد: من الممكن التمييز بين المهلة وإجراء الإلغاء الصريح في وقت التشغيل. نوع الاستثناء المتوافق.

    • السؤال المفتوح: هل من المقبول التخلص من مكدس TaskCanceledException الأصلي ورمي مكدس جديد ، مع الحفاظ على InnerException (مثل TimeoutException.InnerException )؟ أم يجب علينا الحفاظ على TaskCanceledException الأصلي ولفّه؟



      • إما: TaskCanceledException الجديدة -> TimeoutException الجديد -> TaskCanceledException الأصلي (مع InnerException الأصلي الذي قد يكون فارغًا)


      • أو: TaskCanceledException الجديد -> TimeoutException الجديد -> TaskCanceledException الأصلية. InnerException (قد يكون فارغًا)



  3. قم برمي TaskCanceledException برسالة تشير إلى انتهاء المهلة كسبب

    • الإيجابيات: من الممكن التمييز بين المهلة وإجراء الإلغاء الصريح للرسالة / السجلات

    • Con: لا يمكن تمييزه في وقت التشغيل ، فهو "تصحيح الأخطاء فقط".

    • السؤال المفتوح: كما في [2] - هل يجب علينا التفاف أو استبدال TaskCanceledException الأصلية (وتكدس)

أميل إلى الخيار [2] ، مع تجاهل الحزمة الأصلية من TaskCanceledException الأصلي.
stephentoubdavidsh أي أفكار؟

راجع للشغل: يجب أن يكون التغيير واضحًا إلى حد ما في HttpClient.SendAsync حيث قمنا بإعداد المهلة:
https://github.com/dotnet/corefx/blob/30fb78875148665b98748ede3013641734d9bf5c/src/System.Net.Http/src/System/Net/Http/HttpClient.cs#L433 -L461

يجب أن يكون استثناء المستوى الأعلى دائمًا HttpRequestException. هذا هو نموذج API القياسي لـ HttpClient.

ضمن ذلك ، كاستثناء داخلي ، من المحتمل أن تكون "المهلات" استثناءات TimeoutException. في الواقع ، إذا قمنا بدمج هذا مع المشكلات الأخرى (حول تعديل HttpRequestion لتضمين خاصية تعداد جديدة مشابهة لـ WebExceptionStatus) ، فسيتعين على المطورين فقط التحقق من هذا التعداد وليس عليهم فحص الاستثناءات الداخلية على الإطلاق.

هذا هو الخيار الأول بشكل أساسي) ولكن مع الاستمرار في الحفاظ على نموذج واجهة برمجة التطبيقات المتوافق مع التطبيق الحالي ، فإن استثناءات المستوى الأعلى من واجهات برمجة تطبيقات HttpClient هي دائمًا HttpRequestException.

ملاحظة: أي "مهلات" من قراءة تدفق استجابة HTTP مباشرة من Stream APIs مثل:

ج #
var client = new HttpClient () ؛
Stream responseStream = انتظار client.GetStreamAsync (url) ؛

int bytesRead = انتظار الاستجابةStream.ReadAsync (المخزن المؤقت ، 0 ، buffer.Length) ؛
""

يجب أن تستمر في طرح System.IO.IOException وما إلى ذلك كاستثناءات من المستوى الأعلى (لدينا في الواقع بعض الأخطاء في SocketsHttpHandler حول هذا الأمر).

davidsh هل تقترح طرح HttpRequestException حتى في الحالات التي يكون فيها إلغاء المستخدم صريحًا؟ هؤلاء يرمون TaskCanceledException اليوم ويبدو الأمر جيدًا. لست متأكدًا مما إذا كان شيئًا نريد تغييره ...
سأكون على ما يرام لفضح المهلات من جانب العميل كـ HttpRequestException بدلاً من TaskCanceledException .

davidsh هل تقترح طرح HttpRequestException حتى في الحالات التي يكون فيها إلغاء المستخدم واضحًا؟ هؤلاء يرمون TaskCanceledException اليوم ويبدو أنه جيد. لست متأكدًا مما إذا كان هذا شيئًا نريد تغييره ...

أحتاج إلى اختبار السلوكيات المختلفة للمكدسات بما في ذلك .NET Framework للتحقق من السلوكيات الحالية بالضبط قبل أن أتمكن من الإجابة على هذا السؤال.

أيضًا ، في بعض الحالات ، تقوم بعض مكدساتنا بإلقاء HttpRequestException مع استثناء داخلي لـ OperationCanceledException. TaskCanceledException هو نوع مشتق من OperationCanceledException.

عندما يكون هناك إلغاء صريح للمستخدم

نحتاج أيضًا إلى تعريف واضح لماهية "الصريح". على سبيل المثال ، هل تعيين الخاصية HttpClient.Timeout "صريح"؟ أعتقد أننا نقول لا. ماذا عن استدعاء .Cancel () في كائن CancellationTokenSource (والذي يؤثر على الكائن الذي تم تمريره في كائن CancellationToken)؟ هل هذا "صريح"؟ ربما توجد أمثلة أخرى يمكننا التفكير فيها.

يطرح .NET Framework أيضًا TaskCanceledException عند تعيين HttpClient.Timeout .

إذا كنت لا تستطيع التمييز بين الإلغاء من العميل والإلغاء من التنفيذ - فقط تحقق من كليهما. قبل استخدام رمز العميل ، قم بإنشاء رمز مشتق:
ج #
var clientToken = ....
var innerTokenSource = CancellationTokenSource.CreateLinkedTokenSource (clientToken) ،

If at some point you catch **OperationCancelledException**:
```c#
try
{
     //invocation with innerToken
}
catch(OperationCancelledException oce)
{
      if(clientToken.IsCancellationRequested)
          throw; //as is, it is client initiated and in higher priority
      if(innerToken.IsCancellationRequested)
           //wrap it in HttpException, TimeoutException, whatever, wrap it in another linked token until you process all cases.
}

تقوم بشكل أساسي بتصفية جميع الطبقات الممكنة من رمز العميل إلى الرمز الأعمق ، حتى تجد الرمز الذي تسبب في الإلغاء.

أي تحديثات على هذا جعل 2.2 أو 3.0؟ @ karelzdavidsh ، cc NickCraver . أتمنى أن يفعل الخيار 1) لإلقاء TimeoutException ، أو بدلاً من ذلك HttpTimeoutException جديدًا مشتقًا من HttpRequestException. شكرا!

أي تحديثات على هذا جعل 2.2 أو 3.0؟

متأخر جدًا بالنسبة لـ 2.2 ، تم إصداره الأسبوع الماضي ؛)

متأخر جدًا بالنسبة لـ 2.2 ، تم إصداره الأسبوع الماضي ؛)

أرغ ، هذا ما يحدث عندما آخذ استراحة ؛)

على الرغم من كونه أحمقًا بعض الشيء ، فإن الحل الأكثر بساطة الذي وجدته هو تداخل معالج التقاط لـ OperationCanceledException ثم تقييم قيمة IsCancellationRequested لتحديد ما إذا كان رمز الإلغاء ناتجًا عن انقضاء المهلة أو إجهاض جلسة فعلية. من الواضح أن المنطق الذي يؤدي استدعاء واجهة برمجة التطبيقات من المحتمل أن يكون في منطق الأعمال أو طبقة الخدمة ولكني قمت بدمج المثال من أجل البساطة:

شارب
[HttpGet]
مهمة عامة غير متزامنةالفهرس (الإلغاء ، الإلغاء المنطوق)
{
يحاول
{
// يتم ذلك عادةً في منطق عمل أو طبقة خدمة بدلاً من وحدة التحكم نفسها ولكني أوضح النقطة هنا من أجل البساطة
يحاول
{
// استخدام HttpClientFactory لمثيلات HttpClient
var httpClient = _httpClientFactory.CreateClient () ،

        //Set an absurd timeout to illustrate the point
        httpClient.Timeout = new TimeSpan(0, 0, 0, 0, 1);

        //Perform call that requires special timeout logic                
        var httpResponse = await httpClient.GetAsync("https://someurl.com/api/long/running");

        //... (if GetAsync doesn't fail, handle the response as desired)
    }
    catch (OperationCanceledException innerOperationCanceled)
    {
        //If a canceled token exception occurs due to a timeout, "IsCancellationRequested" should be false
        if (cancellationToken.IsCancellationRequested)
        {
            //Bubble exception to global handler
            throw innerOperationCanceled;
        }
        else
        {
            //... (perform timeout logic here)
        }                    
    }                

}
catch (OperationCanceledException operationCanceledEx)
{
    _logger.LogWarning(operationCanceledEx, "Request was aborted by the end user.");
    return new StatusCodeResult(499);
}
catch (Exception ex)
{
    _logger.LogError(ex, "An unexepcted error occured.");
    return new StatusCodeResult(500);
}

}
""

لقد رأيت مقالات أخرى حول كيفية التعامل مع هذا السيناريو بشكل أكثر أناقة ولكنها تتطلب جميعًا الحفر في خط الأنابيب وما إلى ذلك. أدرك أن هذا النهج ليس مثاليًا كما آمل في أنه سيكون هناك دعم أفضل لاستثناءات المهلة الفعلية مع المستقبل إطلاق سراح.

العمل مع عميل http سيئ للغاية. تم حذف احتياجات HttpClient وبدأت من جديد.

على الرغم من كونه أحمقًا بعض الشيء ، فإن الحل الأكثر بساطة الذي وجدته هو تداخل معالج التقاط لـ OperationCanceledException ثم تقييم قيمة IsCancellationRequested لتحديد ما إذا كان رمز الإلغاء ناتجًا عن انقضاء المهلة أو إجهاض جلسة فعلية. من الواضح أن المنطق الذي يؤدي استدعاء واجهة برمجة التطبيقات من المحتمل أن يكون في منطق الأعمال أو طبقة الخدمة ولكني قمت بدمج المثال من أجل البساطة:

[HttpGet]
public async Task<IActionResult> Index(CancellationToken cancellationToken)
{
  try
  {
      //This would normally be done in a business logic or service layer rather than in the controller itself but I'm illustrating the point here for simplicity sake
      try
      {
          //Using HttpClientFactory for HttpClient instances      
          var httpClient = _httpClientFactory.CreateClient();

          //Set an absurd timeout to illustrate the point
          httpClient.Timeout = new TimeSpan(0, 0, 0, 0, 1);

          //Perform call that requires special timeout logic                
          var httpResponse = await httpClient.GetAsync("https://someurl.com/api/long/running");

          //... (if GetAsync doesn't fail, handle the response as desired)
      }
      catch (OperationCanceledException innerOperationCanceled)
      {
          //If a canceled token exception occurs due to a timeout, "IsCancellationRequested" should be false
          if (cancellationToken.IsCancellationRequested)
          {
              //Bubble exception to global handler
              throw innerOperationCanceled;
          }
          else
          {
              //... (perform timeout logic here)
          }                    
      }                

  }
  catch (OperationCanceledException operationCanceledEx)
  {
      _logger.LogWarning(operationCanceledEx, "Request was aborted by the end user.");
      return new StatusCodeResult(499);
  }
  catch (Exception ex)
  {
      _logger.LogError(ex, "An unexepcted error occured.");
      return new StatusCodeResult(500);
  }
}

لقد رأيت مقالات أخرى حول كيفية التعامل مع هذا السيناريو بشكل أكثر أناقة ولكنها تتطلب جميعًا الحفر في خط الأنابيب وما إلى ذلك. أدرك أن هذا النهج ليس مثاليًا كما آمل في أنه سيكون هناك دعم أفضل لاستثناءات المهلة الفعلية مع المستقبل إطلاق سراح.

من الجنون تمامًا أننا نحتاج إلى كتابة هذا الرمز الفظيع. HttpClient هو أكثر تجريد تم إنشاؤه بواسطة Microsoft على الإطلاق

أوافق على أنه يبدو قصير النظر إلى حد ما لعدم تضمين معلومات استثناء أكثر تحديدًا حول المهلات. يبدو أنه أمر أساسي جدًا للأشخاص الذين يرغبون في التعامل مع المهلات الفعلية بشكل مختلف عن استثناءات الرمز المميز الملغاة.

العمل مع عميل http سيئ للغاية. تم حذف احتياجات HttpClient وبدأت من جديد.

هذه ليست ملاحظات مفيدة أو بناءة للغاية dotnetchris . العملاء وموظفو MSFT على حدٍ سواء هنا لمحاولة تحسين الأمور ، ولهذا السبب لا يزال أشخاص مثل karelz يستمعون إلى ملاحظات العملاء ويحاولون التحسين. لا يوجد أي مطلب بالنسبة لهم للقيام بالتنمية في العراء ، ودعنا لا نحرق نواياهم الطيبة بالسلبية أو يمكنهم أن يقرروا أخذ الكرة والعودة إلى المنزل ، وسيكون ذلك أسوأ بالنسبة للمجتمع. شكرا! :)

لماذا ليس مجرد إنشاء HttpClient2 (اسم مؤقت) له السلوك المتوقع وإبلاغه ، في الوثائق ، أن "HttpClient قديم ، يرجى استخدام HttpClient2" وشرح الفرق بين الاثنين.

بهذه الطرق لا يتم إدخال تغيير فاصل في .NetFramework.

لا ينبغي أن يقوم HttpClient على أساس طرح الاستثناءات. ليس من الاستثنائي عدم توفر مضيف الإنترنت. إنه متوقع بالفعل ، بالنظر إلى التباديل اللانهائي للعناوين ، فإن الحالة الاستثنائية تمنحها شيئًا يعمل.

حتى أنني قمت بالتدوين حول مدى سوء استخدام HttpClient منذ أكثر من 3 سنوات. https://dotnetchris.wordpress.com/2015/12/11/working-with-httpclient-is-absurd/

هذا تصميم سيء بشكل صارخ.

هل قام أي شخص في Microsoft باستخدام HttpClient؟ من المؤكد أنه لا يبدو كذلك.

ثم بعد هذا السطح الرهيب لواجهة برمجة التطبيقات ، هناك كل أنواع التجريدات المتسربة فيما يتعلق ببنائها وخيوطها. لا أصدق أنه من الممكن أن تكون قابلة للإصلاح وأن العلامة التجارية الجديدة فقط هي الحل القابل للتطبيق. HttpClient2 ، HttpClientSlim جيد أو أيا كان.

يجب ألا يطرح وصول Http استثناءات. يجب أن تُرجع دائمًا نتيجة ، يجب أن تكون النتيجة قابلة للفحص للإنجاز ، المهلة ، استجابة http. السبب الوحيد الذي يجب السماح به للرمي هو إذا قمت باستدعاء EnsureSuccess() ، فلا بأس من طرح أي استثناء في العالم. ولكن يجب ألا يكون هناك أي تحكم في التدفق في التعامل مع السلوك الطبيعي تمامًا للإنترنت: المضيف ، وليس المضيف ، ومهلة المضيف. لا شيء من هؤلاء استثنائي.

لا ينبغي أن يقوم HttpClient على أساس طرح الاستثناءات. ليس من الاستثنائي عدم توفر مضيف الإنترنت. إنه متوقع بالفعل ، بالنظر إلى التباديل اللانهائي للعناوين ، فإن الحالة الاستثنائية تمنحها شيئًا يعمل.

dotnetchris نظرًا لأنه يبدو أن لديك شغفًا كبيرًا بهذا الموضوع ، فلماذا لا تأخذ الوقت الكافي لكتابة واجهة برمجة التطبيقات الكاملة المقترحة لـ HttpClient2 وإرسالها إلى الفريق للمناقشة كقضية جديدة؟

لم أزعج نفسي بالغوص في التفاصيل الدقيقة لما يجعل HttpClient جيدًا أو سيئًا من مستوى تقني أعمق ، لذلك ليس لدي أي شيء لأضيفه إلى تعليقاتdotnetchris. بالتأكيد لا أعتقد أنه من المناسب انتقاد فريق مطوري MS ، لكنني أفهم أيضًا مدى الإحباط الذي تشعر به عند قضاء ساعات وساعات في البحث عن حلول للمواقف التي يبدو أنها يجب أن تكون سهلة التعامل معها. إنه الإحباط الناتج عن الكفاح من أجل فهم سبب اتخاذ قرارات / تغييرات معينة ، على أمل أن يقوم شخص ما في MS بمعالجة هذا القلق بينما لا يزال يحاول إنجاز عملك وتسليمه في غضون ذلك.

في حالتي ، لدي خدمة خارجية أتصل بها أثناء عملية OAuth لتحديد أدوار المستخدم وإذا انتهت مهلة الاستدعاء هذه خلال فترة زمنية محددة (والتي تحدث للأسف أكثر مما أريد) ، فأنا بحاجة للعودة إلى طريقة ثانوية .

حقًا ، هناك عدد لا يحصى من الأسباب الأخرى التي يمكنني من خلالها معرفة سبب رغبة شخص ما في التمييز بين المهلة والإلغاء. لماذا لا يبدو أن هناك دعمًا أفضل لسيناريو شائع كهذا هو ما أجد صعوبة في فهمه ، وآمل حقًا أن يكون هذا أمرًا يفكر فيه فريق MS بشكل إضافي.

karelz ما هو المطلوب للحصول على هذا في الموعد المحدد لـ 3.0 ، اقتراح API من شخص ما؟

هذا ليس حول اقتراح API. هذا يتعلق بإيجاد التنفيذ الصحيح. إنه مدرج في التراكم 3.0 لدينا وهو مرتفع إلى حد ما في القائمة (خلف سيناريوهات HTTP / 2 والمؤسسة). إنها فرصة جيدة جدًا أن يعالجها فريقنا في 3.0.
بالطبع إذا كان هناك شخص ما في المجتمع متحمس ، فسوف نقوم بمساهمة أيضًا.

karelz كيف يمكن للمجتمع المساعدة في هذه الحالة؟ السبب في أنني ذكرت ما إذا كانت هناك حاجة إلى اقتراح واجهة برمجة التطبيقات هو أنني لم أكن متأكدًا من رسالتك التي تبدأ "لدينا العديد من الخيارات لما يجب فعله عند حدوث المهلة:" إذا كان الفريق قد قرر البديل المفضل لديهم من تلك التي قمت بإدراجها. إذا كنت قد قررت الاتجاه ، فيمكننا الذهاب من هناك. شكرا!

من الناحية الفنية ، فإنه ليس سؤال اقتراح API. لن يتطلب القرار موافقة API. ومع ذلك ، أوافق على أننا يجب أن نكون متسقين بشأن كيفية الكشف عن الاختلاف - من المحتمل أن يكون هناك بعض النقاش.
لا أتوقع أن تختلف الخيارات عن بعضها البعض كثيرًا في التنفيذ - إذا أراد المجتمع المساعدة ، فإن تنفيذ أي من الخيارات سيوفر لنا 98٪ هناك (بافتراض طرح الاستثناء من مكان واحد ويمكن أن يكون تغير بسهولة لاحقًا للتكيف مع [1] - [3] الخيارات المذكورة أعلاه).

مرحبا! لقد وصلنا إلى هذه المشكلة مؤخرًا أيضًا. هل تشعر بالفضول إذا كان لا يزال على رادارك لـ 3.0؟

نعم ، لا يزال مدرجًا في قائمتنا 3.0 - ما زلت أعطيها فرصة بنسبة 90 ٪ لتتم معالجتها في 3.0.

جريت عبر هذا اليوم. لقد قمت بتعيين مهلة على HttpClient وهي تعطيني هذا

{System.Threading.Tasks.TaskCanceledException: A task was canceled.}
CancellationRequested = true

أتفق مع الآخرين في أن هذا محير لأنه لا يذكر أن المهلة هي المشكلة.

أم ، حسنًا ، أنا مرتبك قليلاً. يبدو أن كل شخص في هذا الموضوع يقول أن مهلات HTTP تلقي ب TaskCanceledException لكن هذا ليس ما أحصل عليه ... أحصل على OperationCanceledException في .NET Core 2.1 ...

إذا كنت ترغب في إلقاء عملية OperationCanceledException للمهلة ، فيمكنني حل هذه المشكلة ، لكنني قضيت ساعات في محاولة تتبع ما كان يحدث لأنه لم يتم توثيقه بشكل صحيح:

https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.sendasync

تنص بوضوح على أنه تم طرح HttpRequestException لانتهاء المهلة ...

يُشتق TaskCanceledException من OperationCanceledException.

stephentoub نعم ، لكنني لا أحصل على TaskCanceledException ، أحصل على OperationCanceledException .

كما هو الحال في ، كتلة catch التي تصطاد TaskCanceledException لا تلتقط الاستثناء ، فهي تحتاج على وجه التحديد إلى كتلة catch لـ OperationCanceledException .

أنا الآن أختبر على وجه التحديد مهلات HTTP عن طريق التصفية على نوع الاستثناء ، والطريقة التي أعرف بها أن المهلة هي إذا لم تكن TaskCanceledException :

ج #
يحاول {
باستخدام (var response = wait s_httpClient.SendAsync (request، _updateCancellationSource.Token) .ConfigureAwait (false))
return (int) response.StatusCode <400 ؛
}
catch (OperationCanceledException ex) عندما (ex.GetType ()! = typeof (TaskCanceledException)) {
// مهلة HTTP
عودة كاذبة؛
}
catch (HttpRequestException) {
عودة كاذبة؛
}

or alternatively this works as well, which might be better:

```c#
            try {
                using (var response = await s_httpClient.SendAsync(request, _updateCancellationSource.Token).ConfigureAwait(false))
                    return (int)response.StatusCode < 400;
            }
            catch (OperationCanceledException ex) when (ex.GetType() == typeof(OperationCanceledException)) {
                // HTTP timeout
                return false;
            }
            catch (HttpRequestException) {
                return false;
            }

أم ، حسنًا ، أنا مرتبك قليلاً. يبدو أن كل شخص في هذا الموضوع يقول أن مهلات HTTP تلقي ب TaskCanceledException لكن هذا ليس ما أحصل عليه ... أحصل على OperationCanceledException في .NET Core 2.1 ...

إذا كنت ترغب في إلقاء عملية OperationCanceledException للمهلة ، فيمكنني حل هذه المشكلة ، لكنني قضيت ساعات في محاولة تتبع ما كان يحدث لأنه لم يتم توثيقه بشكل صحيح:

https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.sendasync

تنص بوضوح على أنه تم طرح HttpRequestException لانتهاء المهلة ...

هل قرأت سلسلة الرسائل بالكامل لأن هناك بالفعل العديد من الردود حيث تتم الإشارة إلى عملية إلغاء الأمر ، بما في ذلك مثال الكود الذي طرحته والذي يوضح طريقة (ليست نظيفة كما أريد ولكنها طريقة) للتعامل مع المهلات بشكل صريح.

Hobray نعم لدي - ما الذي يجعلك تعتقد أنني لم أفعل؟ لا يزال هذا لا يفسر عدد الأشخاص في سلسلة الرسائل هذه الذين يفترض أنهم يحصلون على TaskCanceledException في المهلات ولكني لست كذلك.

لقد رأيت مثال الكود الخاص بك أيضًا ولكن لسوء الحظ يحتوي على حالة عرقية لا أعتقد أنك فكرت فيها. تم نشر الكود الذي أستخدمه لتجنب هذه المشكلة ولا يتطلب الوصول إلى رمز الإلغاء ، والذي يمكن أن يكون مهمًا إذا كنت تحاول الحصول على المهلة بشكل أكبر في المنبع.

mikernet ربما طردتني الصياغة. أنت محق في أنني لم أفكر في حالة العرق المحتملة. أدرك أنه ليس حلاً رائعًا ولكن إذا كنت ترغب في شرح ما أغفلته ، فأنا أود سماعه.

هناك شيء واحد لاحظته وهو أن الاستثناء الدقيق الذي تحصل عليه يبدو أنه يختلف اعتمادًا على ما إذا كانت المهلة أو الإلغاء يحدث أم لا في استدعاء Controller vs middleware. داخل استدعاء البرمجيات الوسيطة يبدو أنه TaskCanceledException . لسوء الحظ ، ليس لدي الوقت الكافي للتنقيب في مكتبات رموز .NET Core لفهم السبب ولكن هذا شيء لاحظته.

Hobray Haha نعم بالطبع - آسف ، لم أقصد أن أكون غامضًا بشأن حالة السباق ، كنت فقط على هاتفي بينما كنت أذهب لأكتب هذه الرسالة الأخيرة مما جعل من الصعب شرحها.

تحدث حالة السباق في الحل الخاص بك إذا بدأ إلغاء المهمة بين مهلة HttpClient والنقطة التي تتحقق فيها من حالة إلغاء رمز الإلغاء. في موقفي ، أحتاج إلى استثناء لإلغاء المهمة للاستمرار في الظهور حتى يتمكن كود المنبع من اكتشاف إلغاء المستخدم ، وبالتالي أحتاج إلى أن أكون قادرًا على التقاط الاستثناء فقط إذا كانت المهلة الفعلية - ولهذا السبب أستخدم when لتصفية الصيد. يمكن أن يؤدي استخدام الحل الخاص بك لفحص الرمز المميز إلى تمرير مرشح غير معالج وظهور فقاعات وتحطيم البرنامج ، لأن شخصًا ما ألغى العملية المنبع سيتوقع أن يتم طرح TaskCanceledException OperationCanceledException وليس OperationCanceledException .

إذا كان من المفترض أن يعالج الكود الذي يستدعي الطريقة HttpClient كلاً من المهلة وإلغاء المهمة ، فإن التمييز بين المهلة وإلغاء المستخدم عند حدوث حالة السباق قد لا يكون مهمًا بالنسبة لك ، اعتمادًا على الموقف ... ولكن إذا كنت تكتب رمزًا على مستوى المكتبة وتحتاج إلى السماح بإلغاء المهمة ليتم التعامل معها على مستوى أعلى ، فمن المؤكد أنها تحدث فرقًا.

إذا كان ما تقوله صحيحًا وكانت المهلات تطرح أنواعًا مختلفة من الاستثناءات اعتمادًا على سياق الاستدعاء ، فهذا بالتأكيد يبدو وكأنه مشكلة بالنسبة لي يجب معالجتها. لا توجد طريقة أو يجب أن يكون هذا هو السلوك المقصود.

مثيرة للاهتمام حول حالة السباق المحتملة. لم أفكر في ذلك. لحسن الحظ ، بالنسبة لحالة الاستخدام الخاصة بي ، لن تكون مشكلة كبيرة.

فيما يتعلق بصيغ الاستثناءات ، أحتاج إلى إيجاد بعض الوقت للتخلص من البرامج الوسيطة التي كنت أعمل عليها لمعرفة ما إذا كانت متوافقة مع ما رأيته عدة مرات أثناء تصحيح الأخطاء. لقد كانت مكالمات التحميل المسبق في المربع متعدد الاستخدامات في Chrome هي المكان الذي رأيته فيه في البرنامج الوسيط الخاص بي عندما كان التوقيت مناسبًا تمامًا. أعتقد أنه يمكنني إنشاء مثال بسيط لإثبات ذلك بطريقة أو بأخرى.

ما زلت غير واضح بشأن الحل الصحيح الذي يجب أن يكون.

الحل الذي أقدمه هو الأصح في المواقف التي تؤدي فيها مهلات http إلى تشغيل عملية إلغاء الأمر. لا يمكنني إعادة إنتاج الموقف حيث يتم طرح TaskCanceledException ولم يقدم أحد طريقة لإعادة إنتاج هذا السلوك ، لذلك أقول اختبار بيئتك وإذا كانت تتطابق مع بيئتي ، فهذا هو الحل الصحيح.

إذا تم طرح TaskCanceledException في بعض سياقات التنفيذ ، فإن الحل الخاص بي يفشل كحل للأغراض العامة لتلك السياقات والحل الآخر المقترح هو الحل "الأفضل" ولكنه يحتوي على حالة سباق قد تكون أو لا تكون مهمة لموقفك ، وهذا من أجل عليك أن تقيم.

أود أن أسمع المزيد من التفاصيل من شخص يدعي أنه يحصل على استثناءات TaskCanceledExceptions لأنه من الواضح أن ذلك سيكون خطأً كبيرًا. أنا متشكك إلى حد ما في أن هذا يحدث بالفعل.

mikernet سواء تم طرح TaskCanceledException أو OperationCanceledException هو أمر غير ذي صلة إلى حد كبير. هذه تفاصيل تنفيذ يجب ألا تعتمد عليها. ما يمكنك فعله هو التقاط OperationException (والذي سيحصل أيضًا على TaskCanceledException ) ، وتحقق مما إذا كان رمز الإلغاء الذي مررته قد تم إلغاؤه ، كما هو موضح في تعليق Hobray (https://github.com/ dotnet / corefx / issue / 20296 # issuecomment-449510983).

thomaslevesque لقد تناولت بالفعل سبب كون هذا النهج يمثل مشكلة. بدون معالجة ذلك ، فإن تعليقك ليس مفيدًا للغاية - إنه مجرد إعادة صياغة للعبارات قبل أن أنضم إلى التحويل دون معالجة المشكلة التي وصفتها.

بالنسبة إلى "هذه تفاصيل تنفيذية" - نعم إنها كذلك ، ولكن لسوء الحظ لا بد لي من الاعتماد عليها لأنه بخلاف ذلك لا توجد طريقة جيدة لتحديد ما إذا كانت المهمة قد تم إلغاؤها أو انقضت مهلتها. يجب أن تكون هناك طريقة بنسبة 100٪ لتحديد أي من هذين السيناريوهين حدث لتجنب حالة السباق الموصوفة. OperationCanceledException هو مجرد اختيار سيئ بسبب هذا ... يوجد بالفعل TimeoutException في إطار العمل الذي يجعل مرشحًا أفضل.

يجب ألا تعتمد استثناءات المهام غير المتزامنة على فحص البيانات في كائن آخر يمكن أيضًا تعديله بشكل غير متزامن لتحديد سبب الاستثناء إذا كانت حالة الاستخدام الشائعة هي اتخاذ قرار تفريعي بناءً على سبب الاستثناء. هذا استجداء لمشاكل حالة السباق.

أيضًا ، من حيث كون نوع الاستثناء عبارة عن تفاصيل تنفيذ ... لا أعتقد حقًا أن هذا صحيح بالنسبة للاستثناءات ، على الأقل ليس من حيث ممارسات توثيق .NET الراسخة. قم بتسمية مثال آخر في .NET Framework حيث تقول الوثائق "يطرح استثناء X عندما يحدث Y" ويطرح إطار العمل بالفعل فئة فرعية يمكن الوصول إليها بشكل عام من هذا الاستثناء ، ناهيك عن فئة فرعية يمكن الوصول إليها بشكل عام يتم استخدامها لحالة استثناء مختلفة تمامًا في بنفس الطريقة ! هذا يبدو وكأنه شكل سيء ولم أواجه هذا من قبل خلال 15 عامًا من برمجة .NET.

بغض النظر ، يجب حجز TaskCanceledException لإلغاء المهمة التي بدأها المستخدم ، وليس للمهلة - كما قلت ، لدينا بالفعل استثناء لذلك. يجب أن تقوم المكتبات بالتقاط أي عمليات إلغاء للمهام الداخلية وإلقاء المزيد من الاستثناءات المناسبة. لا ينبغي أن تكون معالجات الاستثناءات لعمليات إلغاء المهام التي تم بدؤها برموز إلغاء المهام مسئولة عن التعامل مع المشكلات الأخرى غير ذات الصلة التي قد تحدث أثناء العملية غير المتزامنة.

mikernet آسف ، فاتني هذا الجزء من المناقشة. نعم ، هناك حالة سباق لم أفكر فيها. ولكن قد لا تكون المشكلة كبيرة كما تبدو ... تحدث حالة السباق إذا تمت الإشارة إلى رمز الإلغاء بعد حدوث المهلة ولكن قبل التحقق من حالة الرمز المميز ، أليس كذلك؟ في هذه الحالة ، لا يهم حقًا ما إذا كانت المهلة قد حدثت إذا تم إلغاء العملية على أي حال. لذلك ستسمح للمتصل بفقاعة OperationCanceledException ، مما يسمح للمتصل بالاعتقاد بأن العملية قد تم إلغاؤها بنجاح ، وهي كذبة لأن المهلة حدثت بالفعل ، لكن هذا لا يهم المتصل ، لأنه أراد ذلك إجهاض العملية على أي حال.

يجب أن تكون هناك طريقة بنسبة 100٪ لتحديد أي من هذين السيناريوهين حدث لتجنب حالة السباق الموصوفة. OperationCanceledException هو مجرد اختيار سيئ بسبب هذا ... يوجد بالفعل TimeoutException في إطار العمل الذي يجعل المرشح أفضل.

أنا أتفق تمامًا مع ذلك ، من الواضح أن السلوك الحالي خاطئ. في رأيي ، فإن أفضل خيار لإصلاحه هو الخيار 1 من تعليق karelz . نعم ، إنه تغيير جذري ، لكنني أظن أن معظم قواعد التعليمات البرمجية لا تتعامل مع هذا السيناريو بشكل صحيح على أي حال ، لذلك لن يزيد الأمر سوءًا.

thomaslevesque حسنًا ، نعم ، لكنني تناولت ذلك نوعًا ما. قد يكون أو لا يكون مهمًا لبعض التطبيقات. في المنجم هو على الرغم من ذلك. لا يتوقع مستخدم طريقة مكتبتي OperationCanceledException عندما يقوم بإلغاء مهمة - فهم يتوقعون TaskCanceledException ويجب أن يكونوا قادرين على التقاط ذلك وأن يكونوا "آمنين". إذا تحققت من رمز الإلغاء ، فتأكد من أنه قد تم إلغاؤه وقمت بتمرير الاستثناء ، فقد قمت للتو بتمرير استثناء لن يتم اكتشافه بواسطة معالجهم وسيؤدي إلى تعطل البرنامج. لا يُفترض أن يكون طريقي على المهلات.

بالتأكيد ، هناك طرق للتغلب على هذا ... يمكنني فقط طرح ملف جديد TaskCanceledException ولكن بعد ذلك أفقد تتبع مكدس المستوى الأعلى ، ويتم التعامل مع مهلات HTTP بشكل مختلف كثيرًا عن عمليات إلغاء المهام في خدمتي - تنتهي مهلات HTTP في ذاكرة التخزين المؤقت لفترة طويلة ، بينما لن يتم إلغاء المهام. لا أريد تفويت المهلات الفعلية للتخزين المؤقت بسبب حالة السباق.

أعتقد أنه يمكنني التقاط OperationCanceledException والتحقق من رمز الإلغاء - إذا تم إلغاؤه ، تحقق أيضًا من نوع الاستثناء للتأكد من أنه TaskCanceledException قبل إعادة النمو لتجنب تعطل البرنامج بالكامل. إذا كان أي من هذه الشروط خاطئًا ، فيجب أن تكون مهلة. المشكلة الوحيدة المتبقية في هذه الحالة هي حالة السباق التي تكون دقيقة ، ولكن عندما يكون لديك الآلاف من طلبات HTTP التي تحدث في الدقيقة على خدمة محملة بكثافة مع تعيين مهلات ضيقة ، يحدث ذلك.

في كلتا الحالتين ، يجب حل هذا الاختراق وكما أشرت بطريقة ما.

(لن تحدث حالة السباق إلا في البيئات التي يتم فيها طرح TaskCanceledException بدلاً من OperationCanceledException ، أينما كان ذلك ، ولكن على الأقل يكون الحل آمنًا من ظهور نوع استثناء غير متوقع وغير متوقع الاعتماد على تفاصيل التنفيذ من أجل الاستمرار في العمل بشكل جيد بشكل معقول إذا تغيرت تفاصيل التنفيذ).

استثناء المهلة الذي تم طرحه بواسطة HttpClient في حالة انتهاء مهلة http يجب ألا يكون من النوع System.Net.HttpRequestException (أو تابع؟) بدلاً من System.TimeoutException العام؟ على سبيل المثال ، WebClient يطرح WebException مع خاصية Status والتي يمكن ضبطها على WebExceptionStatus.Timeout .

للأسف ، لن نتمكن من إنهاء هذا الإصدار 3.0. الانتقال إلى المستقبل.
لا يزال على رأس الأعمال المتراكمة لدينا ، لكن من الناحية الواقعية لن نتمكن من القيام بذلك لـ 3.0 :(.

Karelz @ oh no :( كنت سأقوم بإعادة النشر لأقول كيف واجهت هذا مرة أخرى في الشركة الثانية على التوالي. ما هي المدة التي ستستغرقها النافذة لتقديم علاقات عامة لـ 3.0 إذا أردت التعامل معها بنفسي؟

أواجه صعوبة في تتبع ما يحدث بالضبط في مجموعة التعليقات أعلاه حيث أبلغ الأشخاص عن الاختلافات بين الحصول على TaskCancelledException و OperationCancelledException اعتمادًا على السياق ، هل يمكن لأي شخص من MSFT توضيح ذلك؟

مثل هذا التعليق من mikernet :

كما هو الحال في ، فإن كتلة catch التي تمسك TaskCanceledException لا تلتقط الاستثناء ، فهي تحتاج على وجه التحديد إلى كتلة catch لـ OperationCanceledException.

cc davidshstephentoub ربما ؟

يُشتق TaskCanceledException من OperationCanceledException ويحمل القليل من المعلومات الإضافية. ما عليك سوى التقاط OperationCanceledException.

karelz هل سيكون الخيار 1 الذي نشرته في الأصل ، فقط جعله يطرح استثناء Timeout ، غير مستساغ تمامًا؟

أشياء مثل StackExchange.Redis تطرح استثناءًا مشتقًا من استثناء Timeout ، ولهذا سيكون من الجيد التقاط استثناء Timeout لـ HttpClient ...

أفهم stephentoub بالنظر إلى الميراث ، فقط هذا التعليق أدناه من mikernet يذهلني ... هذا السلوك الذي يصفه يجب أن يكون نوعًا من الأخطاء ؟؟ ولكن إذا كان هذا صحيحًا ، فسيؤثر على الإصلاح أو الحل ...

"كتلة catch التي تمسك TaskCanceledException لا تلتقط الاستثناء ، فهي تحتاج على وجه التحديد إلى كتلة catch من أجل OperationCanceledException"

أم أنك تقول أن بعض الأماكن ترمي عملية EX والأماكن الأخرى TaskEx؟ مثل ربما يرى الناس شيئًا ما قادمًا من البرامج الوسيطة لـ ASP ويعتقدون أنه من HttpClient؟

هذا التعليق أدناه من mikernet يذهلني ... هذا السلوك الذي يصفه يجب أن يكون نوعًا من الأخطاء ؟؟

لماذا هذا "يفجر عقلك"؟ إذا كان الاستثناء B مشتقًا من الاستثناء A ، فلن تلتقط كتلة catch لـ B استثناءً ملموسًا A ، على سبيل المثال إذا كان لدي كتلة catch لـ ArgumentNullException ، فلن تلتقط "طرح ArgumentException جديد (...)".

أم أنك تقول أن بعض الأماكن ترمي عملية EX والأماكن الأخرى TaskEx؟

حق. في الكود العام يجب أن يفترض OCE فقط ؛ بالطريقة التي تُكتب بها الأشياء ، قد ينتهي الأمر ببعض التعليمات البرمجية بإلقاء TCE المشتق ، على سبيل المثال ، المهمة المنجزة عبر TaskCompletionSource. ستنتجrySetCanceled TaskCanceledException.

شكرًا لك ستيفن ، من أصوات الأشياء في الموضوع ، كان لدى العديد من الأشخاص انطباع بأن TaskCE تم طرحها في كل مكان ، مما قد يجعل السلوك الذي ذكره mikernet غير منطقي ... الملاحظة المنطقية :)

stephentoub ، هل هذا التوجيه موثق في أي مكان؟ بينغguardrex

في الكود العام يجب أن يفترض OCE فقط ...

أعمل في مجموعة مستندات ASP.NET هذه الأيام. افتح مشكلة لـ dotnet / docs cats ...

https://github.com/dotnet/docs/issues

هل من الممكن إعادة هذه المحادثة مرة أخرى حيث كانت هناك بعض المقترحات الملموسة مع karelz و davidsh ؟ يبدو الأمر وكأن شخصًا (أشخاصًا) يمتلكون نموذج واجهة برمجة تطبيقات HttpClient يحتاجون إلى اتخاذ قرارات بشأن الاتجاه الذي يجب اتباعه. كان هناك بعض النقاش حول استثناءات المستوى الأعلى دائمًا ما تكون HttpRequestException (بخلاف عمليات الإلغاء الصريحة ؟؟) ، ممزوجة ببعض الموضوعات التي تبدو طويلة المدى حول مُعدِّل أكبر لتعديل HttpRequestion لتضمين خاصية تعداد جديدة مشابهة لـ WebExceptionStatus ...

يبدو الأمر وكأن هذه المشكلة برمتها تتلاشى بالنسبة إلى تغيير الكود الفعلي المطلوب. هل هناك أشخاص آخرون لديهم حصة / ملكية في نموذج واجهة برمجة تطبيقات HttpClient والتي يجب تكرارها من أجل اتخاذ بعض القرارات؟ شكرا جزيلا للجميع!

أواجه نفس المشكلة هنا - ومع ذلك ، فإن cancellationToken.IsCancellationRequested يعود true :

    public class TimeoutHandler : DelegatingHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            try
            {
                var response = await base.SendAsync(request, cancellationToken);
                response.EnsureSuccessStatusCode();

                return response;
            }
            catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
            {
                throw new TimeoutException("Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.");
            }
        }

أنا أجبر مهلة. الاستثناء الذي تم رفعه هو TaskCancelledException مع IOException كاستثناء داخلي:

System.Threading.Tasks.TaskCanceledException: The operation was canceled. ---> System.IO.IOException: Unable to read data from the transport connection: A operação de E/S foi anulada devido a uma saída de thread ou a uma requisição de aplicativo. ---> System.Net.Sockets.SocketException: A operação de E/S foi anulada devido a uma saída de thread ou a uma requisição de aplicativo
   --- End of inner exception stack trace ---
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.GetResult(Int16 token)
   at System.Net.Http.HttpConnection.FillAsync()
   at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

...

(آسف على نص الاستثناء المترجم - من الواضح أن أحدهم اعتقد أنه سيكون فكرة جيدة لإحضار هذا إلى .NET Core أيضًا)

كما ترى ، كنت آمل أن أتحقق من IsCancellationRequest لحل هذه المشكلة كما اقترح البعض الآخر ، ولكن حتى في المهلات ، فإنه يعيد true .

أفكر حاليًا في تنفيذ مؤقت للتحقق مما إذا كانت المهلة المهيأة قد مرت. لكن ، من الواضح أنني أريد أن أموت ، فهذا حل رهيب.

مرحبًا FelipeTaveira ،

نهجك لا يعمل ، لأنه يتم التعامل مع الإلغاء قبل TimeoutHandler ، بواسطة HttpClient نفسه. يتلقى المعالج رمز إلغاء تم إلغاؤه بواسطة HttpClient عند حدوث Timeout . لذا فإن التحقق من أن رمز الإلغاء لا يتم إلغاؤه يعمل فقط في الكود الذي يستدعي HttpClient ، وليس في الكود الذي يسمى HttpClient .

طريقة جعله يعمل مع معالج مخصص هو تعطيل HttpClient 's Timeout عن طريق تعيينه على Timeout.InfiniteTimeSpan ، والتحكم في سلوك المهلة في المعالج الخاص بك ، مثل موضح في هذه المقالة (الكود الكامل هنا )

thomaslevesque أوه ، شكراً! لقد قرأت التعليمات البرمجية الخاصة بك واعتقدت أن هذا الجزء كان يتعلق بدعم تهيئة مهلة كل طلب ولم ألاحظ أنه من الضروري أيضًا دعم الشيء TimeoutException .

آمل أن يتم تناول هذا في المستقبل.

لما يستحق ، أجد أيضًا أن TaskCanceledException يتم إلقاؤه في المهلات أمرًا محيرًا.

أستطيع أن أشهد أن TaskCanceledExceptions كان مصدرًا رئيسيًا للارتباك عند التعامل مع مشكلات الإنتاج في وظيفتي السابقة. سنقوم عمومًا بلف المكالمات إلى HttpClient ورمي استثناءات TimeoutExceptions عند الاقتضاء.

eiriktsarpalis شكرا. نخطط لمعالجته في الإصدار 5.0 ، حتى تتمكن من استلامه في هذا الإطار الزمني إذا أردت ، الآن بعد أن انضممت إلى فريقنا 😇.

سنة واحدة؟ 😵 أين هي خفة الحركة الموعودة لـ NET Core؟

الحكم على رشاقة المشروع بأكمله بناءً على قضية واحدة هو أمر غير عادل بعض الشيء.
نعم ، إنه أمر محرج بعض الشيء ، ما زلنا نواجه هذه المشكلة ، ومع ذلك ، من الصعب إصلاحها (مع تأثير المواطن) وكانت هناك فقط أهداف عمل ذات أولوية أعلى يجب معالجتها أولاً (في الشبكات) - انظر التغييرات في المعالم عبر التاريخ من هذه القضية.

راجع للشغل: كما هو الحال في العديد من مشاريع OSS الأخرى ، لا توجد اتفاقيات SLA أو ETA أو وعود بشأن موعد إصلاح المشكلة. كل هذا يتوقف على الأولويات ، والأعمال الأخرى ، والصعوبة وعدد الخبراء القادرين على معالجة المشكلة.

الحكم على رشاقة المشروع بأكمله بناءً على قضية واحدة هو أمر غير عادل بعض الشيء.

حسنًا ، لقد كان سؤالًا صادقًا. لقد مرت بالفعل عامين وعندما رأيت أن الأمر سيستغرق عامًا آخر ، فوجئت قليلاً. لا تعني الإساءة بالرغم من ذلك 🙂. أعلم أنه لإصلاح هذه المشكلة ، كانت هناك / هناك بعض الأسئلة التي يجب / يجب الإجابة عليها أولاً.

في عالم من التنازلات ... لا أحب ذلك ولكن إليك خيار آخر لمضغه:

يمكن أن نستمر في طرح TaskCanceledException ، لكن نضبط قيمة CancellationToken على قيمة الحراسة.

c# catch(TaskCanceledException ex) when(ex.CancellationToken == HttpClient.TimeoutToken) { }

وآخر: قم برمي HttpTimeoutException جديد مشتق من TaskCanceledException .

وآخر: قم برمي HttpTimeoutException جديد مشتق من TaskCanceledException .

أعتقد أن هذا من شأنه معالجة جميع المخاوف. إنه يجعل من السهل تحديد المهلة على وجه التحديد ، ولا تزال TaskCanceledException ، لذا فإن الكود الذي يمسك هذا الاستثناء حاليًا سيقبض أيضًا على الاستثناء الجديد (بدون تغيير كسر).

وآخر: قم برمي HttpTimeoutException جديدًا مشتقًا من TaskCanceledException.

يبدو قبيحًا إلى حد ما ، لكن من المحتمل أن يكون حل وسط جيد.

وآخر: قم برمي HttpTimeoutException جديد مشتق من TaskCanceledException .

أعتقد أن هذا من شأنه معالجة جميع المخاوف. إنه يجعل من السهل تحديد المهلة على وجه التحديد ، ولا تزال TaskCanceledException ، لذا فإن الكود الذي يمسك هذا الاستثناء حاليًا سيقبض أيضًا على الاستثناء الجديد (بدون تغيير كسر).

حسنًا ، يمكن أن يكون هناك أشخاص يكتبون رمزًا مثل هذا:

try
{
  // ...
}
catch (Exception ex) when (ex.GetType() == typeof(TaskCanceledException))
{
}

لذلك سيكون هذا تقنيًا تغييرًا جذريًا.

وأعتقد أيضًا أنه يحتوي على جزء من أسوأ ما في العالمين. ما زلنا لا نحصل على TimeoutException عام في نفس الوقت مع وجود تغيير مفاجئ.

يمكن أن يكون هناك أشخاص يكتبون رمزًا مثل هذا لذا سيكون هذا تغييرًا تقنيًا

FWIW ، من المحتمل أن ينكسر كل تغيير تقريبًا ، لذا لتحقيق تقدم للأمام في أي شيء ، يجب على المرء أن يرسم خطاً في مكان ما. في corefx ، لا نفكر في إعادة أو إلقاء نوع مشتق أكثر ليتم كسره.
https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/breaking-change-rules.md#exceptions

في عالم من التنازلات ... لا أحب ذلك ولكن إليك خيار آخر لمضغه:

يمكن أن نستمر في طرح TaskCanceledException ، لكن نضبط قيمة CancellationToken على قيمة الحراسة.

catch(TaskCanceledException ex) when(ex.CancellationToken == HttpClient.TimeoutToken)
{
}

أنا حقا أحب هذا واحد. هل هناك أي عيب آخر لها غير كونها "قبيحة"؟ ما هو ex.CancellationToken اليوم عند انتهاء المهلة؟

هل هناك أي عيب آخر لها غير كونها "قبيحة"؟

سيكون من السهل حقًا أن يعتقد شخص ما أنه يمكن تمرير TimeoutToken واستخدامه للإشارة إلى الإلغاء عند حدوث انتهاء المهلة ، نظرًا لأن هذا هو التصميم المستخدم في مكان آخر لمثل هذه الأشياء.

أنا حقا أحب هذا واحد. هل هناك أي عيب آخر لها غير كونها "قبيحة"؟ ما هو ex.CancellationToken اليوم عند انتهاء المهلة؟

إنه أقل سهولة من التقاط نوع استثناء معين ، والذي يمكن ذكره صراحة في الوثائق.

لقد اعتدت التفكير في أنواع OperationCanceledException والمشتقة للدلالة على تنفيذ متقطع ، وليس خطأ في التطبيق. عادةً ما يكون الاستثناء HttpClient الذي يتم طرحه عند انتهاء المهلة خطأ - كان هناك استدعاء لواجهة برمجة تطبيقات HTTP ، ولم يكن متاحًا. يؤدي هذا السلوك إما إلى تعقيدات أثناء معالجة الاستثناءات على مستوى أعلى ، على سبيل المثال ، في البرامج الوسيطة لخطوط الأنابيب ASP.NET Core ، نظرًا لأن هذا الرمز يجب أن يعرف أن هناك نوعين من النكهات من OperationCanceledException ، خطأ وليس خطأ ، أو يجبرك على إنهاء كل مكالمة HttpClient في كتلة رمي.

وآخر: قم برمي HttpTimeoutException جديدًا مشتقًا من TaskCanceledException.

يبدو قبيحًا إلى حد ما ، لكن من المحتمل أن يكون حل وسط جيد.

هل هذا قبيح حقًا ، نظرًا لقيود التصميم المتضمنة واعتبارات التوافق العكسي؟ لا أعلم أن أي شخص في هذا الموضوع قد اقترح حلاً متفوقًا بوضوح لا يحتوي على عيوب (سواء الاستخدام أو نقاء التصميم وما إلى ذلك)

نريد أن ننظر إلى هذا بشكل أعمق من مجرد تغيير نوع الاستثناء. هناك أيضًا قضية طال أمدها وهي "أين انتهت مهلنا؟" - على سبيل المثال ، من الممكن أن تنتهي مهلة الطلب دون أن يصطدم بالسلك - وهو ما نحتاج إلى النظر فيه ، ويجب أن يكون الحل متوافقًا مع الاتجاه الذي نذهب إليه هناك.

نريد أن ننظر إلى هذا بشكل أعمق من مجرد تغيير نوع الاستثناء. هناك أيضًا قضية طال أمدها وهي "أين انتهت مهلنا؟" - على سبيل المثال ، من الممكن أن تنتهي مهلة الطلب دون أن يصطدم بالسلك - وهو ما نحتاج إلى النظر فيه ، ويجب أن يكون الحل متوافقًا مع الاتجاه الذي نذهب إليه هناك.

هل هذا حقا شيء تحتاج إلى معرفته؟ أعني ، هل ستتعامل مع الخطأ بشكل مختلف اعتمادًا على الوقت الذي انتهت فيه؟ بالنسبة لي ، يكفي عادةً معرفة أن المهلة حدثت.
لا أمانع إذا كنت تريد فعل المزيد ، فأنا لا أريد أن يفوت هذا التغيير قطار .NET 5 بسبب المتطلبات الإضافية: غمزة:

أعتقد أن المشكلة التي طرحتها scalablecory جديرة بالملاحظة ، لكنني أوافق على أنه لا ينبغي أن يعيق حل هذا الأمر عاجلاً. يمكنك تحديد آلية للسماح بتقييم سبب المهلة ولكن من فضلك لا تتأخر في إصلاح مشكلة الاستثناء لذلك ... يمكنك دائمًا إضافة خاصية Reason إلى الاستثناء لاحقًا.

أتفق معthomaslevesque ؛ لم أسمع ذلك كمشكلة كبيرة من قبل. حيث أن تأتي من؟

هل هذه حالة تصحيح أخطاء مناسبة إلى حد ما حيث سيكون من المقبول البحث في سبب طلب القليل من الإجراءات الصريحة ، بينما بالنسبة للمطور العام ، سيكون عليهم فقط معرفة / الاهتمام بالتعامل مع شيء واحد.

نريد أن ننظر إلى هذا بشكل أعمق من مجرد تغيير نوع الاستثناء. هناك أيضًا قضية طال أمدها وهي "أين انتهت مهلنا؟" - على سبيل المثال ، من الممكن أن تنتهي مهلة الطلب دون أن يصطدم بالسلك - وهو ما نحتاج إلى النظر فيه ، ويجب أن يكون الحل متوافقًا مع الاتجاه الذي نذهب إليه هناك.

أفترض أن المعنى الضمني هنا هو أنه يجب أن يكون من مسؤولية كل HttpMessageHandler طرح نوع استثناء المهلة الصحيحة بدلاً من إصلاح HttpClient للأشياء.

أفترض أن المعنى الضمني هنا هو أنه يجب أن يكون من مسؤولية كل HttpMessageHandler طرح نوع استثناء المهلة الصحيحة بدلاً من إصلاح HttpClient للأشياء.

لا أرى كيف يكون ذلك ممكنًا مع التجريد المحدد اليوم. HttpMessageHandler ليس لديه معرفة بـ HttpClient's Timeout ؛ بقدر ما يتعلق الأمر بـ HttpMessageHandler ، فقد تم تسليمه للتو رمزًا مميزًا للإلغاء ، والذي قد يؤدي إلى طلب الإلغاء لأي عدد من الأسباب ، بما في ذلك الإشارة إلى رمز إلغاء المتصل الذي يتم الإشارة إليه ، واستدعاء طلبات HttpClient's CancelPendingRequests ، وانتهاء مهلة HttpClient المفروضة ، وما إلى ذلك.

هل هذا حقا شيء تحتاج إلى معرفته؟ أعني ، هل ستتعامل مع الخطأ بشكل مختلف اعتمادًا على الوقت الذي انتهت فيه؟ بالنسبة لي ، يكفي عادةً معرفة أن المهلة حدثت.

من المفيد معرفة ما إذا كان الخادم قد عالج طلبك. إنها أيضًا رائعة للتشخيص - خادم بعيد لا تنتهي مهلته ولكن إبلاغ العميل عن المهلات يعد تجربة محبطة.

قد يكون لدى davidsh المزيد من البصيرة.

أتفق معthomaslevesque ؛ لم أسمع ذلك كمشكلة كبيرة من قبل. حيث أن تأتي من؟

لقد كانت نقطة أثيرت خلال اجتماع NCL الأخير. قد نقرر أن هذا ليس مهمًا بما يكفي لفضح الأشياء أو تأخيرها ، لكن الأمر يستحق مناقشة سريعة أولاً.

@ dotnet / nclstephentoub لنضع هذا في الفراش. نحن نعلم أن أي شيء نقوم به سيتم كسره بمهارة. يبدو أن هذا هو الخيار الأقل سوءًا. أقترح المضي قدمًا في:

طرح HttpTimeoutException جديدًا مشتقًا من TaskCanceledException .

اعتراضات؟

طرح HttpTimeoutException جديدًا مشتقًا من TaskCanceledException.

كيف نفعل هذا عمليا؟ ربما يعني ذلك أنه يتعين علينا مسح الكود الخاص بنا والعثور على جميع الأماكن التي تستدعي CancellationToken .

c# if (token.IsCancellationRequested) throw new HttpTimeoutException(EXTRASTUFF, token);

بالإضافة إلى الأماكن الصريحة التي قد نتصل بها في الواقع OperationCancelledException أيضًا.

هل هناك أي خيار لا يتطلب تجاوز كل تلك التعليمات البرمجية ذات الصلة على أي حال؟

هل هناك أي خيار لا يتطلب تجاوز كل تلك التعليمات البرمجية ذات الصلة على أي حال؟

ربما لا ، ولكن قد تكون هناك أماكن لا نتحكم فيها (لست متأكدًا بعد) ولذا سنحتاج إلى الحصول على TaskCancelledException / OperationCancelledException عشوائيًا وإعادة طرح HttpTimeoutException الجديد.

ربما يعني هذا أنه يتعين علينا مسح الكود الخاص بنا والعثور على جميع الأماكن التي تستدعي CancellationToken.

هل هناك أي خيار لا يتطلب تجاوز كل تلك التعليمات البرمجية ذات الصلة على أي حال؟

ليس تماما.

بقدر ما يتعلق الأمر بالمعالجين ، فإن كل ما يتلقونه هو إلغاء الأمر: فهم لا يعرفون ولا يهتمون بمصدر هذا الرمز المميز ، أو من أنتجه ، أو سبب طلب الإلغاء. كل ما يعرفونه هو أنه قد يتم طلب الإلغاء في وقت ما ، وهم يطرحون استثناءً للإلغاء ردًا على ذلك. لذلك ، لا يوجد شيء يمكن القيام به هنا في المتعاملين.

يقوم HttpClient نفسه بإنشاء CancellationTokenSource ذي الصلة وتعيين مهلة عليه:
https://github.com/dotnet/corefx/blob/bdd33976fe3713cc3e78b83cf2a1176c70b793be/src/System.Net.Http/src/System/Net/Http/HttpClient.cs#L488
المهلة هي بالكامل اختراع HttpClient نفسها ، وهي فقط تعرف ما إذا كانت تريد معالجة استثناء الإلغاء الذي ظهر على أنه خاص.

هذا يعني أن الكود المشار إليه أعلاه سيحتاج إلى إعادة هيكلة لتتبع المهلة بشكل منفصل ، إما كمصدر منفصل لـ CancellationTokenSource ، أو على الأرجح من خلال معالجة منطق المهلة من تلقاء نفسه ، بالإضافة إلى إلغاء CTS ، وكذلك تعيين علامة يمكنه ذلك ثم تحقق أيضا. من المحتمل أن يكون هذا غير نظام الدفع مقابل اللعب ، حيث سنضيف تخصيصات إضافية هنا ، ولكن من منظور الكود ، يكون الأمر بسيطًا نسبيًا.

ثم في أماكن في HttpClient مثل:
https://github.com/dotnet/corefx/blob/bdd33976fe3713cc3e78b83cf2a1176c70b793be/src/System.Net.Http/src/System/Net/Http/HttpClient.cs#L536 -L541
و
https://github.com/dotnet/corefx/blob/bdd33976fe3713cc3e78b83cf2a1176c70b793be/src/System.Net.Http/src/System/Net/Http/HttpClient.cs#L562 -L566
عندما يكتشف استثناءً ، سيحتاج إلى إلغاء حالة خاصة ، للتحقق مما إذا كانت المهلة قد انتهت ، وإذا كان قد انتهى ، افترض أنه كان سبب الإلغاء وطرح استثناء جديد من النوع المطلوب.

ستحتاج إلى إلغاء حالة خاصة ، للتحقق لمعرفة ما إذا كانت المهلة قد انتهت ، وإذا كانت قد انتهت ، افترض أنها كانت سبب الإلغاء وطرح استثناء جديد من النوع المطلوب.

كيف يعمل هذا إذا لم يتم تضمين الخاصية HttpClient.Timeout؟ ربما تم تعيينه على "لانهائي". ماذا عن الرموز المميزة للإلغاء التي تم تمريرها مباشرة إلى واجهات برمجة تطبيقات HttpClient (GetAsync و SendAync وما إلى ذلك)؟ أفترض أن يعمل نفس الشيء؟

كيف يعمل هذا إذا لم يتم تضمين الخاصية HttpClient.Timeout؟

لا أفهم السؤال ... هذه هي المهلة الوحيدة التي نتحدث عنها هنا. إذا تم الضبط على Infinite ، فلن يحدث الإلغاء أبدًا بسبب هذه المهلة ، ولن يكون هناك ما يمكن فعله. لدينا بالفعل حالة خاصة مهلة == لانهائية وسنواصل:
https://github.com/dotnet/corefx/blob/bdd33976fe3713cc3e78b83cf2a1176c70b793be/src/System.Net.Http/src/System/Net/Http/HttpClient.cs#L481

ماذا عن الرموز المميزة للإلغاء التي تم تمريرها مباشرة إلى واجهات برمجة تطبيقات HttpClient (GetAsync و SendAync وما إلى ذلك)؟ أفترض أن يعمل نفس الشيء؟

نحن نجمع أي رمز تم تمريره مع واحد من صنعنا:
https://github.com/dotnet/corefx/blob/bdd33976fe3713cc3e78b83cf2a1176c70b793be/src/System.Net.Http/src/System/Net/Http/HttpClient.cs#L485
سنتعقب طريقة تعاملنا مع HttpClient.Timeout ، كما هو مذكور في تعليقاتي السابقة. إذا اختار المتصل تمرير رمز مميز قام بتكوينه مع انتهاء المهلة ، فإن التعامل مع هذا الأمر بشكل خاص متروك له: بقدر ما نشعر بالقلق ، فهو مجرد طلب إلغاء.

اعتراضات؟

لماذا يتم تقديم نوع استثناء مشتق جديد "يتنافس" مع TimeoutException الحالي بدلاً من ، على سبيل المثال ، طرح استثناء إلغاء يلتف على TimeoutException باعتباره الاستثناء الداخلي؟ إذا كان الهدف هو تمكين المستهلك من تحديد برمجيًا ما إذا كان الإلغاء بسبب انتهاء المهلة ، فهل يكفي ذلك؟ يبدو أنه ينقل نفس المعلومات ، دون الحاجة إلى مساحة سطح جديدة.

لماذا يتم تقديم نوع استثناء مشتق جديد "يتنافس" مع TimeoutException الحالي بدلاً من ، على سبيل المثال ، طرح استثناء إلغاء يلتف على TimeoutException باعتباره الاستثناء الداخلي

للراحة ، في الغالب. الكتابة أسهل وأكثر سهولة

catch(HttpTimeoutException)

من

catch(OperationCanceledException ex) when (ex.InnerException is TimeoutException)

ومع ذلك ، فإن كلتا الحالتين جيدة بالنسبة لي ، طالما أنه من السهل تحديد المهلة بشكل معقول.

قل ، طرح استثناء إلغاء يلتف TimeoutException كاستثناء داخلي؟

أعتقد أن هذا حل وسط جيد. سيساعد ذلك في إزالة الغموض عن سجلات الاستثناءات ، والتي كانت مصدر إزعاجي الأساسي عند التعامل مع هذه الأنواع من المهلات. من المحتمل أيضًا أن ينقل بشكل أفضل حقيقة أن HttpClient يقوم بإلغاء طلب ، بدلاً من المهلة التي يتم رفعها بواسطة المعالج الأساسي. أيضا ، لا توجد تغييرات كسر.

نخب:

  • سنقوم بتحديث هذا السيناريو للحصول على InnerException من TimeoutException مع رسالة للتسجيل / التشخيص الذي يميز بسهولة الإلغاء على أنه ناجم عن تشغيل المهلة.
  • سنقوم بتحديث الوثائق مع إرشادات حول الطرق التي يمكن للمرء أن يفحصها برمجيًا للتمييز بين الإلغاء: التحقق من TimeoutException ، باستخدام Timeout لانهائي واجتياز CancellationToken مع فترة المهلة ، إلخ.

نحن ندرك أن أي حل هنا يتضمن بعض الحلول الوسط ، ونعتقد أن هذا سيوفر مستوى جيدًا من التوافق مع الكود الحالي.

لماذا يتم تقديم نوع استثناء مشتق جديد "يتنافس" مع TimeoutException الحالي بدلاً من ، على سبيل المثال ، طرح استثناء إلغاء يلتف على TimeoutException باعتباره الاستثناء الداخلي

للراحة ، في الغالب. الكتابة أسهل وأكثر سهولة

catch(HttpTimeoutException)

من

catch(OperationCanceledException ex) when (ex.InnerException is TimeoutException)

ومع ذلك ، فإن كلتا الحالتين جيدة بالنسبة لي ، طالما أنه من السهل تحديد المهلة بشكل معقول.

scalablecory أشعر بالضيق لأنني قد فاتني المناقشة لبضع ساعات - تجربتي في توصيل هذا النوع من الأشياء مع مطوري LoB .NET العامين هي أن اصطياد HttpTimeoutException المشتق أسهل طريقة لفهم / تبني الناس من الاضطرار إلى ذلك تذكر استخدام مرشح استثناء في استثناء داخلي. لا يعرف الجميع حتى ما هو مرشح الاستثناء.

في الوقت نفسه ، أدرك تمامًا أن هذا هو أحد تلك السيناريوهات حيث لا يوجد حل واحد واضح للفوز / عدم المساومة ، كما قلت.

اتفقنا على هذه النقطة ericsampson ولكن هذا من شأنه أن يكسر التغيير للعديد من المستخدمين الحاليين. كما ذكر scalablecory ، فقد قمنا بالتسوية لإجراء تحسين مع الحد من ضرر التوافق.

عندما أفكر في الاستثناءات ، بشكل عام ، فإنني أعتبر نهج الالتفاف أفضل. اشتقاق الاستثناء من OperationCanceledException يجعل هذا الاستثناء متاحًا فقط في الاستخدام غير المتزامن. وحتى أنه ضيق على المهام. كما رأينا في الماضي ، كان هناك العديد من التطورات في الأساليب غير المتزامنة وأنا أعتبر المهمة بمثابة تفاصيل تنفيذ ولكن TimeoutException ، على سبيل المثال ، جزء من مفهوم المقبس الذي لن يتغير.

اتفقنا على هذه النقطة ericsampson ولكن هذا من شأنه أن يكسر التغيير للعديد من المستخدمين الحاليين. كما ذكر scalablecory ، فقد قمنا بالتسوية لإجراء تحسين مع الحد من ضرر التوافق.

على الرغم من أنني لا أختلف بالضرورة مع خيار التغليف ، أعتقد أنه من الجدير الإشارة إلى أنه - بقدر ما فهمت - لا تكمن المشكلة في أن الخيار المشتق هو تغيير فاصل ، بل أن خيار الالتفاف أبسط. كما ذكر stephentoub سابقًا في المناقشة ، لا يعتبر طرح استثناء مشتق تغييرًا فاصلًا وفقًا لإرشادات corefx.

اشتقاق HttpTimeoutException من TaskCanceledException ينتهك علاقة "هي" بين هذين الاستثناءين. سيظل يجعل كود الاتصال يعتقد أن الإلغاء حدث ، ما لم يتعامل بشكل خاص مع HttpTimeoutException. هذا هو في الأساس نفس التعامل الذي يتعين علينا القيام به في الوقت الحالي عندما نتحقق من إلغاء رمز الإلغاء لتحديد ما إذا كانت مهلة أم لا. علاوة على ذلك ، فإن وجود استثناءين للمهلة في المكتبة الأساسية أمر محير.
لن توفر إضافة TimeoutException كاستثناء داخلي لـ TaskCanceledException أي معلومات إضافية في معظم الحالات ، حيث يمكننا بالفعل التحقق من رمز الإلغاء وتحديد ما إذا كانت المهلة قد انتهت أم لا.

أعتقد أن الحل المعقول الوحيد هو تغيير الاستثناء الذي تم إلقاؤه في timeout إلى TimeoutException. نعم ، سيكون تغييرًا مفاجئًا ، لكن المشكلة تمتد بالفعل إلى العديد من الإصدارات الرئيسية والتغييرات العاجلة هي سبب الإصدارات الرئيسية.

هل يمكن تحديث الوثائق الخاصة بالإصدارات الحالية للإشارة إلى أن الأساليب يمكن أن تؤدي إلى ظهور TaskCanceledException و / أو OperationCanceledException (كلا النوعين الملموسين يبدو أنهما محتملان) عند حدوث انتهاء المهلة؟ تشير الوثائق حاليًا إلى صفقات HttpRequestException مع انتهاء المهلة ، وهو أمر غير صحيح ومضلل.

qidydl هذه هي الخطة ... سوف توثق بشكل كامل أي طرق يمكن أن تظهر بها المهلات وكيفية توضيح التفاصيل بها.

شكرًا alnikola وscalablecory و davidsh و karelz وكل من شارك في هذه المناقشة / التنفيذ ، أنا أقدر ذلك حقًا.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

matty-hall picture matty-hall  ·  3تعليقات

btecu picture btecu  ·  3تعليقات

bencz picture bencz  ·  3تعليقات

jchannon picture jchannon  ·  3تعليقات

omariom picture omariom  ·  3تعليقات