What I have learned by building .NET Stars -part 5 – always available data for a display website
Dotnet Stars being a site just for displaying data, it does not require an API per se. Yes, for development purposes it needs a database and an API to display – but later – the data could be retrieved from local.
The first part is to write data in JSON files near to Blazor . But how to export by default this ?
And here ASPIRE thrives : I have made a console app to export data – and registered in ASPIRE with dependency of Blazor – and can see where Blazor folder is.
this is the extension
public static IResourceBuilder<TRes> AddPathToEnvironmment<TProject,TRes>(
this IResourceBuilder<TRes> builder, TProject p, string name)
where TProject : IProjectMetadata, new()
where TRes : IResourceWithEnvironment
{
//var p = new TProject();
string pathPrj = p.ProjectPath;
var fi = new FileInfo(pathPrj);
string dirName = fi?.DirectoryName ?? "";
var projectBuilder = builder
.WithEnvironment(ctx=>
{
ctx.EnvironmentVariables[name] =dirName;
ctx.EnvironmentVariables[$"{name}csproj"] = pathPrj;
});
return projectBuilder;
}
and this is how it is used
var exportToJson = builder.AddProject<Projects.StatsExport>("statsExport")
.WithReference(ui)
.WithReference(db)
.WaitFor(db)
.AddPathToEnvironmment(new Projects.StatsBlazorUI(),"pathToWrite")
;
And the code that uses this
var pathToWrite = Environment.GetEnvironmentVariable("pathToWrite");
if (string.IsNullOrWhiteSpace(pathToWrite))
{
Console.WriteLine("please add a path to write");
return;
}
The second part is to get data from WebAPI , if available, and, if not, from JSON files.
And here the Roslyn Code Generator, https://github.com/ignatandrei/RSCG_CompositeProvider , it is useful .
We have 2 implementations of same interface ,
public interface IStatsData
{
//other code
IAsyncEnumerable<IProjectWithStars> GetProjectsWithStars();
}
And we have an implementation from WebAPI and another from JSON files
With the nugethttps://nuget.org/packages/RSCG_CompositeProviderwe can obtain data from the first that returns data.
builder.Services.AddKeyedScoped<IStatsData>("both", (sp, obj) =>
{
var statsDataLocal = sp.GetRequiredKeyedService<IStatsData>("local_host");
var statsDataAPI = sp.GetRequiredKeyedService<IStatsData>("statsconsole_host");
StatsData_CP composite = new(statsDataAPI, statsDataLocal);
composite.UseFirstTheLastOneThatWorks = true;
return composite;
});