nooogle / CDS.CSharpScripting

Drop-in user control for C# editing with intellisense and compilation. Script compilation and execution classes for GUI and console applications.
MIT License
9 stars 3 forks source link

NullReference Exception #32

Open tcartwright opened 1 year ago

tcartwright commented 1 year ago

I am using your library here https://github.com/tcartwright/SqlServerDEID and it used to run without issues. I am running into a System.NullReferenceException now. The issue occurs when editing the script in the editor and when it goes to show intellisense it throws an exception at that point in time.

It is occuring at the following location in Microsoft.CodeAnalysis.CSharp.CodeGeneration.CSharpCodeGenerationService:

private TDeclarationNode AddStatementsWorker<TDeclarationNode>(
    TDeclarationNode destinationMember,
    IEnumerable<SyntaxNode> statements,
    CodeGenerationOptions options,
    CancellationToken cancellationToken) where TDeclarationNode : SyntaxNode
        {
            var location = options.BestLocation;

The options variable is null at this point in time.

This code used to work without issues, I have tried both upgrading your nuget package to the latest version, and going back to the version that used to work for me (1.0.18). Neither of which seem to matter

The source code for the form that does the editing is located here: https://github.com/tcartwright/SqlServerDEID/blob/master/SqlServerDEID.Editor/frmCodeEditor.cs

Can you please help?

tcartwright commented 1 year ago

I found this: https://github.com/dotnet/roslyn/issues/44387 and it seems related.

nooogle commented 1 year ago

Hi,

Sorry to hear you get these exceptions. I also get occasional exceptions with this library. Most of the time I can catch them, but some of them still kill my apps from time to time.

The underlying library, RoslynPad, has been updated a lot recently, but is no longer supporting .Net Framework. For me it means not being able to update to the latest and greatest NuGet packages across the board.

I’m working on my own scripting library now, for Framework and .Net, nothing like as powerful as RoslynPad but easier to manage and fix I hope. It’s a few weeks away though.

For exceptions thrown during editing, I’ve found that adding a program-level handler for unhandled exceptions can help - without this my apps will die more frequently. I see in your code you have a handler for CurrentDomain. I also add one for Application Thread exceptions.

Also - since ChatGPT is now my unofficial co-worker, I asked it for any tips on unhandled exceptions and it suggested a third that I haven’t heard of: TaskSchedular.UnobservedTasksException. I’m going to try this in my apps to see if it helps with stability. (I have the same issue that sometimes when I’m editing the script I’ll get some exception that causes problems, and that I can’t directly catch myself.)

Two bits below.. a snipped from my own program.cs for the application unhandled exceptions, and then the ChatGPT info about 3 options. Please let me know if any of this works for you.

Thanks Jon

(1) Program.cs from my own test apps:

using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms;

namespace WindowsFormsAppDemo { static class Program { ///

/// The main entry point for the application. /// [STAThread] static void Main() { HookThreadExceptions(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FormMain()); }

    /// <summary>
    /// At the time of writing, using RoslynPad 3.6.0, there are occasional WinForms 
    /// thread exceptions - these are (probably) thrown when an activity is attempted
    /// on the wrong thread. For now, all we can do is send the exception to the 
    /// debug output.
    /// </summary>
    private static void HookThreadExceptions()
    {
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, true);
        Application.ThreadException += Application_ThreadException;
    }

    /// <summary>
    /// Send otherwise-unhandled thread exceptions details to the debug output.
    /// 
    /// (See <see cref="HookThreadExceptions"/> for details of why we do this.)
    /// </summary>
    private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
        if (new[] { "RoslynPad", "AvalonEdit" }.Any(lib => e.Exception.StackTrace.Contains(lib)))
        {
            System.Diagnostics.Debug.WriteLine(
                $"Caught a WinForms thread exception, possibly due to a " +
                $"problem in RoslynPad or dependent library.");

            System.Diagnostics.Debug.WriteLine($"Exception message: {e.Exception.Message}");
            System.Diagnostics.Debug.WriteLine($"Exception stack trace: {e.Exception.StackTrace}");
        }
        else
        {
            System.Diagnostics.Debug.WriteLine($"Caught a WinForms thread exception, unknown reason.");
        }
    }
}

}

(2) ChatGPT info:

Sure, in addition to handling exceptions within tasks, you can also add some general exception handling at the application level. Here are a few more strategies for dealing with those:

1. AppDomain.CurrentDomain.UnhandledException

This event will be triggered for any unhandled exceptions.

AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
    Exception ex = (Exception)e.ExceptionObject;
    // Handle the exception
    // Please note that typically the application will terminate after this event has been fired
};

This is more of a last resort for catching exceptions and typically the application will terminate after this event has been fired.

2. Application.ThreadException

This event will catch exceptions thrown on Windows Forms threads.

Application.ThreadException += (sender, e) =>
{
    Exception ex = e.Exception;
    // Handle the exception
};

You will need to set the Application.SetUnhandledExceptionMode to CatchException for this event to trigger for all unhandled exceptions:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

3. TaskScheduler.UnobservedTaskException

As mentioned before, this event can be used to catch exceptions that were thrown from tasks and not handled.

TaskScheduler.UnobservedTaskException += (sender, e) =>
{
    // Handle exception
    e.SetObserved();
};

These events give you a chance to log the errors and perhaps notify the user, but generally speaking, if an unhandled exception has been thrown, it means there is a problem in your code that should be fixed. Depending on the nature of the exception, it may or may not be safe to continue executing the application.

Remember that swallowing exceptions is typically a bad practice. You should always aim to handle only the exceptions you expect and know how to recover from. For everything else, let the application crash. This is generally better than continuing in an undefined state.

㊔ Carpe Diem Systems Limited

Registered in England & Wales: 3268509

🏠 14 Lawley Way, Droitwich, WR9 8FB 🕸️ http://www.carpediemsystems.co.uk/ 📧 @. @.> ☎️ +44 (0) 7545 533911

On 15 Jun 2023, at 17:36, Tim Cartwright @.***> wrote:

I am using your library here https://github.com/tcartwright/SqlServerDEID and it used to run without issues. I am running into a System.NullReferenceException now. The issue occurs when editing the script in the editor and when it goes to show intellisense it throws an exception at that point in time.

It is occuring at the following location in Microsoft.CodeAnalysis.CSharp.CodeGeneration.CSharpCodeGenerationService:

private TDeclarationNode AddStatementsWorker( TDeclarationNode destinationMember, IEnumerable statements, CodeGenerationOptions options, CancellationToken cancellationToken) where TDeclarationNode : SyntaxNode { var location = options.BestLocation; The options variable is null at this point in time.

This code used to work without issues, I have tried both upgrading your nuget package to the latest version, and going back to the version that used to work for me (1.0.18). Neither of which seem to matter

The source code for the form that does the editing is located here: https://github.com/tcartwright/SqlServerDEID/blob/master/SqlServerDEID.Editor/frmCodeEditor.cs

Can you please help?

— Reply to this email directly, view it on GitHub https://github.com/nooogle/CDS.CSharpScripting/issues/32, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADE2TGJXETPBAC6YATOQROLXLM2ZXANCNFSM6AAAAAAZIDSBQI. You are receiving this because you are subscribed to this thread.

tcartwright commented 1 year ago

Ty for the awesome and quick response. I hope you don't mind but I posted a way to reproduce that bug using your library in the roslyn bug: https://github.com/dotnet/roslyn/issues/44387#issuecomment-1594815744

I am hoping they either:

  1. Fix the bug (optimal)
  2. Tell (us) you how to use their code differently to keep the bug from happening

If those fail, I will probably look into exception handling like you mentioned, but I would rather that be a last resort.

nooogle commented 1 year ago

Hi - I’ve tried a few times to reproduce this, using the solution you posted as a zip, but I can’t make it fail 😬

Screen recording attached, in case you spot a different way to reproduce this.

㊔ Carpe Diem Systems Limited

Registered in England & Wales: 3268509

🏠 14 Lawley Way, Droitwich, WR9 8FB 🕸️ http://www.carpediemsystems.co.uk/ 📧 @. @.> ☎️ +44 (0) 7545 533911

On 16 Jun 2023, at 15:53, Tim Cartwright @.***> wrote:

Ty for the awesome and quick response. I hope you don't mind but I posted a way to reproduce that bug using your library in the roslyn bug: dotnet/roslyn#44387 (comment) https://github.com/dotnet/roslyn/issues/44387#issuecomment-1594815744 I am hoping they either:

Fix the bug (optimal) Tell (us) you how to use their code differently to keep the bug from happening If those fail, I will probably look into exception handling like you mentioned, but I would rather that be a last resort.

— Reply to this email directly, view it on GitHub https://github.com/nooogle/CDS.CSharpScripting/issues/32#issuecomment-1594824746, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADE2TGO2RRDFTSCTFJCKKSLXLRXPHANCNFSM6AAAAAAZIDSBQI. You are receiving this because you commented.

tcartwright commented 1 year ago

Sometimes you just have to bounce around intellisense. I have noticed it does not always pop up using my instructions. Very bizarre.