कंसोल अनुप्रयोग में .NET वैश्विक अपवाद हैंडलर


199

प्रश्न: मैं अपने कंसोल एप्लिकेशन में बिना किसी अपवाद के वैश्विक अपवाद हैंडलर को परिभाषित करना चाहता हूं। Asp.net में, कोई Global.asax में, और विंडोज़ एप्लिकेशन / सेवाओं में एक को परिभाषित कर सकता है, एक नीचे के रूप में परिभाषित कर सकता है

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);

लेकिन मैं कंसोल एप्लिकेशन के लिए वैश्विक अपवाद हैंडलर को कैसे परिभाषित कर सकता हूं?
currentDomain काम नहीं कर रहा है (.NET 2.0)?

संपादित करें:

अर्ग, बेवकूफ गलती।
VB.NET में, किसी को CurrentDomain के सामने "AddHandler" कीवर्ड जोड़ने की आवश्यकता होती है, या किसी को IntelliSense में UnhandledException इवेंट नहीं दिखता है ...
ऐसा इसलिए है क्योंकि VB.NET और C # कंपाइलर ईवेंट को आसानी से हैंडल करते हैं।

जवाबों:


283

नहीं, ऐसा करने का सही तरीका है। यह बिल्कुल वैसा ही काम करना चाहिए जैसा कि आप शायद कुछ काम कर सकते हैं:

using System;

class Program {
    static void Main(string[] args) {
        System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
        throw new Exception("Kaboom");
    }

    static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) {
        Console.WriteLine(e.ExceptionObject.ToString());
        Console.WriteLine("Press Enter to continue");
        Console.ReadLine();
        Environment.Exit(1);
    }
}

ध्यान रखें कि आप इस तरह से घबराने से उत्पन्न प्रकार और फ़ाइल लोड अपवादों को नहीं पकड़ सकते। आपके मेन () विधि के चलने से पहले वे होते हैं। जिन लोगों को घबराहट में देरी करने की आवश्यकता होती है, उन्हें पकड़ना, जोखिम भरा कोड को दूसरी विधि में ले जाना और [MethodImpl (MethodImplOptions.NoInlining)] को लागू करना।


3
आपने जो यहां प्रस्तावित किया था, उसे मैंने लागू किया, लेकिन मैं आवेदन से बाहर नहीं निकलना चाहता। मैं बस इसे लॉग इन करना चाहता हूं, और इस प्रक्रिया को जारी रखें (बिना Console.ReadLine()या किसी अन्य प्रोग्राम के प्रवाह में गड़बड़ी के। लेकिन मुझे जो कुछ भी मिलता है वह बार-बार अपवाद है, और फिर से।

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

6
यह सबसे निश्चित रूप से करता है! हम यहां Application.ThreadException इवेंट के बारे में बात नहीं कर रहे हैं।
हंस पासेंट

4
मुझे लगता है कि इस उत्तर को समझने और उत्तर में टिप्पणियों को समझने की कुंजी यह है कि यह कोड अपवाद का पता लगाने के लिए अब प्रदर्शित होता है, लेकिन पूरी तरह से "हैंडल" नहीं करता है जैसा कि आप एक सामान्य कोशिश / पकड़ ब्लॉक में कर सकते हैं जहां आपके पास जारी रखने का विकल्प है । विवरण के लिए मेरा अन्य उत्तर देखें। यदि आप इस तरह से अपवाद को "हैंडल" करते हैं, तो आपके पास कोई विकल्प नहीं होता है कि जब कोई अपवाद किसी अन्य थ्रेड पर होता है, तो उसे जारी रखने का विकल्प न हो। उस अर्थ में, यह कहा जा सकता है कि यह उत्तर अपवाद को पूरी तरह से "हैंडल" नहीं करता है यदि "हैंडल" से आपका मतलब "प्रक्रिया और जारी रहना" है।
BlueMonkMN

4
विभिन्न थ्रेड्स में चलने के लिए बहुत सारी प्रौद्योगिकियाँ नहीं हैं। उदाहरण के लिए, टास्क पैरेलल लाइब्रेरी (TPL) के पास बिना किसी अपवाद के पकड़ने का अपना तरीका है। इसलिए, यह कहना कि यह सभी स्थितियों के लिए काम नहीं करता है, एक प्रकार का आलसी है, C # में सब कुछ के लिए कोई एक जगह नहीं है, लेकिन सभी आपके द्वारा उपयोग की जाने वाली तकनीकों के आधार पर आप विभिन्न स्थानों पर हुक कर सकते हैं।
डौग

23

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

static bool exiting = false;

static void Main(string[] args)
{
   try
   {
      System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
      demo.Start();
      Console.ReadLine();
      exiting = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine("Caught an exception");
   }
}

static void DemoThread()
{
   for(int i = 5; i >= 0; i--)
   {
      Console.Write("24/{0} =", i);
      Console.Out.Flush();
      Console.WriteLine("{0}", 24 / i);
      System.Threading.Thread.Sleep(1000);
      if (exiting) return;
   }
}

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

static bool exiting = false;

static void Main(string[] args)
{
   try
   {
      System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
      AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
      demo.Start();
      Console.ReadLine();
      exiting = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine("Caught an exception");
   }
}

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
   Console.WriteLine("Notified of a thread exception... application is terminating.");
}

static void DemoThread()
{
   for(int i = 5; i >= 0; i--)
   {
      Console.Write("24/{0} =", i);
      Console.Out.Flush();
      Console.WriteLine("{0}", 24 / i);
      System.Threading.Thread.Sleep(1000);
      if (exiting) return;
   }
}

इसलिए मेरी राय में, सांत्वना एप्लिकेशन में इसे संभालने का सबसे साफ तरीका यह सुनिश्चित करना है कि हर धागे के मूल में एक अपवाद हैंडलर है:

static bool exiting = false;

static void Main(string[] args)
{
   try
   {
      System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
      demo.Start();
      Console.ReadLine();
      exiting = true;
   }
   catch (Exception ex)
   {
      Console.WriteLine("Caught an exception");
   }
}

static void DemoThread()
{
   try
   {
      for (int i = 5; i >= 0; i--)
      {
         Console.Write("24/{0} =", i);
         Console.Out.Flush();
         Console.WriteLine("{0}", 24 / i);
         System.Threading.Thread.Sleep(1000);
         if (exiting) return;
      }
   }
   catch (Exception ex)
   {
      Console.WriteLine("Caught an exception on the other thread");
   }
}

TRY CATCH अप्रत्याशित त्रुटियों के लिए रिलीज़ मोड में काम नहीं करता है: /
Muflix

12

आपको थ्रेड्स से अपवादों को भी संभालने की आवश्यकता है:

static void Main(string[] args) {
Application.ThreadException += MYThreadHandler;
}

private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e)
{
    Console.WriteLine(e.Exception.StackTrace);
}

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


1

मुझे सिर्फ एक पुराना VB.NET कंसोल एप्लिकेशन विरासत में मिला है और एक ग्लोबल एक्सेप्शन हैंडलर स्थापित करने की आवश्यकता है। चूँकि इस प्रश्न में कुछ समय VB.NET का उल्लेख है और इसे VB.NET के साथ टैग किया गया है, लेकिन यहाँ अन्य सभी उत्तर C # में हैं, मुझे लगा कि मैं VB.NET अनुप्रयोग के लिए भी सटीक वाक्यविन्यास जोड़ूँगा।

Public Sub Main()
    REM Set up Global Unhandled Exception Handler.
    AddHandler System.AppDomain.CurrentDomain.UnhandledException, AddressOf MyUnhandledExceptionEvent

    REM Do other stuff
End Sub

Public Sub MyUnhandledExceptionEvent(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
    REM Log Exception here and do whatever else is needed
End Sub

मैंने REMयहाँ एकल उद्धरण के बजाय टिप्पणी मार्कर का उपयोग किया, क्योंकि स्टैक ओवरफ्लो के साथ थोड़ा बेहतर हाइलाइटिंग सिंटैक्स को संभालने के लिए लग रहा था REM


-13

आप MSDN डॉक्स के लिए .Net 2.0 के अनुसार काम करना चाह रहे हैं। आप कंसोल ऐप के लिए अपने प्रवेश बिंदु के चारों ओर मुख्य रूप से एक कोशिश कर सकते हैं / पकड़ सकते हैं।

static void Main(string[] args)
{
    try
    {
        // Start Working
    }
    catch (Exception ex)
    {
        // Output/Log Exception
    }
    finally
    {
        // Clean Up If Needed
    }
}

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

BlueMonkMN द्वारा इंगित किए गए थ्रेड्स के बारे में बिंदु को स्पष्ट करने के लिए संपादित और उनके उत्तर में विस्तार से दिखाया गया है।


1
अपवाद वास्तव में अभी भी मुख्य () ब्लॉक के बाहर फेंक सकते हैं, दुर्भाग्य से। यह वास्तव में एक "सभी को पकड़" नहीं है जैसा आप सोच सकते हैं। देखिए @ हंस का जवाब।
माइक एटलस

@ माइक प्रथम ने कहा कि वह जिस तरह से कर रहा है वह सही है, और यह कि वह मुख्य में कोशिश / पकड़ बना सकता है। मुझे यकीन नहीं है कि आपने (या किसी और ने) मुझे वोट क्यों दिया, जब मैं हंस के साथ सहमत था, बस एक और जवाब दे रहा था जिसके लिए मुझे चेक मिलने की उम्मीद नहीं थी। यह वास्तव में उचित नहीं है, और फिर यह कहना कि बिना किसी प्रमाण के कोई विकल्प प्रदान किए बिना विकल्प गलत है, एक अपवाद जिसे AppDomain UnhandledException प्रक्रिया द्वारा पकड़ा जा सकता है कि Main में एक try / catch नहीं पकड़ सकता है। मुझे लगता है कि यह कहना गलत है कि कुछ गलत है, यह साबित करने के बिना कि यह गलत क्यों है, सिर्फ इतना कहना कि ऐसा नहीं है।
रॉडनी एस। फोली

5
मैंने आपके द्वारा पूछे जा रहे उदाहरण को पोस्ट किया है। कृपया ज़िम्मेदार हों और यदि आप नहीं हैं तो माइक के पुराने उत्तरों से अपने अप्रासंगिक वोटों को हटा दें। (कोई व्यक्तिगत रुचि नहीं, सिस्टम का ऐसा दुरुपयोग देखना पसंद नहीं है।)
BlueMonkMN

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

3
ओह, मैं यह भी जोड़ना चाहूंगा कि डाउन-वोटिंग उन लोगों के लिए नहीं है जो "पूर्ण बेवकूफ हैं या नियमों का उल्लंघन कर रहे हैं", बल्कि एक जवाब की गुणवत्ता का न्याय करने के लिए। यह मुझे लगता है कि उन्हें प्रदान करने वाले व्यक्ति पर "टिप्पणी" करने के लिए डाउन-वोटिंग उत्तर, उत्तर की सामग्री के आधार पर डाउन-वोटिंग उत्तरों की तुलना में बहुत बड़ा दुरुपयोग है, भले ही वह वोट सटीक हो या नहीं। इसे व्यक्तिगत मत बनाइए।
BlueMonkMN
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.