Skip to content

Commit 67ffea0

Browse files
committed
Merge branch 'enhance/user-facing-exception'
2 parents 9574ad8 + 95bed6e commit 67ffea0

File tree

102 files changed

+2052
-110
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+2052
-110
lines changed

docs-generation/Website/article_arguments.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using EntryPoint;
77
using System.Collections.Generic;
8+
using EntryPoint.Exceptions;
89

910
namespace Website {
1011
class article_arguments {
@@ -52,6 +53,10 @@ public SimpleCliArguments() : base("SimpleApp") { }
5253
// un-mapped operands are stored
5354
[Operand(Position: 1)]
5455
public decimal FirstOperand { get; set; }
56+
57+
public override void OnUserFacingException(UserFacingException e, string message) {
58+
throw new NotImplementedException();
59+
}
5560
}
5661
#endif
5762

@@ -139,6 +144,10 @@ public MessagingCliArguments() : base("Message Sender") { }
139144
[Required]
140145
[Operand(1)]
141146
public string Message { get; set; }
147+
148+
public override void OnUserFacingException(UserFacingException e, string message) {
149+
throw new NotImplementedException();
150+
}
142151
}
143152

144153
enum MessageImportanceEnum {

docs-generation/Website/article_commands.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using EntryPoint;
77
using System.Collections.Generic;
8+
using EntryPoint.Exceptions;
89

910
namespace Website {
1011
class article_commands {
@@ -45,6 +46,10 @@ public void Command2(string[] args) {
4546
// var arguments = Cli.Parse<Command2CliArguments>(args);
4647
// ...Application logic
4748
}
49+
50+
public override void OnUserFacingException(UserFacingException e, string message) {
51+
throw new NotImplementedException();
52+
}
4853
}
4954
#endif
5055

docs-generation/Website/article_help_generator.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
using EntryPoint;
77
using System.Collections.Generic;
8+
using EntryPoint.Exceptions;
89

910
namespace Website {
1011
class article_help_generator {
@@ -39,6 +40,10 @@ class ExampleHelpCliCommands : BaseCliCommands {
3940
public void Command1(string[] args) {
4041
// ...etc
4142
}
43+
44+
public override void OnUserFacingException(UserFacingException e, string message) {
45+
throw new NotImplementedException();
46+
}
4247
}
4348

4449
class CommandsHelpProgram {
@@ -68,6 +73,10 @@ public ExampleHelpCliArguments()
6873
[OptionParameter(LongName: "value1")]
6974
[Help("Some value to set")]
7075
public bool Value1 { get; set; }
76+
77+
public override void OnUserFacingException(UserFacingException e, string message) {
78+
throw new NotImplementedException();
79+
}
7180
}
7281

7382
class ArgumentsHelpProgram {
@@ -109,6 +118,10 @@ public override void OnHelpInvoked(string helpText) {
109118
Console.WriteLine(helpText);
110119
throw new HelpInvokedException("Using an exception to control application flow");
111120
}
121+
122+
public override void OnUserFacingException(UserFacingException e, string message) {
123+
throw new NotImplementedException();
124+
}
112125
}
113126
#endif
114127
class HelpInvokedException : Exception {
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#define CODE
2+
3+
using System;
4+
using System.Linq;
5+
6+
using EntryPoint;
7+
using System.Collections.Generic;
8+
using EntryPoint.Exceptions;
9+
10+
namespace Website {
11+
class article_user_facing_exceptions {
12+
/// ## User Facing Exceptions
13+
///
14+
/// When a user makes a mistake, EntryPoint will throw an exception which derives from UserFacingException.
15+
///
16+
/// This exception is caught and the following takes place on the relevant CliCommands or CliArguments instance
17+
/// * `.UserFacingExceptionThrown` is set to `true`
18+
/// * the virtual method `.OnUserFacingException(UserFacingException e, string message)` is called
19+
///
20+
/// The virtual method contains a sane default implementation which prints to screen and exits the application.
21+
///
22+
///
23+
/// #### Custom OnUserFacingException Handler
24+
///
25+
/// If you want your own implementation you can override this, like so
26+
///
27+
#if CODE
28+
class CliArguments : BaseCliArguments {
29+
public CliArguments() : base("Test") { }
30+
31+
[Option(LongName: "Option",
32+
ShortName: 'o')]
33+
public bool Option { get; set; }
34+
35+
public override void OnUserFacingException(UserFacingException e, string message) {
36+
// your own handling of the message for the user
37+
Console.WriteLine("User error: " + message);
38+
}
39+
}
40+
41+
class UserFacingExceptionProgram {
42+
public void main(string[] args) {
43+
var arguments = Cli.Parse<CliArguments>(args);
44+
// Execution would not reach this point if the user provides invalid arguments,
45+
// since OnUserFacingException would run and exit the program
46+
47+
// However, if you override OnUserFacingException and don't exit,
48+
// you could also do this:
49+
if (arguments.UserFacingExceptionThrown) {
50+
// Return here, or run something else
51+
}
52+
53+
// Normal Post-Arguments Application code...
54+
}
55+
}
56+
#endif
57+
58+
/// #### UserFacingException Bubbling
59+
///
60+
/// If your application utilises both CliCommands and CliArguments,
61+
/// you may want to handle UserFacingExceptions only on the CliCommands level.
62+
///
63+
/// This can be achieved using bubbling.
64+
///
65+
/// Simply override OnUserFacingException in your CliArguments implementations and re-throw the exception.
66+
/// The exception will then be caught at the CliCommands level.
67+
///
68+
#if CODE
69+
class BubblingCliArguments : BaseCliArguments {
70+
public BubblingCliArguments() : base("Test") { }
71+
72+
[Option(LongName: "Option",
73+
ShortName: 'o')]
74+
public bool Option { get; set; }
75+
76+
public override void OnUserFacingException(UserFacingException e, string message) {
77+
// Re-throw the exception, causing it to bubble up to the root command
78+
throw e;
79+
}
80+
}
81+
82+
class BubblingCliCommands : BaseCliCommands{
83+
84+
[Command("command1")]
85+
public void Command1(string[] args) {
86+
var arguments = Cli.Parse<BubblingCliArguments>(args);
87+
88+
// Normal Post-Arguments application logic
89+
}
90+
91+
public override void OnUserFacingException(UserFacingException e, string message) {
92+
// All UserFacingException throws will now come to here
93+
Console.WriteLine("User error: " + message);
94+
Console.ReadLine();
95+
Environment.Exit(1);
96+
}
97+
}
98+
99+
class BubblingProgram {
100+
public void main(string[] args) {
101+
var commands = Cli.Execute<BubblingCliCommands>(args);
102+
// Execution would not reach this point when the user provides invalid
103+
// commands or arguments, since our custom OnUserFacingException handler
104+
// would run and exit the program
105+
106+
// However, if you override OnUserFacingException and don't exit,
107+
// you could also do this:
108+
if (commands.UserFacingExceptionThrown) {
109+
// Return here, or run something else
110+
}
111+
112+
// Normal Post-Command Application code...
113+
}
114+
}
115+
#endif
116+
}
117+
}

docs-generation/Website/www/arguments.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ This has one Option `-s`, one OptionParameter `--name Bob` and a positional Oper
4242
// un-mapped operands are stored
4343
[Operand(Position: 1)]
4444
public decimal FirstOperand { get; set; }
45+
46+
public override void OnUserFacingException(UserFacingException e, string message) {
47+
throw new NotImplementedException();
48+
}
4549
}
4650

4751
#### Attributes
@@ -126,6 +130,10 @@ The following is used like:
126130
[Required]
127131
[Operand(1)]
128132
public string Message { get; set; }
133+
134+
public override void OnUserFacingException(UserFacingException e, string message) {
135+
throw new NotImplementedException();
136+
}
129137
}
130138

131139
enum MessageImportanceEnum {

docs-generation/Website/www/commands.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ This is the purpose of `BaseCliCommands`.
3535
// var arguments = Cli.Parse<Command2CliArguments>(args);
3636
// ...Application logic
3737
}
38+
39+
public override void OnUserFacingException(UserFacingException e, string message) {
40+
throw new NotImplementedException();
41+
}
3842
}
3943

4044
#### Attributes

docs-generation/Website/www/help_generator.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ The Help Generator consumes the following information for each class type.
2929
public void Command1(string[] args) {
3030
// ...etc
3131
}
32+
33+
public override void OnUserFacingException(UserFacingException e, string message) {
34+
throw new NotImplementedException();
35+
}
3236
}
3337

3438
class CommandsHelpProgram {
@@ -58,6 +62,10 @@ The Help Generator consumes the following information for each class type.
5862
[OptionParameter(LongName: "value1")]
5963
[Help("Some value to set")]
6064
public bool Value1 { get; set; }
65+
66+
public override void OnUserFacingException(UserFacingException e, string message) {
67+
throw new NotImplementedException();
68+
}
6169
}
6270

6371
class ArgumentsHelpProgram {
@@ -98,4 +106,8 @@ Below is a brief example of overriding the help method.
98106
Console.WriteLine(helpText);
99107
throw new HelpInvokedException("Using an exception to control application flow");
100108
}
109+
110+
public override void OnUserFacingException(UserFacingException e, string message) {
111+
throw new NotImplementedException();
112+
}
101113
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
## User Facing Exceptions
2+
3+
When a user makes a mistake, EntryPoint will throw an exception which derives from UserFacingException.
4+
5+
This exception is caught and the following takes place on the relevant CliCommands or CliArguments instance
6+
* `.UserFacingExceptionThrown` is set to `true`
7+
* the virtual method `.OnUserFacingException(UserFacingException e, string message)` is called
8+
9+
The virtual method contains a sane default implementation which prints to screen and exits the application.
10+
11+
12+
#### Custom OnUserFacingException Handler
13+
14+
If you want your own implementation you can override this, like so
15+
16+
17+
class CliArguments : BaseCliArguments {
18+
public CliArguments() : base("Test") { }
19+
20+
[Option(LongName: "Option",
21+
ShortName: 'o')]
22+
public bool Option { get; set; }
23+
24+
public override void OnUserFacingException(UserFacingException e, string message) {
25+
// your own handling of the message for the user
26+
Console.WriteLine("User error: " + message);
27+
}
28+
}
29+
30+
class UserFacingExceptionProgram {
31+
public void main(string[] args) {
32+
var arguments = Cli.Parse<CliArguments>(args);
33+
// Execution would not reach this point if the user provides invalid arguments,
34+
// since OnUserFacingException would run and exit the program
35+
36+
// However, if you override OnUserFacingException and don't exit,
37+
// you could also do this:
38+
if (arguments.UserFacingExceptionThrown) {
39+
// Return here, or run something else
40+
}
41+
42+
// Normal Post-Arguments Application code...
43+
}
44+
}
45+
46+
#### UserFacingException Bubbling
47+
48+
If your application utilises both CliCommands and CliArguments,
49+
you may want to handle UserFacingExceptions only on the CliCommands level.
50+
51+
This can be achieved using bubbling.
52+
53+
Simply override OnUserFacingException in your CliArguments implementations and re-throw the exception.
54+
The exception will then be caught at the CliCommands level.
55+
56+
57+
class BubblingCliArguments : BaseCliArguments {
58+
public BubblingCliArguments() : base("Test") { }
59+
60+
[Option(LongName: "Option",
61+
ShortName: 'o')]
62+
public bool Option { get; set; }
63+
64+
public override void OnUserFacingException(UserFacingException e, string message) {
65+
// Re-throw the exception, causing it to bubble up to the root command
66+
throw e;
67+
}
68+
}
69+
70+
class BubblingCliCommands : BaseCliCommands{
71+
72+
[Command("command1")]
73+
public void Command1(string[] args) {
74+
var arguments = Cli.Parse<BubblingCliArguments>(args);
75+
76+
// Normal Post-Arguments application logic
77+
}
78+
79+
public override void OnUserFacingException(UserFacingException e, string message) {
80+
// All UserFacingException throws will now come to here
81+
Console.WriteLine("User error: " + message);
82+
Console.ReadLine();
83+
Environment.Exit(1);
84+
}
85+
}
86+
87+
class BubblingProgram {
88+
public void main(string[] args) {
89+
var commands = Cli.Execute<BubblingCliCommands>(args);
90+
// Execution would not reach this point when the user provides invalid
91+
// commands or arguments, since our custom OnUserFacingException handler
92+
// would run and exit the program
93+
94+
// However, if you override OnUserFacingException and don't exit,
95+
// you could also do this:
96+
if (commands.UserFacingExceptionThrown) {
97+
// Return here, or run something else
98+
}
99+
100+
// Normal Post-Command Application code...
101+
}
102+
}

0 commit comments

Comments
 (0)