Repository: dotnet/aspnetcore
File: src/Hosting/TestHost/src/WebHostBuilderExtensions.cs (C#)

Code before:
    /// <param name="applicationBasePath">The root of the app's directory.</param>
    /// <param name="solutionName">The name of the solution file to make the content root relative to.</param>
    /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
    [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
    public static IWebHostBuilder UseSolutionRelativeContentRoot(
        this IWebHostBuilder builder,
        string solutionRelativePath,
        string applicationBasePath,
        string solutionName)
    {
        return builder.UseSolutionRelativeContentRoot(solutionRelativePath, applicationBasePath, [solutionName]);
    }

    /// <summary>
    /// Sets the content root of relative to the <paramref name="solutionRelativePath" />.
    /// </summary>
    /// <param name="builder">The <see cref="IWebHostBuilder"/>.</param>
    /// <param name="solutionRelativePath">The directory of the solution file.</param>
    /// <param name="applicationBasePath">The root of the app's directory.</param>
    /// <param name="solutionNames">The names of the solution files to make the content root relative to. If empty, defaults to *.sln and *.slnx.</param>
    /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
    [SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Required to maintain compatibility")]
    public static IWebHostBuilder UseSolutionRelativeContentRoot(
        this IWebHostBuilder builder,
        string solutionRelativePath,
        string applicationBasePath,
        ReadOnlySpan<string> solutionNames = default)
    {
        ArgumentNullException.ThrowIfNull(solutionRelativePath);
        ArgumentNullException.ThrowIfNull(applicationBasePath);

        if (solutionNames.IsEmpty)
        {
            solutionNames = _defaultSolutionNames;
        }

        var directoryInfo = new DirectoryInfo(applicationBasePath);
        do
        {
            foreach (var solutionName in solutionNames)
            {
                var solutionPath = Directory.EnumerateFiles(directoryInfo.FullName, solutionName).FirstOrDefault();
                if (solutionPath != null)
                {
                    builder.UseContentRoot(Path.GetFullPath(Path.Combine(directoryInfo.FullName, solutionRelativePath)));
                    return builder;
                }
            }

            directoryInfo = directoryInfo.Parent;
        }

Review comment (security):
Should this use `IReadOnlyCollection<string>` or similar instead? It's not exactly performance sensitive.

Code after:
    /// <param name="applicationBasePath">The root of the app's directory.</param>
    /// <param name="solutionName">The name of the solution file to make the content root relative to.</param>
    /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
    public static IWebHostBuilder UseSolutionRelativeContentRoot(
        this IWebHostBuilder builder,
        string solutionRelativePath,
        string applicationBasePath,
        string solutionName)
    {
        return builder.UseSolutionRelativeContentRoot(solutionRelativePath, applicationBasePath, [solutionName]);
    }

    /// <summary>
    /// Sets the content root of relative to the <paramref name="solutionRelativePath" />.
    /// </summary>
    /// <param name="builder">The <see cref="IWebHostBuilder"/>.</param>
    /// <param name="solutionRelativePath">The directory of the solution file.</param>
    /// <param name="applicationBasePath">The root of the app's directory.</param>
    /// <param name="solutionNames">The names of the solution files to make the content root relative to. If empty, defaults to *.sln and *.slnx.</param>
    /// <returns>The <see cref="IWebHostBuilder"/>.</returns>
    [SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads", Justification = "Required to maintain compatibility")]
    public static IWebHostBuilder UseSolutionRelativeContentRoot(
        this IWebHostBuilder builder,
        string solutionRelativePath,
        string applicationBasePath,
        ReadOnlySpan<string> solutionNames = default)
    {
        ArgumentNullException.ThrowIfNull(solutionRelativePath);
        ArgumentNullException.ThrowIfNull(applicationBasePath);

        if (solutionNames.IsEmpty)
        {
            solutionNames = _defaultSolutionNames;
        }

        var directoryInfo = new DirectoryInfo(applicationBasePath);
        do
        {
            foreach (var solutionName in solutionNames)
            {
                var solutionPath = Directory.EnumerateFiles(directoryInfo.FullName, solutionName).FirstOrDefault();
                if (solutionPath != null)
                {
                    builder.UseContentRoot(Path.GetFullPath(Path.Combine(directoryInfo.FullName, solutionRelativePath)));
                    return builder;
                }
            }

            directoryInfo = directoryInfo.Parent;
        }
        while (directoryInfo is not null);