command-line-api icon indicating copy to clipboard operation
command-line-api copied to clipboard

NullReferenceException when redirecting output from ScreenView

Open flakey-bit opened this issue 5 years ago • 2 comments

Given the following program:

public class Program
{
    static async Task<int> Main(InvocationContext invocationContext, string[] args)
    {
        var consoleRenderer = new ConsoleRenderer(
            invocationContext.Console,
            mode: invocationContext.BindingContext.OutputMode(),
            resetAfterRender: true);

        var screen = new ScreenView(consoleRenderer, invocationContext.Console) { Child =
            new ContentView("Hello World!")
        };

        screen.Render();
        return 0;
    }
}

Running as .\bin\Debug\net471\Program.exe

gives the output

Hello World!

However attempting to redirect output to a file with .\bin\Debug\net471\Program.exe > c:\temp\output.txt

throws a NullReferenceException:

Unhandled exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at System.CommandLine.Rendering.Views.ScreenView.Render()
   at SampleProject.Program.<Main>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Invocation.CommandHandler.<GetResultCodeAsync>d__34.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Invocation.ModelBindingCommandHandler.<InvokeAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_0.<<BuildInvocationChain>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseParseErrorReporting>b__20_0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass15_0.<<UseHelp>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass24_0.<<UseVersionOption>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass22_0.<<UseTypoCorrections>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseSuggestDirective>b__21_0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseParseDirective>b__19_0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseDebugDirective>b__11_0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<RegisterWithDotnetSuggest>b__10_0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass6_0.<<ConfigureConsole>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass13_0.<<UseExceptionHandler>b__0>d.MoveNext()

flakey-bit avatar Apr 30 '20 21:04 flakey-bit

Right, this was just a conceptual misunderstanding on my behalf.

I didn't actually need a ScreenView at all but rather should simply have told my View (in this case, a ContentView) to render itself to the console renderer as follows:

new ContentView("Hello World!").Render(consoleRenderer, Region.EntireTerminal);

The NullReferenceException for the incorrect usage probably should be fixed, though

flakey-bit avatar May 04 '20 00:05 flakey-bit

@flakey-bit did you ever get it to render properly? I am glad that my code is no longer throwing NullReferenceExceptions, but the output of a TableView is broken in every terminal:

namespace FileInfoRender;

using System.CommandLine;
using System.CommandLine.Invocation;
using System.CommandLine.Rendering;
using System.CommandLine.Rendering.Views;
using System.IO;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var rootCommand = new RootCommand();
        rootCommand.Handler = CommandHandler.Create<InvocationContext>(Print);
        rootCommand.Invoke(args);
    }

    static void Print(InvocationContext context)
    {
        var consoleRenderer = new ConsoleRenderer(
            context.Console,
            context.BindingContext.OutputMode(),
            true);
        var tableView = new TableView<FileInfo>
        {
            Items = new DirectoryInfo(".").EnumerateFiles().ToList()
        };
        tableView.AddColumn(f => f.Name, "Name");
        tableView.AddColumn(f => f.LastWriteTime, "Modified");
        tableView.AddColumn(f => f.Length, "Size");
        tableView.Render(consoleRenderer, Region.EntireTerminal);
    }
}

grafik

With DragonFruit and ScreenView everything works, but I would like to not use DragonFruit:

static void Main(InvocationContext context, DirectoryInfo argument= null)
{
    argument ??= new DirectoryInfo(".");
    var consoleRenderer = new ConsoleRenderer(
        context.Console,
        context.BindingContext.OutputMode(),
        true);

    var tableView = new TableView<FileInfo>
    {
        Items = argument.EnumerateFiles().ToList()
    };

    tableView.AddColumn(f => f.Name, "Name");

    tableView.AddColumn(f => f.LastWriteTime, "Modified");

    tableView.AddColumn(f => f.Length, "Size");

    var screen = new ScreenView(consoleRenderer, context.Console) { Child = tableView };
    screen.Render();
}

Trolldemorted avatar Nov 18 '21 10:11 Trolldemorted

Hello!

We have decided to deprecate the System.CommandLine.Rendering package: https://github.com/dotnet/command-line-api/issues/2576#Deprecating-experimental-projects

We recommend using https://www.nuget.org/packages/Spectre.Console#readme-body-tab which became the golden standard in the .NET Ecosystem

adamsitnik avatar Jun 19 '25 21:06 adamsitnik