एक WPF आवेदन में विश्व स्तर पर अपवाद?


242

हम एक WPF आवेदन कर रहे हैं, जहां इसके कुछ भाग रनटाइम पर अपवाद फेंक सकते हैं। मैं विश्व स्तर पर किसी भी अनछुए अपवाद को पकड़ना चाहता हूं और उन्हें लॉग इन करना चाहता हूं, लेकिन अन्यथा प्रोग्राम निष्पादन जारी रखें जैसे कि कुछ भी नहीं हुआ (जैसे वीबी की तरह On Error Resume Next)।

क्या यह C # में संभव है? और यदि हां, तो वास्तव में मुझे अपवाद हैंडलिंग कोड डालने की आवश्यकता कहां होगी?

वर्तमान में मैं ऐसा कोई भी बिंदु नहीं देख सकता जहाँ मैं try/ a को लपेट सकूँ catchऔर जो सभी अपवादों को पकड़ सकता है। और तब भी मैं कैच की वजह से जो कुछ भी किया गया था उसे छोड़ देता। या मैं यहाँ बुरी तरह गलत दिशाओं में सोच रहा हूँ?

ईटीए: क्योंकि नीचे कई लोगों ने इसे इंगित किया है: आवेदन परमाणु ऊर्जा संयंत्रों को नियंत्रित करने के लिए नहीं है। यदि यह क्रैश होता है तो यह बहुत बड़ी बात नहीं है, लेकिन यादृच्छिक रूप से अपवाद जो कि ज्यादातर यूआई-संबंधित हैं, उस संदर्भ में एक उपद्रव हैं जहां इसका उपयोग किया जाएगा। उनमें से कुछ थे (और शायद अभी भी हैं) क्योंकि यह एक प्लगइन वास्तुकला का उपयोग करता है और दूसरों द्वारा बढ़ाया जा सकता है (उस मामले में भी; इसलिए कोई भी अनुभवी डेवलपर्स जो पूरी तरह से त्रुटि-मुक्त कोड लिखने में सक्षम नहीं हैं)।

अपवाद के रूप में जो पकड़े जाते हैं: मैं उन्हें लॉग फ़ाइल में लॉग करता हूं, जिसमें पूर्ण स्टैक ट्रेस भी शामिल है। यह उस अभ्यास का पूरा बिंदु था। बस उन लोगों का मुकाबला करने के लिए जो वीबी के ओआरएन पर मेरी सादृश्य को सचमुच ले जा रहे थे।

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

आवेदन के तत्काल उपयोग के लिए कई चीजें नहीं हैं जो एक अपवाद पर हो सकती हैं:

  • कोई अपवाद हैंडलिंग - त्रुटि संवाद और अनुप्रयोग से बाहर निकलना। प्रयोग को दोहराया जाना चाहिए, हालांकि किसी अन्य विषय के साथ होने की संभावना है। कोई त्रुटि लॉग नहीं की गई है, जो दुर्भाग्यपूर्ण है।
  • सामान्य अपवाद हैंडलिंग - सौम्य त्रुटि फंस गई, कोई नुकसान नहीं हुआ। विकास के दौरान हम जो भी त्रुटियां देख रहे थे, उससे यह सामान्य मामला होना चाहिए। इस तरह की त्रुटियों को अनदेखा करने के तत्काल परिणाम नहीं होने चाहिए; कोर डेटा संरचनाओं का अच्छी तरह से परीक्षण किया जाता है कि वे आसानी से इससे बच जाएंगे।
  • सामान्य अपवाद हैंडलिंग - गंभीर त्रुटि, संभवतः बाद में दुर्घटनाग्रस्त हो गई। ऐसा शायद ही कभी हो सकता है। हमने इसे अब तक कभी नहीं देखा है। त्रुटि वैसे भी लॉग होती है और क्रैश अपरिहार्य हो सकता है। तो यह वैचारिक रूप से पहले मामले के समान है। सिवाय इसके कि हमारे पास एक स्टैक ट्रेस है। और अधिकांश मामलों में उपयोगकर्ता नोटिस भी नहीं करेगा।

कार्यक्रम द्वारा उत्पन्न प्रयोग डेटा के लिए: एक गंभीर त्रुटि सबसे खराब होगी, जिसके कारण कोई डेटा रिकॉर्ड नहीं किया जाएगा। सूक्ष्म परिवर्तन जो कभी-कभी प्रयोग के परिणाम को बदल देते हैं वे बहुत कम संभावनाएं हैं। और उस स्थिति में भी, यदि परिणाम संदिग्ध प्रतीत होता है कि त्रुटि लॉग की गई थी; यदि यह कुल मिलाकर हो तो कोई भी डेटा बिंदु को फेंक सकता है।

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

साइड नोट: उस एप्लिकेशन के लिए ठीक एक उपयोगकर्ता है। यह विंडोज या ऑफिस जैसी कोई चीज नहीं है जो लाखों लोगों द्वारा उपयोग की जाती है, जहां उपयोगकर्ता को अपवाद बबल होने की लागत पहले से ही पहले से बहुत अलग होगी।


यह वास्तव में नहीं सोच रहा है - हाँ, आप शायद आवेदन से बाहर निकलना चाहते हैं। लेकिन, पहले अपने स्टैकट्रेस के साथ अपवाद लॉग करना अच्छा नहीं होगा? यदि आपको उपयोगकर्ता से मिला है, तो "मेरा बटन दबाते ही आपका एप्लिकेशन क्रैश हो गया", आप कभी भी समस्या का समाधान नहीं कर सकते क्योंकि आपके पास पर्याप्त जानकारी नहीं होगी। लेकिन यदि आपने पहली बार आवेदन को और अधिक सुखद तरीके से समाप्त करने से पहले अपवाद को लॉग इन किया है, तो आपके पास काफी अधिक जानकारी होगी।
रस

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

एक और पक्ष नोट: यदि आप इस दृष्टिकोण के साथ किसी भी क्रैश को रोकते हैं, तो उपयोगकर्ता इसे सबसे अधिक पसंद करेंगे।
लहजोन_ज

देखें विंडोज विजुअल स्टूडियो 2010 के लिए सी # में WPF में बिना क्रिया के अपवाद (संचालकों का सबसे पूरा संग्रह) नमूना हैंडलिंग । यह AppDomain.CurrentDomain.FirstChanceException, Application.DispatcherUnhandledException और AppDomain.CurrentDomain.UnhandledException सहित 5 उदाहरण हैं।
user34660

मैं यह जोड़ना चाहूंगा कि On Error Resume NextC # में VB जैसा कोड-फ्लो संभव नहीं है। एक Exception(सी # में "त्रुटियां" नहीं होने के बाद ) आप बस अगले बयान के साथ फिर से शुरू नहीं कर सकते हैं: निष्पादन एक catchब्लॉक में जारी रहेगा - या नीचे दिए गए उत्तरों में वर्णित घटना संचालकों में से एक में।
माइक

जवाबों:


191

का प्रयोग करें Application.DispatcherUnhandledException Eventइस प्रश्न को सारांश के लिए देखें ( ड्रू नोक के उत्तर देखें )।

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


धन्यवाद। और हां, मैं जानता हूं कि ऐसे अपवाद हैं जिनसे मैं उबर नहीं सकता, लेकिन जो लोग हो सकते हैं उनमें से अधिकांश इस मामले में सौम्य हैं।
जॉय

14
यदि आपका अपवाद किसी बैकग्राउंड थ्रेड पर होता है (थ्रेडपूल का उपयोग करके। QueueUserWorkItem), तो यह काम नहीं करेगा।
सिजमन रोजगा

@ सिज़: अच्छी बात है, लेकिन उन लोगों को कार्यक्षेत्र में एक सामान्य कोशिश ब्लॉक के साथ संभाला जा सकता है, नहीं?
डेविड श्मिट

1
@PitiOngmongkolkul: हैंडलर को मुख्य लूप से ईवेंट कहा जाता है। जब ईवेंट हैंडलर लौटता है, तो आपका ऐप सामान्य रूप से जारी रहता है।
डेविड श्मिट

4
ऐसा लगता है कि हमें e.andled = true सेट करने की आवश्यकता है, जहाँ e एक डिस्पैचररहैंडल्ड एक्ससेप्शन EventArgs है, डिफ़ॉल्ट हैंडलर को छोड़ने के लिए जो प्रोग्राम्स को छोड़ देता है। msdn.microsoft.com/en-us/library/…
पीटी ओंगमॉन्गकोलकुल

55

का उपयोग कर उदाहरण कोड NLog कि से फेंका अपवाद पकड़ेगा AppDomain में सभी धागे से, यूआई डिस्पैचर धागा और से async कार्यों :

App.xaml.cs:

