dotnet / dotnet/command-line-api

Gracefully handle exceptions in command handlers

Ouverte
#1,655 5 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
C#
Étoiles
3.7k
Forks
428
Métriques de merge des PR
Aucune PR mergée en 30 j

Description

When an exception occurs in a command handler the entire stack trace is barfed out into stderr and I'd like to not have that behavior for explicitly handled exceptions. Consider a handler that tries to read a file but the filename is not found. The standard libraries throw a FileNotFoundException which I'd like to catch and display just the message and not the entire stack trace. For unhandled exceptions I think the current behavior of the stack trace is fine since by definition it is unhandled.

I looks like I can get the invocation context and set the invocation result to a custom IInvocationResult. The problem is there doesn't appear to be (or I missed it 😅) an ErrorResult for setting a user-defined error that the handler failed. I made my own that is essentially a copy of `ParseErrorResult` but you can specify the message in the ctor.

```c#
public class ErrorResult : IInvocationResult
{
private readonly string _errorMessage;
private readonly int _errorExitCode;

public ErrorResult(string errorMessage, int errorExitCode = 1)
{
_errorMessage = errorMessage;
_errorExitCode = errorExitCode;
}

public void Apply(InvocationContext context)
{
context.Console.ResetTerminalForegroundColor();
context.Console.SetTerminalForegroundRed();

context.Console.Error.WriteLine(_errorMessage);
context.Console.Error.WriteLine();

context.ExitCode = _errorExitCode;

context.Console.ResetTerminalForegroundColor();
}
}
```

The main issue I ran into was that `ResetTerminalForegroundColor` and `ResetTerminalForegroundColor` are internal extension methods and those also rely on the internal `Platform` static class. I copied them into my code base for now.

Assuming those APIs were public, ErrorResult now works and you can use it like in the following trivial example:

```c#
void Handler(InvocationContext ctx, string filename)
{
try
{
Console.WriteLine(File.ReadAllText(filename));
}
catch (FileNotFoundException e)
{
ctx.InvocationResult = new ErrorResult(e.Message, 42);
}
}
```

Now when the handled exception occurs, it doesnt bubble up and kill the application but instead just prints (in red) to stderr.

I'm not familiar with the details of how System.CommandLine works. Do you think this is a valid approach for handling exceptions in a handler?

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

Commencez par lire le chemin des résultats d’invocation autour de InvocationContext, IInvocationResult et ParseErrorResult, puis examinez les méthodes internes de couleur du terminal et la dépendance Platform mentionnées dans l’issue. Le travail est terminé lorsque l’approche prise en charge par le projet pour les exceptions gérées et non gérées, la sortie stderr et les codes de sortie est clairement définie et validée.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
csharp
Domaine
cli
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
À clarifier
Accessibilité débutants
30/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.