c# - WPF গ্লোবাল ব্যতিক্রম হ্যান্ডলার




.net exception (6)

এই প্রশ্নটি ইতিমধ্যে একটি উত্তর আছে:

কখনও কখনও, পুনরুত্পাদন পরিস্থিতিতে অধীনে, আমার WPF অ্যাপ্লিকেশন কোন বার্তা ছাড়াই ক্র্যাশ। অ্যাপ্লিকেশন সহজভাবে বন্ধ অবিলম্বে।

গ্লোবাল চেষ্টা / ক্যাচ ব্লক বাস্তবায়ন করার সেরা জায়গা কোথায়। অন্তত আমাকে একটি বার্তাবাক্স বাস্তবায়ন করতে হবে: "অসুবিধার জন্য দুঃখিত ..."


Application.Dispatcher.UnhandledException এর জন্য কোডের একটি দ্রুত উদাহরণ:

public App() {
    this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
}

void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
    string errorMessage = string.Format("An unhandled exception occurred: {0}", e.Exception.Message);
    MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
    // OR whatever you want like logging etc. MessageBox it's just example
    // for quick debugging etc.
    e.Handled = true;
}

আমি App.xaml.cs এই কোড যোগ


আপনি বিভিন্ন স্তরে unhandled ব্যতিক্রম ফাঁদ করতে পারেন:

  1. AppDomain.UnhandledException সমস্ত থ্রেড থেকে।
  2. Dispatcher.UnhandledException একটি একক নির্দিষ্ট UI প্রেরক থ্রেড থেকে।
  3. Application.DispatcherUnhandledException আপনার WPF অ্যাপ্লিকেশনে প্রধান UI প্রেরক থ্রেড থেকে।
  4. প্রতিটি অ্যাপডোমাইনের মধ্যে থেকে TaskScheduler.UnobservedTaskException যা অ্যাসিঙ্ক্রোনাস ক্রিয়াকলাপগুলির জন্য একটি টাস্ক সময়সূচী ব্যবহার করে।

আপনি unhandled ব্যতিক্রম ফাঁদে আটকে প্রয়োজন কি স্তর বিবেচনা করা উচিত।

# 2 এবং # 3 এর মধ্যে সিদ্ধান্ত নেওয়া হলে আপনি একাধিক WPF থ্রেড ব্যবহার করছেন কিনা তা নির্ভর করে। এটি একটি বহিরাগত পরিস্থিতি এবং যদি আপনি নিশ্চিত না হন বা না করেন তবে এটি সম্ভবত আপনি সম্ভবত নন।


উপরে পোস্ট ছাড়াও:

Application.Current.DispatcherUnhandledException

অন্য থ্রেড থেকে মূল থ্রেড থেকে নিক্ষিপ্ত হয় ব্যতিক্রম ব্যতিক্রম হবে না। আপনি তার প্রকৃত থ্রেড উপর যারা ব্যতিক্রম হ্যান্ডেল আছে। কিন্তু আপনি যদি তাদের গ্লোবাল ব্যতিক্রম হ্যান্ডলারের উপর পরিচালনা করতে চান তবে আপনি এটি মূল থ্রেডে প্রেরণ করতে পারেন:

 System.Threading.Thread t = new System.Threading.Thread(() =>
    {
        try
        {
            ...
            //this exception will not be catched by 
            //Application.DispatcherUnhandledException
            throw new Exception("huh..");
            ...
        }
        catch (Exception ex)
        {
            //But we can handle it in the throwing thread
            //and pass it to the main thread wehre Application.
            //DispatcherUnhandledException can handle it
            System.Windows.Application.Current.Dispatcher.Invoke(
                System.Windows.Threading.DispatcherPriority.Normal,
                new Action<Exception>((exc) =>
                    {
                      throw new Exception("Exception from another Thread", exc);
                    }), ex);
        }
    });

একটি সম্পূর্ণ সমাধান here

এটা নমুনা কোড সঙ্গে খুব সুন্দর ব্যাখ্যা করা হয়েছে। যাইহোক, সতর্কতা অবলম্বন করুন যে অ্যাপ্লিকেশনটি বন্ধ করে না। লাইন অ্যাপ্লিকেশন যুক্ত করুন। Current.Shutdown (); চিত্তাকর্ষক অ্যাপ্লিকেশন বন্ধ।


যখনই একটি unhandled ব্যতিক্রম ঘটে তখন আমি "আমার অসুবিধার জন্য দুঃখিত" ডায়লগ বাক্সটি দেখানোর জন্য আমার WPF অ্যাপ্লিকেশানগুলিতে নিম্নলিখিত কোডটি ব্যবহার করি। এটি ব্যতিক্রম বার্তাটি দেখায় এবং ব্যবহারকারীকে জিজ্ঞাসা করে যে তারা অ্যাপ্লিকেশনটি বন্ধ করতে চায় নাকি ব্যতিক্রম উপেক্ষা করতে পারে এবং চালিয়ে যেতে পারে (পরবর্তী ক্ষেত্রে কোনও মারাত্মক ব্যতিক্রম ঘটে এবং ব্যবহারকারী সাধারণত অ্যাপ্লিকেশনটি ব্যবহার করতে পারে)।

App.xaml স্টার্টআপ ইভেন্ট হ্যান্ডলার যোগ করুন:

<Application .... Startup="Application_Startup">

App.xaml.cs কোডটিতে স্টার্টআপ ইভেন্ট হ্যান্ডলার ফাংশন যোগ করুন যা গ্লোবাল অ্যাপ্লিকেশন ইভেন্ট হ্যান্ডলার নিবন্ধন করবে:

using System.Windows.Threading;

private void Application_Startup(object sender, StartupEventArgs e)
{
    // Global exception handling  
    Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(AppDispatcherUnhandledException);    
}

void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{    
    \#if DEBUG   // In debug mode do not custom-handle the exception, let Visual Studio handle it

    e.Handled = false;

    \#else

    ShowUnhandledException(e);    

    \#endif     
}

void ShowUnhandledException(DispatcherUnhandledExceptionEventArgs e)
{
    e.Handled = true;

    string errorMessage = string.Format("An application error occurred.\nPlease check whether your data is correct and repeat the action. If this error occurs again there seems to be a more serious malfunction in the application, and you better close it.\n\nError: {0}\n\nDo you want to continue?\n(if you click Yes you will continue with your work, if you click No the application will close)",

    e.Exception.Message + (e.Exception.InnerException != null ? "\n" + 
    e.Exception.InnerException.Message : null));

    if (MessageBox.Show(errorMessage, "Application Error", MessageBoxButton.YesNoCancel, MessageBoxImage.Error) == MessageBoxResult.No)   {
        if (MessageBox.Show("WARNING: The application will close. Any changes will not be saved!\nDo you really want to close it?", "Close the application!", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
    {
        Application.Current.Shutdown();
    } 
}

সেরা উত্তর সম্ভবত https://.com/a/1472562/601990 ।

এখানে কিছু কোড রয়েছে যা এটি ব্যবহার করে দেখায়:

App.xaml.cs

public sealed partial class App
{
    protected override void OnStartup(StartupEventArgs e)
    {
        // setting up the Dependency Injection container
        var resolver = ResolverFactory.Get();

        // getting the ILogger or ILog interface
        var logger = resolver.Resolve<ILogger>();
        RegisterGlobalExceptionHandling(logger);

        // Bootstrapping Dependency Injection 
        // injects ViewModel into MainWindow.xaml
        // remember to remove the StartupUri attribute in App.xaml
        var mainWindow = resolver.Resolve<Pages.MainWindow>();
        mainWindow.Show();
    }

    private void RegisterGlobalExceptionHandling(ILogger log)
    {
        // this is the line you really want 
        AppDomain.CurrentDomain.UnhandledException += 
            (sender, args) => CurrentDomainOnUnhandledException(args, log);

        // optional: hooking up some more handlers
        // remember that you need to hook up additional handlers when 
        // logging from other dispatchers, shedulers, or applications

        Application.Dispatcher.UnhandledException += 
            (sender, args) => DispatcherOnUnhandledException(args, log);

        Application.Current.DispatcherUnhandledException +=
            (sender, args) => CurrentOnDispatcherUnhandledException(args, log);

        TaskScheduler.UnobservedTaskException += 
            (sender, args) => TaskSchedulerOnUnobservedTaskException(args, log);
    }

    private static void TaskSchedulerOnUnobservedTaskException(UnobservedTaskExceptionEventArgs args, ILogger log)
    {
        log.Error(args.Exception, args.Exception.Message);
        args.SetObserved();
    }

    private static void CurrentOnDispatcherUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
    {
        log.Error(args.Exception, args.Exception.Message);
        // args.Handled = true;
    }

    private static void DispatcherOnUnhandledException(DispatcherUnhandledExceptionEventArgs args, ILogger log)
    {
        log.Error(args.Exception, args.Exception.Message);
        // args.Handled = true;
    }

    private static void CurrentDomainOnUnhandledException(UnhandledExceptionEventArgs args, ILogger log)
    {
        var exception = args.ExceptionObject as Exception;
        var terminatingMessage = args.IsTerminating ? " The application is terminating." : string.Empty;
        var exceptionMessage = exception?.Message ?? "An unmanaged exception occured.";
        var message = string.Concat(exceptionMessage, terminatingMessage);
        log.Error(exception, message);
    }
}




exception-handling