public partial class App : Application
{
    private static Logger _logger = LogManager.GetCurrentClassLogger();

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        SetupExceptionHandling();
    }

    private void SetupExceptionHandling()
    {
        AppDomain.CurrentDomain.UnhandledException += (s, e) =>
            LogUnhandledException((Exception)e.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");

        DispatcherUnhandledException += (s, e) =>
        {
            LogUnhandledException(e.Exception, "Application.Current.DispatcherUnhandledException");
            e.Handled = true;
        };

        TaskScheduler.UnobservedTaskException += (s, e) =>
        {
            LogUnhandledException(e.Exception, "TaskScheduler.UnobservedTaskException");
            e.SetObserved();
        };
    }

    private void LogUnhandledException(Exception exception, string source)
    {
        string message = $"Unhandled exception ({source})";
        try
        {
            System.Reflection.AssemblyName assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
            message = string.Format("Unhandled exception in {0} v{1}", assemblyName.Name, assemblyName.Version);
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "Exception in LogUnhandledException");
        }
        finally
        {
            _logger.Error(exception, message);
        }
    }

10
यह यहाँ सबसे पूरा जवाब है! Tak अनुसूचक अपवाद शामिल हैं। मेरे लिए सबसे अच्छा, स्वच्छ और सरल कोड।
निकोला जोविच

3
हाल ही में मेरे पास एक ग्राहक पर एक App.config भ्रष्टाचार था, और उसका ऐप भी शुरू नहीं हो रहा था क्योंकि NLog App.config से पढ़ने की कोशिश कर रहा था और एक अपवाद को फेंक दिया। चूंकि यह अपवाद स्थिर लकड़हारा इनिशियलाइज़र में था, इसलिए इसे UnhandledExceptionहैंडलर द्वारा पकड़ा नहीं जा रहा था । मुझे विंडोज इवेंट लॉग व्यूअर को देखना था कि क्या हो रहा था ...
हेल्टनबिकर

मैं सेट की सिफारिश e.Handled = true;पर UnhandledExceptionकि आवेदन यूआई अपवाद पर क्रैश नहीं करेंगे
Apfelkuacha

30

AppDomain.UnhandledException घटना

यह घटना बिना किसी अपवाद के सूचना प्रदान करती है। यह एप्लिकेशन को अपवाद के बारे में जानकारी लॉग करने की अनुमति देता है इससे पहले कि सिस्टम डिफॉल्ट हैंडलर उपयोगकर्ता को अपवाद रिपोर्ट करता है और एप्लिकेशन को समाप्त कर देता है।

   public App()
   {
      AppDomain currentDomain = AppDomain.CurrentDomain;
      currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);    
   }

   static void MyHandler(object sender, UnhandledExceptionEventArgs args) 
   {
      Exception e = (Exception) args.ExceptionObject;
      Console.WriteLine("MyHandler caught : " + e.Message);
      Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
   }

यदि UnhandledException इवेंट को डिफ़ॉल्ट एप्लिकेशन डोमेन में संभाला जाता है, तो इसे किसी भी थ्रेड में किसी भी अनहेल्ड अपवाद के लिए उठाया जाता है, चाहे कोई भी एप्लिकेशन डोमेन थ्रेड प्रारंभ किया गया हो। यदि थ्रेड किसी ऐसे अनुप्रयोग डोमेन में प्रारंभ हुआ जिसमें UnhandledException के लिए ईवेंट हैंडलर है। ईवेंट को उस एप्लिकेशन डोमेन में उठाया जाता है। यदि वह एप्लिकेशन डोमेन डिफ़ॉल्ट एप्लिकेशन डोमेन नहीं है, और डिफ़ॉल्ट एप्लिकेशन डोमेन में एक इवेंट हैंडलर भी है, तो इवेंट को दोनों एप्लिकेशन डोमेन में उठाया जाता है।

उदाहरण के लिए, मान लें कि एप्लिकेशन डोमेन "AD1" में एक थ्रेड शुरू होता है, एप्लिकेशन डोमेन "AD2" में एक विधि कहता है, और वहां से एप्लिकेशन डोमेन "AD3" में एक विधि कॉल करता है, जहां यह एक अपवाद फेंकता है। पहला एप्लीकेशन डोमेन जिसमें अनहेल्डडैसेप्शन ईवेंट को उठाया जा सकता है, वह है "AD1"। यदि वह एप्लिकेशन डोमेन डिफ़ॉल्ट एप्लिकेशन डोमेन नहीं है, तो इवेंट को डिफ़ॉल्ट एप्लिकेशन डोमेन में भी उठाया जा सकता है।


आपके द्वारा बताए गए URL से कॉपी करना (जो कंसोल एप्लिकेशन और केवल मेरे विचार से WinForms एप्लिकेशन की बात करता है): ".NET फ्रेमवर्क 4 से शुरू होकर, यह घटना अपवादों के लिए नहीं उठाई जाती है जो प्रक्रिया की स्थिति को भ्रष्ट करती है, जैसे स्टैक ओवरफ्लो या पहुँच उल्लंघन, जब तक कि ईवेंट हैंडलर सुरक्षा-महत्वपूर्ण नहीं है और उसके पास हैंडलेप्रोसेसकोर्पोरेटेडस्टैटेस्ट अपवाद हैं। "
जॉर्ज बिरबिलिस

1
@GeorgeBirbilis: आप ऐप कंस्ट्रक्टर में अनहैंडल्ड अपवाद घटना के लिए सदस्यता ले सकते हैं।
चरिथज

18

इसके अलावा दूसरों ने यहां क्या उल्लेख किया है, ध्यान दें कि Application.DispatcherUnhandledException(और इसके सिमिलर्स ) का संयोजन

<configuration>
  <runtime>  
    <legacyUnhandledExceptionPolicy enabled="1" />
  </runtime>
</configuration>

में app.configआवेदन बंद करने से अपने माध्यमिक सूत्र अपवाद को रोकने जाएगा।


2

यहाँ का उपयोग कर पूरा उदाहरण है NLog

using NLog;
using System;
using System.Windows;

namespace MyApp
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private static Logger logger = LogManager.GetCurrentClassLogger();

        public App()
        {
            var currentDomain = AppDomain.CurrentDomain;
            currentDomain.UnhandledException += CurrentDomain_UnhandledException;
        }

        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var ex = (Exception)e.ExceptionObject;
            logger.Error("UnhandledException caught : " + ex.Message);
            logger.Error("UnhandledException StackTrace : " + ex.StackTrace);
            logger.Fatal("Runtime terminating: {0}", e.IsTerminating);
        }        
    }


}

-4

जैसे "वीबी की त्रुटि को फिर से शुरू करें?" जो डरावना लगता है। पहली सिफारिश यह नहीं है। दूसरी सिफारिश यह नहीं है और इसके बारे में मत सोचो। आपको अपने दोषों को बेहतर ढंग से अलग करना होगा। इस समस्या से कैसे संपर्क करें, यह इस बात पर निर्भर करता है कि आप किस तरह से संरचित हैं। यदि आप MVC या जैसे पैटर्न का उपयोग कर रहे हैं तो यह बहुत मुश्किल नहीं होना चाहिए और निश्चित रूप से वैश्विक अपवाद निगलने की आवश्यकता नहीं होगी। दूसरे, log4net की तरह एक अच्छे लॉगिंग लाइब्रेरी की तलाश करें या ट्रेसिंग का उपयोग करें। हमें अधिक विवरणों को जानना होगा जैसे कि आप किस प्रकार के अपवादों के बारे में बात कर रहे हैं और आपके आवेदन के कुछ हिस्सों के परिणामस्वरूप अपवादों को फेंका जा सकता है।


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

9
मैं समझता हूं, लेकिन आपको अपवाद के बाद जारी रखने के लिए बहुत सतर्क रहना होगा कि आप जांच नहीं करते हैं, डेटा भ्रष्टाचार की संभावना है और आगे विचार करने के लिए।
बॉबीशाफ्टो

3
मैं बॉबीशाफ्टो से सहमत हूं। यह जाने का सही तरीका नहीं है। एप्लिकेशन को क्रैश होने दें। अगर गलती कुछ प्लगइन पर है, तो किसी को ठीक करने या प्लगइन को ठीक करने के लिए प्राप्त करें। इसे छोड़ना बेहद खतरनाक है। आपको अजीब साइड इफेक्ट्स मिलेंगे और एक बिंदु पर पहुंचेंगे जहां आप अपने आवेदन में हो रहे बगों के लिए तार्किक स्पष्टीकरण नहीं पा सकेंगे।

1
मैंने उस प्रश्न पर थोड़ा विस्तार किया। मुझे इसमें शामिल जोखिमों का पता है और उस विशेष एप्लिकेशन के लिए इसे स्वीकार्य माना गया था। और यूआई कुछ सीमा के बाहर सरल के रूप में कुछ के लिए आवेदन को निरस्त करते हुए, जबकि यूआई ने कुछ अच्छा एनीमेशन करने की कोशिश की, ओवरकिल और अनावश्यक है। हां, मुझे सटीक कारण नहीं पता है, लेकिन हमारे पास दावा करने के लिए डेटा है कि त्रुटि के मामलों का विशाल बहुमत सौम्य है। हम जिस गंभीर समस्या के लिए आवेदन कर रहे हैं वह दुर्घटना का कारण बन सकती है, लेकिन वैश्विक अपवाद से निपटने के बिना वैसे भी क्या हुआ होगा।
जोए

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