Skip to content

[Configuration] Configuration Extensions ContentSource and Add*Configuration misses validation for the provided name! current State: not useable with slash usage or non appsettings prefix #3007

@DevTKSS

Description

@DevTKSS

Current behavior

I am unable to source Solution-wide-synced Configuration or json Data like the <Content Include="..." LinkBase="..." CopyToOutputDirectory="..." /> (used in the Uno.Chefs App with Windows.Storage.StorageFile.* ), with simply using the provided IConfigBuilder.ContentSource Functionallity:

public static IConfigBuilder ContentSource(this IConfigBuilder hostBuilder, string? config = null, bool includeEnvironmentSettings = true)
{
return hostBuilder
.ConfigureAppConfiguration((ctx, b) =>
{
if (config is { Length: > 0 })
{
b.AddConfiguration(ctx, config);
if (includeEnvironmentSettings)
{
b.AddEnvironmentConfiguration(ctx, config);
}
}
else
{
b.AddAppConfiguration(ctx);
if (includeEnvironmentSettings)
{
b.AddEnvironmentAppConfiguration(ctx);
}
}
}).AsConfigBuilder();
}


The detail that I think is maybe causing the problem, is that as soon as ContentSource for example calls Line 38:

public static IConfigBuilder ContentSource(this IConfigBuilder hostBuilder, string? config = null, bool includeEnvironmentSettings = true)
{
return hostBuilder
.ConfigureAppConfiguration((ctx, b) =>
{
if (config is { Length: > 0 })
{
b.AddConfiguration(ctx, config);
if (includeEnvironmentSettings)
{
b.AddEnvironmentConfiguration(ctx, config);
}
}
else
{
b.AddAppConfiguration(ctx);
if (includeEnvironmentSettings)
{
b.AddEnvironmentAppConfiguration(ctx);
}
}
}).AsConfigBuilder();
}

which can not apply if this ContentSource is something like ../AppData/*.json to load content data, (using LinkBase would then remove the ../) we would end up with something like this in the Chefs App: AppData/Reciepes.json

The ContentSource call then calls:

  • .AddConfiguration(... from here:

    /// <summary>
    /// Adds a JSON configuration source by name to builder.
    /// </summary>
    /// <param name="configurationBuilder">The builder instance used to create an <see cref="IConfiguration"/> with keys and values from a set of sources</param>
    /// <param name="hostingContext">The <see cref="HostBuilderContext"/> which provides information specific to the hosting environment</param>
    /// <param name="configurationName">A name to identify the added configuration source. Optional</param>
    /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
    public static IConfigurationBuilder AddConfiguration(this IConfigurationBuilder configurationBuilder, HostBuilderContext hostingContext, string? configurationName = null)
    {
    var configSection = configurationName is { Length: > 0 } ? string.Format(AppConfiguration.FileNameTemplate, configurationName) : AppConfiguration.FileName;
    return configurationBuilder.AddConfigurationFile(hostingContext, configSection.ToLower());
    }

    recognize Line 31:

    var configSection = configurationName is { Length: > 0 } ? string.Format(AppConfiguration.FileNameTemplate, configurationName) : AppConfiguration.FileName;`

    so in case we provided a Name to ContentSource, this will go into using string.Format(

  • We can find the AppConfiguration.FileNameTemplate and it's always used Prefix right here:
    https://github.com/unoplatform/uno.extensions/blob/9e1337c5d07679dba1c31a0324a4d9ca5993d45b/src/Uno.Extensions.Configuration/AppConfiguration.cs#L3-L9

  • so resulting from this, the example string value me might provided: AppData/Reciepes.json

  • would now in line 31 of the AddConfiguration become: appsettings.AppData/Reciepes.json because this is how string.Format works. It fills the numbers you provide starting from {0}.

  • Of course, this file name now is not longer what we should be expecting, would be invalid and resulting in not loaded Configuration Data at runtime just the issue linked files for example.

  • Then after AddConfiguration function did made our provided filename/path invalid, we will send it over to the private .AddConfigurationFile( here:

    private static IConfigurationBuilder AddConfigurationFile(this IConfigurationBuilder configurationBuilder, HostBuilderContext hostingContext, string configurationFileName)
    {
    var relativePath = $"{ConfigBuilderExtensions.ConfigurationFolderName}/{configurationFileName}";
    var rootFolder = hostingContext.HostingEnvironment.GetAppDataPath();
    if (rootFolder is null)
    {
    return configurationBuilder;
    }
    var fullPath = Path.Combine(rootFolder, relativePath);
    return configurationBuilder.AddJsonFile(fullPath, optional: true, reloadOnChange: false);
    }

    Possibly this might be pointing to a output folder in /bin or /obj (?) but if not, I just want to remark, that the ConfigBuilderExtensions.ConfigurationFoldeName config is not known by the consumer so to expect us possibly to have such folder in place, would be obviously not working.

The Docs I found in the Walkthrought about ContentSource are using it with Generic brackets:

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    // NOT RECOMMENDED FOR WEB ASSEMBLY
    var appBuilder = this.CreateBuilder(e)
        .Configure(
            host => host
                .UseConfiguration(
                    builder => builder
                        .ContentSource<App>()

but effectively, the source shows, that there is no generic overload and the ConfigBuilder Implementation itself is not having such method at all

public static IConfigBuilder ContentSource(this IConfigBuilder hostBuilder, string? config = null, bool includeEnvironmentSettings = true)
{

Expected behavior

  • It should be working flawless, if there is no information about a not useable state when we include slash or non appsettings prefixed files to ContentSource!

  • if the ContentSource provides the string config argument, but does not realistically allow anything which is not having this prefix of appsettings, then we should get made aware of this!

  • There should be any validation logic for the provided input string, except from null or not null:

    1. Check for null (of course this stays)
    2. Check if it .Contains('/') or .Contains('\') -> do not use the hardcoded appsettings Prefix and should potentially also not consider UseEnvironmentSettings!
    3. Check if .ToLower().StartsWith("appsettings") -> either trim this to use the Prefix and not end up with appsettings.appsettings.xyz.json or just use the provided one like in 2.

How to reproduce it (as minimally and precisely as possible)

Environment

Nuget Package (s):

Package Version(s):

Affected platform(s):

  • All Platforms
  • Build tasks

Visual Studio:

  • 2019 (version: )
  • 2022 (version: )
  • Visual Studio Code (version: )
  • Rider Windows (version: )
  • Rider macOS (version: )

Relevant plugins:

  • Resharper (version: )

Anything else we need to know?

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugSomething isn't workingtriage/untriagedIndicates an issue requires triaging or verification.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions