dotnet / platform-compat

Roslyn analyzer that finds usages of APIs that will throw PlatformNotSupportedException on certain platforms.
MIT License
279 stars 43 forks source link

With DE0002 How else are we going to be able to register the UnhandledException events on all platforms? #231

Open AraHaan opened 4 years ago

AraHaan commented 4 years ago

With DE0002 being given to projects that uses using System.Security.Permissions; just to be able to register an unhandled exception event and to control appdomains (which registering that event requires). How else are we going to be able to use that event without using the CAS that is says not to use?

I think the documentation should include ways of using that event without using CAS then...

consider a minimal example being a console application like so:

  1. make a new console application dotnet new console and then add the package Microsoft.DotNet.Analyzers.Compatibility at version 0.2.12-alpha.
  2. Replace the Program.cs file with the following code:
    
    using System;
    using System.IO;
    using System.Security.Permissions;
    using System.Diagnostics;

namespace ConsoleApplication1 { public static class Program { [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)] public static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler); throw new Exception("Unhandled.") }

    private static void MyHandler(object sender, UnhandledExceptionEventArgs args)
    {
        // log the exception to a file.
        var e = (Exception)args.ExceptionObject;
        _ = Directory.CreateDirectory("logs");
        var text = string.Empty;
        text += e.GetType().Name + ": " + e.Message;
        text += e.StackTrace!;
        GetInnerException(text, e.InnerException);
        File.WriteAllText($"logs{Path.DirectorySeparatorChar}UnhandledExceptions.txt", text);
        Debug.WriteLine(e.GetType().Name + ": " + e.Message);
        Debug.WriteLine(e.StackTrace);
    }

    // this is to recurse and capture all inner exceptions.
    private static void GetInnerException(string? text, Exception? ex)
    {
        if (ex != null)
        {
            text += "Inner Exception:\n";
            text += ex.GetType().Name + ": " + ex.Message;
            text += ex.StackTrace!;
            Debug.WriteLine("Inner Exception:\n");
            Debug.WriteLine(ex.GetType().Name + ": " + ex.Message);
            Debug.WriteLine(ex.StackTrace);
            GetInnerException(text, ex.InnerException);
        }
    }

}

KalleOlaviNiemitalo commented 4 years ago

Registering a handler for AppDomain.UnhandledException on .NET Framework does not require SecurityPermissionAttribute if the application domain already grants full trust to all assemblies; see AppDomain.IsFullyTrusted. So if you don't need to support partial-trust scenarios, you can delete that.

Your code sample seems to be using C# 8, which is not supported on .NET Framework anyway.

KalleOlaviNiemitalo commented 4 years ago

https://github.com/dotnet/dotnet-api-docs/pull/4384 is removing the SecurityPermissionAttribute from the AppDomain.UnhandledException example.

AraHaan commented 4 years ago

It is targeting .NET Core 3.1 and uses that to use that event for unhandled exceptions.

But I also plan to switch it to net5.0 eventually though.