Watch2–part 6- options

The Watch2 package passes all the command line arguments to the dotnet watch. So how can it have its own settings? Simple: by reading a watch.json file that is in the same folder where it is executing.

1. Testing
I was considering how to perform the testing,and there were two options:

Microsoft File Providers: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/file-providers?view=aspnetcore-8.0

TestableIO: https://github.com/TestableIO/System.IO.Abstractions

I thought that the second option (TestableIO) would be easier to use and more flexible. However,I do not need to test the creation of the file,but rather the content of the file. Therefore,I will use the first option (Microsoft File Providers).

2. Maintain JSON in Sync with C#
I need a solution to transform JSON to C# on the fly (i.e.,at compile time). For this,a Roslyn Code Generator can be used. The rscgutils NuGet package will be helpful for this purpose.

Here is the relevant configuration in the project file:

<ItemGroup>
    <PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="8.0.0" />
    <PackageReference Include="rscgutils" Version="2024.2000.2000" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

<ItemGroup>
    <ProjectReference Include="..\Watch2_Interfaces\Watch2_Interfaces.csproj" />
</ItemGroup>
<ItemGroup>
	<AdditionalFiles Include="options.gen.json" />
</ItemGroup>

Code in Program.cs
The code in Program.cs will utilize the above configurations and packages. Here is an example of how it might look:

This example demonstrates how to read the watch.json file using the Microsoft File Providers package. The rscgutils package will handle the transformation of JSON to C# at compile time,ensuring that the JSON configuration is always in sync with the C# code.

So the code in program.cs will be:

//test
//args = ["run --no-hot-reload"];
//string folder = @"D:\gth\RSCG_Examples\v2\Generator";

//uncomment this line for production
string folder = Environment.CurrentDirectory;

var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection,folder);

var serviceProvider = serviceCollection.BuildServiceProvider();

var console = serviceProvider.GetRequiredService<IConsoleWrapper>();
var processManager = serviceProvider.GetRequiredService<ProcessManager>();
var startInfo = serviceProvider.GetRequiredService<IProcessStartInfo>();

var fileOptions = serviceProvider.GetRequiredService<IOptionsReader>();
if(!fileOptions.ExistsFile())
{
    var file = Path.Combine(folder,"watch2.json");
    File.WriteAllText(file,MyAdditionalFiles.options_gen_json);    
}

await processManager.StartProcessAsync(args,console,startInfo);



void ConfigureServices(IServiceCollection services,string folder)
{
    services.AddSingleton<IFileProvider>(new PhysicalFileProvider(folder));
    services.AddSingleton<IOptionsReader,OptionsReader>();
    services.AddSingleton<Ioptions_gen_json>(it =>
    {
        var optionsReader = it.GetRequiredService<IOptionsReader>();
        return optionsReader.GetOptions() ?? options_gen_json.Empty;
    });
    services.AddSingleton<IConsoleWrapper,ConsoleWrapper>();
    services.AddSingleton<ProcessManager,ProcessManager>();
    services.AddSingleton<IProcessStartInfo>(provider => new ProcessStartInfoWrapper
    {
    FileName = "dotnet",
    Arguments = "watch " + string.Join(' ',args),
    WorkingDirectory = folder,
    RedirectStandardOutput = true,
    RedirectStandardInput = true,
    RedirectStandardError = true,
    UseShellExecute = false,
    CreateNoWindow = true
    });

    services.AddLogging(loggingBuilder =>
    {
        loggingBuilder.ClearProviders();
        loggingBuilder.SetMinimumLevel(LogLevel.Trace);
        loggingBuilder.AddNLog("nlog.config");
    });
    services.AddSingleton<ILogger<ProcessManager>,Logger<ProcessManager>>();
    services.AddSingleton<Func<IProcessStartInfo,IProcessWrapper>>(it => new ProcessWrapper(it));
}


Posted

in

, ,

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *