जब ब्राउज़र अनुरोध को रद्द कर देता है तो ASP.NET वेब एपीआई ऑपरेशनकेंक्लिड अपवाद


119

जब कोई उपयोगकर्ता किसी पेज को लोड करता है, तो वह एक या एक से अधिक ajax अनुरोध करता है, जो ASP.NET वेब एपीआई 2 नियंत्रकों को हिट करता है। यदि उपयोगकर्ता किसी अन्य पृष्ठ पर नेविगेट करता है, तो इन अजाक्स अनुरोधों को पूरा करने से पहले, ब्राउज़र द्वारा अनुरोधों को रद्द कर दिया जाता है। हमारा ELMAH HttpModule तब प्रत्येक रद्द किए गए अनुरोध के लिए दो त्रुटियां करता है:

त्रुटि 1:

System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()

त्रुटि 2:

System.OperationCanceledException: The operation was canceled.
   at System.Threading.CancellationToken.ThrowIfCancellationRequested()
   at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.WebHost.HttpControllerHandler.<CopyResponseAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.WebHost.HttpControllerHandler.<ProcessRequestAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.TaskAsyncHelper.EndTask(IAsyncResult ar)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

स्टैकट्रेस को देखते हुए, मैं देखता हूं कि अपवाद यहां से फेंका जा रहा है: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http.WhatHost/HttpControllerHandler.cs# L413

मेरा सवाल है: मैं इन अपवादों को कैसे संभाल और अनदेखा कर सकता हूं?

यह उपयोगकर्ता कोड के बाहर प्रतीत होता है ...

टिप्पणियाँ:

  • मैं ASP.NET वेब API 2 का उपयोग कर रहा हूं
  • वेब एपीआई एंडपॉइंट्स async और गैर- async विधियों का मिश्रण हैं।
  • कोई फर्क नहीं पड़ता कि मैं त्रुटि लॉगिंग कहां जोड़ता हूं, मैं उपयोगकर्ता कोड में अपवाद को पकड़ने में असमर्थ हूं

1
हमने कताना पुस्तकालयों के वर्तमान संस्करण के साथ ही अपवाद (टास्ककैन्लेड ​​एक्सेप्शन और ऑपरेशन कैन्सेलेड अपवाद) को देखा है।
डेविड

मुझे कुछ और विवरण मिले हैं जब दोनों अपवाद होते हैं और यह पता लगाया जाता है कि यह समाधान केवल उनमें से एक के खिलाफ काम करता है। यहाँ कुछ विवरण हैं: stackoverflow.com/questions/22157596/…
Ilya चेरनोमोर्डिक

जवाबों:


78

यह ASP.NET वेब API 2 में एक बग है और दुर्भाग्य से, मुझे नहीं लगता कि कोई वर्कअराउंड है जो हमेशा सफल होगा। हमने इसे अपने पक्ष में ठीक करने के लिए एक बग दर्ज किया ।

अंततः, समस्या यह है कि हम इस मामले में ASP.NET को रद्द किए गए कार्य को वापस करते हैं, और ASP.NET एक रद्द किए गए कार्य को एक अनछुए अपवाद की तरह मानता है (यह एप्लिकेशन इवेंट लॉग में समस्या को लॉग करता है)।

इस बीच, आप नीचे दिए गए कोड की तरह कुछ आज़मा सकते हैं। यह एक शीर्ष-स्तरीय संदेश हैंडलर जोड़ता है जो उस सामग्री को हटा देता है जब कैंसलेशन टोकन फायर हो जाता है। यदि प्रतिक्रिया में कोई सामग्री नहीं है, तो बग को ट्रिगर नहीं किया जाना चाहिए। अभी भी एक छोटी सी संभावना है कि यह हो सकता है, क्योंकि संदेश हैंडलर रद्द करने के टोकन को चेक करने के बाद ही ग्राहक सही डिस्कनेक्ट कर सकता है, लेकिन इससे पहले कि उच्च-स्तरीय वेब एपीआई कोड समान चेक करता है। लेकिन मुझे लगता है कि यह ज्यादातर मामलों में मदद करेगा।

डेविड

config.MessageHandlers.Add(new CancelledTaskBugWorkaroundMessageHandler());

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

        // Try to suppress response content when the cancellation token has fired; ASP.NET will log to the Application event log if there's content in this case.
        if (cancellationToken.IsCancellationRequested)
        {
            return new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }

        return response;
    }
}

2
अद्यतन के रूप में, यह कुछ अनुरोधों को कैप्चर करता है। हम अभी भी अपने लॉग में काफी कुछ देखते हैं। काम के लिए धन्यवाद-आसपास। एक तय करने के लिए आगे देख रहे हैं।
बेट्स वेस्टमोरलैंड

2
@ किरनचल्ला - मैं पुष्टि कर सकता हूं कि 5.2.2 में अपग्रेड अभी भी ये त्रुटियां हैं।
नाइटफॉक्स

2
फिर भी मुझे त्रुटि मिल रही है। मैंने सुझाव के ऊपर, किसी भी अन्य सुराग का उपयोग किया है।
M2012

3
जब मैंने ऊपर की सिफारिश की कोशिश की, तब भी मुझे अपवाद प्राप्त हुए जब अनुरोध को पारित होने से पहले ही रद्द कर दिया गया था SendAsync(आप इसे F5अपने यूआरएल में अनुरोध करने वाले यूआरएल पर ब्राउज़र में पकड़कर अनुकरण कर सकते हैं । मैंने इस मुद्दे को भी हल किया है। if (cancellationToken.IsCancellationRequested)कॉल के ऊपर चेक को जोड़ने पर SendAsync। अब अपवाद तब दिखाई नहीं देते हैं जब ब्राउज़र जल्दी से अनुरोध को रद्द कर देता है।
seangwright

2
मुझे कुछ और विवरण मिले हैं जब दोनों अपवाद होते हैं और यह पता लगाया जाता है कि यह समाधान केवल उनमें से एक के खिलाफ काम करता है। यहाँ कुछ विवरण हैं: stackoverflow.com/a/51514604/1671558
इल्या चेर्नोमोर्डिक

17

WebApi के लिए एक अपवाद लकड़हारा लागू करते समय, System.Web.Http.ExceptionHandling.ExceptionLoggerExceptionFilter बनाने के बजाय कक्षा का विस्तार करने की अनुशंसा की जाती है । WebApi इंटर्नल रद्द अनुरोधों के लिए अपवाद विधि के लॉग विधि को कॉल नहीं करेगा (हालाँकि, अपवाद फ़िल्टर उन्हें मिल जाएगा)। यह डिजाइन द्वारा है।

HttpConfiguration.Services.Add(typeof(IExceptionLogger), myWebApiExceptionLogger); 

ऐसा लगता है कि इस दृष्टिकोण के साथ समस्या यह है कि त्रुटि अभी भी Global.asax त्रुटि हैंडलिंग में पॉप अप करती है ... घटना हालांकि यह अपवाद हैंडलर को नहीं भेजी जाती है
इल्या चेर्नोमोर्डिक

14

यहाँ इस समस्या के लिए एक अन्य समाधान है। OWIN पाइप लाइन की शुरुआत में एक कस्टम OWIN मिडलवेयर जोड़ें OperationCanceledException:

#if !DEBUG
app.Use(async (ctx, next) =>
{
    try
    {
        await next();
    }
    catch (OperationCanceledException)
    {
    }
});
#endif

2
मुझे मुख्य रूप से OWIN संदर्भ से यह त्रुटि मिल रही थी और यह एक बेहतर लक्ष्य है
नितिनसिंह

3

आप डिफ़ॉल्ट TPL कार्य अपवाद हैंडलिंग व्यवहार को बदलने की कोशिश कर सकते हैं web.config:

<configuration> 
    <runtime> 
        <ThrowUnobservedTaskExceptions enabled="true"/> 
    </runtime> 
</configuration>

फिर आपके वेब ऐप में एक staticक्लास (एक staticकंस्ट्रक्टर के साथ ) है, जो हैंडल करेगा AppDomain.UnhandledException

हालाँकि, ऐसा प्रतीत होता है कि यह अपवाद वास्तव में ASP.NET वेब एपीआई रनटाइम के अंदर कहीं और संभाला जा रहा है , इससे पहले कि आपके पास इसे अपने कोड से संभालने का मौका भी हो।

इस मामले में, आपको इसे 1 मौका अपवाद के रूप में पकड़ने में सक्षम होना चाहिए AppDomain.CurrentDomain.FirstChanceException, यहां , यह है कि कैसे । मैं समझता हूं कि यह वह नहीं है जो आप ढूंढ रहे हैं।


1
दोनों में से किसी ने भी मुझे अपवाद को संभालने की अनुमति नहीं दी।
बेट्स वेस्टमोरलैंड

@ बेट्सवेस्टरलैंड, भी नहीं FirstChanceException? क्या आपने इसे स्थिर वर्ग के साथ संभालने की कोशिश की है जो HTTP अनुरोधों पर कायम है?
noseratio

2
समस्या मैं इसे पकड़ने के लिए हल करने की कोशिश कर रहा हूं, और इन अपवादों को अनदेखा कर रहा हूं। उपयोग करना AppDomain.UnhandledExceptionया AppDomain.CurrentDomain.FirstChanceExceptionमुझे अपवाद का निरीक्षण करने की अनुमति दे सकता है, लेकिन पकड़ नहीं और अनदेखा कर सकता है। मैंने इन अपवादों को चिह्नित करने का कोई तरीका नहीं देखा क्योंकि इनमें से किसी भी दृष्टिकोण का उपयोग किया गया था। अगर मैं ग़लत हूं तो मेरी गलती सुझाएं।
बेट्स वेस्टमोरलैंड

2

मुझे कभी-कभी अपने वेब एपीआई 2 एप्लिकेशन में समान 2 अपवाद मिलते हैं, हालांकि मैं उन्हें सामान्य अपवाद फ़िल्टर का उपयोग करके और Application_Errorविधि के साथ पकड़ सकता हूं ।Global.asax.cs

मजेदार बात यह है, हालांकि, मैं इन अपवादों को नहीं पकड़ना पसंद करता हूं, क्योंकि मैं हमेशा सभी अखंडित अपवादों को लॉग करता हूं जो एप्लिकेशन को क्रैश कर सकते हैं (ये 2, हालांकि, मेरे लिए अप्रासंगिक हैं और जाहिर तौर पर कम से कम नहीं होना चाहिए या दुर्घटना नहीं होनी चाहिए। यह), लेकिन मैं गलत हो सकता है)। मुझे लगता है कि इन त्रुटियों को क्लाइंट से कुछ समय समाप्ति या स्पष्ट रद्दीकरण के कारण दिखाई देता है, लेकिन मुझे उम्मीद है कि उन्हें ASP.NET फ्रेमवर्क के अंदर इलाज किया जाएगा और इसके बाहर प्रचारित अपवाद के रूप में प्रचारित नहीं किया जाएगा।


मेरे मामले में, ये अपवाद होते हैं क्योंकि ब्राउज़र अनुरोध को रद्द कर देता है क्योंकि उपयोगकर्ता एक नए यूआरएल पर नेविगेट करता है।
बेट्स वेस्टमोरलैंड

1
समझा। मेरे मामले में, अनुरोध WinHTTPएक ब्राउज़र से नहीं बल्कि एपीआई के माध्यम से जारी किए जाते हैं ।
गैब्रियल एस।

2

मुझे इस त्रुटि पर थोड़ा और विवरण मिला है। 2 संभावित अपवाद हैं जो हो सकते हैं:

  1. OperationCanceledException
  2. TaskCanceledException

यदि कनेक्शन कोड में आपके कोड को निष्पादित करता है (या संभवतः उस के आसपास भी कुछ सिस्टम कोड) तो पहले वाला होता है। जबकि दूसरा एक तब होता है जब कनेक्शन गिरा दिया जाता है जबकि निष्पादन एक विशेषता (जैसे AuthorizeAttribute) के अंदर होता है ।

तो प्रदान किए गए वर्कअराउंड आंशिक रूप से पहले अपवाद को कम करने में मदद करता है, यह दूसरे के साथ मदद करने के लिए कुछ भी नहीं करता है। उत्तरार्द्ध मामले में कॉल के TaskCanceledExceptionदौरान base.SendAsyncही होता है, बल्कि रद्द टोकन को सही पर सेट किया जा रहा है।

मैं इन्हें हल करने के दो तरीके देख सकता हूं:

  1. Global.asax में केवल दोनों अपवादों की अनदेखी। इसके बाद सवाल आता है कि क्या अचानक किसी महत्वपूर्ण चीज को अनदेखा करना संभव है?
  2. हैंडलर में एक अतिरिक्त कोशिश / कैच करना (हालांकि यह बुलेटप्रूफ नहीं है) अभी भी संभावना है TaskCanceledExceptionकि हम इसे अनदेखा कर देंगे जो हम लॉग इन करना चाहते हैं।

config.MessageHandlers.Add(new CancelledTaskBugWorkaroundMessageHandler());

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

            // Try to suppress response content when the cancellation token has fired; ASP.NET will log to the Application event log if there's content in this case.
            if (cancellationToken.IsCancellationRequested)
            {
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }
        }
        catch (TaskCancellationException)
        {
            // Ignore
        }

        return response;
    }
}

एकमात्र तरीका मुझे लगा कि हम गलत अपवादों को इंगित करने की कोशिश कर सकते हैं यदि स्टैकट्रेस में कुछ Asp.Net सामान हैं। हालांकि बहुत मजबूत नहीं लगता है।

PS यह है कि मैं इन त्रुटियों को कैसे फ़िल्टर करता हूं:

private static bool IsAspNetBugException(Exception exception)
{
    return
        (exception is TaskCanceledException || exception is OperationCanceledException) 
        &&
        exception.StackTrace.Contains("System.Web.HttpApplication.ExecuteStep");
}

1
आपके सुझाए गए कोड में, आप responseप्रयास के अंदर चर बनाते हैं और इसे कोशिश के बाहर लौटाते हैं। यह संभव काम नहीं कर सकता है? इसके अलावा आप कहाँ IsAspNetBugException का उपयोग करते हैं?
शाओफ

1
नहीं, यह काम नहीं कर सकता है, यह सिर्फ कोर्स के प्रयास / कैच ब्लॉक के बाहर घोषित किया जाना है और पूर्ण कार्य की तरह कुछ के साथ प्रारंभ किया गया है। यह सिर्फ उस समाधान का एक उदाहरण है जो वैसे भी बुलेटप्रूफ नहीं है। अन्य प्रश्न के लिए आप Global.Asax OnError हैंडलर में इसका उपयोग करते हैं। यदि आप अपने संदेशों को लॉग करने के लिए उस एक का उपयोग नहीं करते हैं, तो आपको वैसे भी चिंता करने की आवश्यकता नहीं है। यदि आप करते हैं, तो यह एक उदाहरण है कि आप सिस्टम से "गैर त्रुटियों" को कैसे फ़िल्टर करते हैं।
इलिया चेर्नोमोर्डिक

1

हम एक ही अपवाद प्राप्त कर रहे हैं, हमने @ dmatson के वर्कअराउंड का उपयोग करने की कोशिश की, लेकिन हम अभी भी कुछ अपवाद प्राप्त करेंगे। हमने हाल ही में इससे निपटा। हमने देखा कि कुछ विंडोज लॉग एक खतरनाक दर से बढ़ रहे हैं।

इसमें स्थित त्रुटि फ़ाइलें: C: \ Windows \ System32 \ LogFiles \ HTTPERR

अधिकांश त्रुटियां "टिमर_कॉन्नेनेटल" के लिए थीं। मैंने चारों ओर खोज की और ऐसा लगा कि वेब एप कॉल समाप्त होने के बावजूद, कनेक्शन अभी भी मूल कनेक्शन से दो मिनट पहले बना हुआ है।

मुझे लगा कि हमें प्रतिक्रिया में कनेक्शन बंद करने की कोशिश करनी चाहिए और देखना चाहिए कि क्या होता है।

मैंने response.Headers.ConnectionClose = true;SendAsync MessageHandler में जोड़ा और जो मैं बता सकता हूं कि क्लाइंट कनेक्शन बंद कर रहे हैं और हम इस समस्या का सामना नहीं कर रहे हैं।

मुझे पता है कि यह सबसे अच्छा समाधान नहीं है, लेकिन यह हमारे मामले में काम करता है। मुझे भी पूरा यकीन है कि प्रदर्शन-वार यह कुछ ऐसा नहीं है जो आप करना चाहते हैं यदि आपका एपीआई एक ही क्लाइंट से कई कॉल बैक-टू-बैक कर रहा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.