Skip to content

Incorrect use of DefaultValueFactory for custom file existence validation #52489

@BBrown4

Description

@BBrown4

Type of issue

Code doesn't work

Description

The "Add subcommands and custom validation" section places file-existence validation inside DefaultValueFactory:

Option<FileInfo> fileOption = new("--file")
{
    Description = "An option whose argument is parsed as a FileInfo",
    Required = true,
    DefaultValueFactory = result =>
    {
        if (result.Tokens.Count == 0)
        {
            return new FileInfo("sampleQuotes.txt");
        }
        string filePath = result.Tokens.Single().Value;
        if (!File.Exists(filePath))
        {
            result.AddError("File does not exist");
            return null;
        }
        else
        {
            return new FileInfo(filePath);
        }
    }
};

The article states:

"Without this code, missing files are reported with an exception and stack trace. With this code just the specified error message is displayed."

This doesn't work. DefaultValueFactory only runs when no value is provided for the option. When a user passes --file nofile, System.CommandLine's built-in parser converts the argument directly to FileInfo (which doesn't validate existence), bypassing DefaultValueFactory entirely. The action handler then throws a FileNotFoundException with a stack trace.

Suggested fix (option A — built-in validator):

  fileOption.AcceptExistingOnly();

Suggested fix (option B — custom validator with custom error message):

fileOption.Validators.Add(result =>
{
    var file = result.GetValueOrDefault<FileInfo>();
    if (file is not null && !file.Exists)
    {
        result.AddError("File does not exist");
    }
});

In both cases, DefaultValueFactory should be simplified to only handle the default:

DefaultValueFactory = result =>
{
    if (result.Tokens.Count == 0)
    {
        return new FileInfo("sampleQuotes.txt");
    }
    return new FileInfo(result.Tokens.Single().Value);
}

References:

Reproduction:

  dotnet new console -n scl
  cd scl
  dotnet add package System.CommandLine
  # Follow the tutorial through "Add subcommands and custom validation"
  dotnet run -- quotes read --file nonexistent
  # Expected: "File does not exist"
  # Actual: Unhandled FileNotFoundException with stack trace

Page URL

https://learn.microsoft.com/en-us/dotnet/standard/commandline/get-started-tutorial#add-subcommands-and-custom-validation

Content source URL

https://github.com/dotnet/docs/blob/main/docs/standard/commandline/get-started-tutorial.md

Document Version Independent Id

fa160b1d-66ed-8c5d-37cd-b7e02443e9f1

Platform Id

0f144444-1ce3-cdf7-87a6-c659d44e08d3

Article author

@gewarren

Metadata

  • ID: 7705dc41-7297-0807-7e9c-2e6548c26b84
  • PlatformId: 0f144444-1ce3-cdf7-87a6-c659d44e08d3
  • Service: dotnet-fundamentals

Related Issues


Associated WorkItem - 566723

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

Status

👀 In review

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions