Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IHostApplicationBuilder interface #86974

Merged
merged 2 commits into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,22 @@

namespace Microsoft.Extensions.Configuration
{
public readonly partial struct ConfigurationDebugViewContext
{
private readonly object _dummy;
private readonly int _dummyPrimitive;
public ConfigurationDebugViewContext(string path, string key, string? value, Microsoft.Extensions.Configuration.IConfigurationProvider configurationProvider) { throw null; }
public Microsoft.Extensions.Configuration.IConfigurationProvider ConfigurationProvider { get { throw null; } }
public string Key { get { throw null; } }
public string Path { get { throw null; } }
public string? Value { get { throw null; } }
}
public static partial class ConfigurationExtensions
{
public static Microsoft.Extensions.Configuration.IConfigurationBuilder Add<TSource>(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, System.Action<TSource>? configureSource) where TSource : Microsoft.Extensions.Configuration.IConfigurationSource, new() { throw null; }
public static System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string?>> AsEnumerable(this Microsoft.Extensions.Configuration.IConfiguration configuration) { throw null; }
public static System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string?>> AsEnumerable(this Microsoft.Extensions.Configuration.IConfiguration configuration, bool makePathsRelative) { throw null; }
public static bool Exists([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] this Microsoft.Extensions.Configuration.IConfigurationSection? section) { throw null; }
public static bool Exists([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] this Microsoft.Extensions.Configuration.IConfigurationSection? section) { throw null; }
public static string? GetConnectionString(this Microsoft.Extensions.Configuration.IConfiguration configuration, string name) { throw null; }
public static Microsoft.Extensions.Configuration.IConfigurationSection GetRequiredSection(this Microsoft.Extensions.Configuration.IConfiguration configuration, string key) { throw null; }
}
Expand All @@ -33,15 +43,7 @@ public static partial class ConfigurationPath
public static partial class ConfigurationRootExtensions
{
public static string GetDebugView(this Microsoft.Extensions.Configuration.IConfigurationRoot root) { throw null; }
public static string GetDebugView(this IConfigurationRoot root, System.Func<ConfigurationDebugViewContext, string>? processValue) { throw null; }
}
public readonly partial struct ConfigurationDebugViewContext
{
public ConfigurationDebugViewContext(string path, string key, string? value, IConfigurationProvider configurationProvider) { throw null; }
public string Path { get; }
public string Key { get; }
public string? Value { get; }
public IConfigurationProvider ConfigurationProvider { get; }
public static string GetDebugView(this Microsoft.Extensions.Configuration.IConfigurationRoot root, System.Func<Microsoft.Extensions.Configuration.ConfigurationDebugViewContext, string>? processValue) { throw null; }
}
public partial interface IConfiguration
{
Expand All @@ -57,6 +59,9 @@ public partial interface IConfigurationBuilder
Microsoft.Extensions.Configuration.IConfigurationBuilder Add(Microsoft.Extensions.Configuration.IConfigurationSource source);
Microsoft.Extensions.Configuration.IConfigurationRoot Build();
}
public partial interface IConfigurationManager : Microsoft.Extensions.Configuration.IConfiguration, Microsoft.Extensions.Configuration.IConfigurationBuilder
{
}
public partial interface IConfigurationProvider
{
System.Collections.Generic.IEnumerable<string> GetChildKeys(System.Collections.Generic.IEnumerable<string> earlierKeys, string? parentPath);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.Extensions.Configuration;

/// <summary>
/// Represents a mutable configuration object.
/// </summary>
/// <remarks>
/// It is both an <see cref="IConfigurationBuilder"/> and an <see cref="IConfiguration"/>.
/// As sources are added, it updates its current view of configuration.
/// </remarks>
public interface IConfigurationManager : IConfiguration, IConfigurationBuilder
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ConfigurationKeyComparer() { }
public static Microsoft.Extensions.Configuration.ConfigurationKeyComparer Instance { get { throw null; } }
public int Compare(string? x, string? y) { throw null; }
}
public sealed partial class ConfigurationManager : Microsoft.Extensions.Configuration.IConfiguration, Microsoft.Extensions.Configuration.IConfigurationBuilder, Microsoft.Extensions.Configuration.IConfigurationRoot, System.IDisposable
public sealed partial class ConfigurationManager : Microsoft.Extensions.Configuration.IConfiguration, Microsoft.Extensions.Configuration.IConfigurationBuilder, Microsoft.Extensions.Configuration.IConfigurationManager, Microsoft.Extensions.Configuration.IConfigurationRoot, System.IDisposable
{
public ConfigurationManager() { }
public string? this[string key] { get { throw null; } set { } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@
namespace Microsoft.Extensions.Configuration
{
/// <summary>
/// ConfigurationManager is a mutable configuration object. It is both an <see cref="IConfigurationBuilder"/> and an <see cref="IConfigurationRoot"/>.
/// As sources are added, it updates its current view of configuration.
/// Represents a mutable configuration object.
/// </summary>
/// <remarks>
/// It is both an <see cref="IConfigurationBuilder"/> and an <see cref="IConfigurationRoot"/>.
/// As sources are added, it updates its current view of configuration.
/// </remarks>
[DebuggerDisplay("{DebuggerToString(),nq}")]
[DebuggerTypeProxy(typeof(ConfigurationManagerDebugView))]
public sealed class ConfigurationManager : IConfigurationBuilder, IConfigurationRoot, IDisposable
public sealed class ConfigurationManager : IConfigurationManager, IConfigurationBuilder, IConfigurationRoot, IDisposable
{
// Concurrently modifying config sources or properties is not thread-safe. However, it is thread-safe to read config while modifying sources or properties.
private readonly ConfigurationSources _sources;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ public partial interface IHost : System.IDisposable
System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
System.Threading.Tasks.Task StopAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
}
public partial interface IHostApplicationBuilder
{
Microsoft.Extensions.Configuration.IConfigurationManager Configuration { get; }
Microsoft.Extensions.Hosting.IHostEnvironment Environment { get; }
Microsoft.Extensions.Logging.ILoggingBuilder Logging { get; }
System.Collections.Generic.IDictionary<object, object> Properties { get; }
Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get; }
void ConfigureContainer<TContainerBuilder>(Microsoft.Extensions.DependencyInjection.IServiceProviderFactory<TContainerBuilder> factory, System.Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull;
}
public partial interface IHostApplicationLifetime
{
System.Threading.CancellationToken ApplicationStarted { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Microsoft.Extensions.Hosting;

/// <summary>
/// Represents a hosted applications and services builder which helps manage configuration, logging, lifetime, and more.
/// </summary>
public interface IHostApplicationBuilder
{
/// <summary>
/// Gets a central location for sharing state between components during the host building process.
/// </summary>
IDictionary<object, object> Properties { get; }

/// <summary>
/// Gets the set of key/value configuration properties.
/// </summary>
/// <remarks>
/// This can be mutated by adding more configuration sources, which will update its current view.
/// </remarks>
IConfigurationManager Configuration { get; }

/// <summary>
/// Gets the information about the hosting environment an application is running in.
/// </summary>
IHostEnvironment Environment { get; }

/// <summary>
/// Gets a collection of logging providers for the application to compose. This is useful for adding new logging providers.
/// </summary>
ILoggingBuilder Logging { get; }

/// <summary>
/// Gets a collection of services for the application to compose. This is useful for adding user provided or framework provided services.
/// </summary>
IServiceCollection Services { get; }

/// <summary>
/// Registers a <see cref="IServiceProviderFactory{TContainerBuilder}" /> instance to be used to create the <see cref="IServiceProvider" />.
/// </summary>
/// <param name="factory">The factory object that can create the <typeparamref name="TContainerBuilder"/> and <see cref="IServiceProvider"/>.</param>
/// <param name="configure">
/// A delegate used to configure the <typeparamref T="TContainerBuilder" />. This can be used to configure services using
/// APIS specific to the <see cref="IServiceProviderFactory{TContainerBuilder}" /> implementation.
/// </param>
/// <typeparam name="TContainerBuilder">The type of builder provided by the <see cref="IServiceProviderFactory{TContainerBuilder}" />.</typeparam>
/// <remarks>
/// <para>
/// The <see cref="IServiceProvider"/> is created when this builder is built and so the delegate provided
/// by <paramref name="configure"/> will run after all other services have been registered.
/// </para>
/// <para>
/// Multiple calls to <see cref="ConfigureContainer{TContainerBuilder}(IServiceProviderFactory{TContainerBuilder}, Action{TContainerBuilder})"/> will replace
/// the previously stored <paramref name="factory"/> and <paramref name="configure"/> delegate.
/// </para>
/// </remarks>
void ConfigureContainer<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory, Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Configuration.Abstractions\src\Microsoft.Extensions.Configuration.Abstractions.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.DependencyInjection.Abstractions\src\Microsoft.Extensions.DependencyInjection.Abstractions.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.FileProviders.Abstractions\src\Microsoft.Extensions.FileProviders.Abstractions.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Logging.Abstractions\src\Microsoft.Extensions.Logging.Abstractions.csproj" />
</ItemGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'netstandard2.1'))">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,16 @@ public static partial class Host
public static Microsoft.Extensions.Hosting.IHostBuilder CreateDefaultBuilder(string[]? args) { throw null; }
public static Microsoft.Extensions.Hosting.HostApplicationBuilder CreateEmptyApplicationBuilder(Microsoft.Extensions.Hosting.HostApplicationBuilderSettings? settings) { throw null; }
}
public sealed partial class HostApplicationBuilder
public sealed partial class HostApplicationBuilder : Microsoft.Extensions.Hosting.IHostApplicationBuilder
{
public HostApplicationBuilder() { }
public HostApplicationBuilder(Microsoft.Extensions.Hosting.HostApplicationBuilderSettings? settings) { }
public HostApplicationBuilder(string[]? args) { }
public Microsoft.Extensions.Configuration.ConfigurationManager Configuration { get { throw null; } }
public Microsoft.Extensions.Hosting.IHostEnvironment Environment { get { throw null; } }
public Microsoft.Extensions.Logging.ILoggingBuilder Logging { get { throw null; } }
Microsoft.Extensions.Configuration.IConfigurationManager Microsoft.Extensions.Hosting.IHostApplicationBuilder.Configuration { get { throw null; } }
System.Collections.Generic.IDictionary<object, object> Microsoft.Extensions.Hosting.IHostApplicationBuilder.Properties { get { throw null; } }
public Microsoft.Extensions.DependencyInjection.IServiceCollection Services { get { throw null; } }
public Microsoft.Extensions.Hosting.IHost Build() { throw null; }
public void ConfigureContainer<TContainerBuilder>(Microsoft.Extensions.DependencyInjection.IServiceProviderFactory<TContainerBuilder> factory, System.Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
namespace Microsoft.Extensions.Hosting
{
/// <summary>
/// A builder for hosted applications and services which helps manage configuration, logging, lifetime and more.
/// Represents a hosted applications and services builder which helps manage configuration, logging, lifetime, and more.
/// </summary>
public sealed class HostApplicationBuilder
public sealed class HostApplicationBuilder : IHostApplicationBuilder
{
private readonly HostBuilderContext _hostBuilderContext;
private readonly ServiceCollection _serviceCollection = new();
Expand Down Expand Up @@ -182,45 +182,28 @@ private void Initialize(HostApplicationBuilderSettings settings, out HostBuilder
logging = new LoggingBuilder(Services);
}

/// <summary>
/// Provides information about the hosting environment an application is running in.
/// </summary>
IDictionary<object, object> IHostApplicationBuilder.Properties => _hostBuilderContext.Properties;

/// <inheritdoc />
public IHostEnvironment Environment => _environment;

/// <summary>
/// A collection of services for the application to compose. This is useful for adding user provided or framework provided services.
/// Gets the set of key/value configuration properties.
/// </summary>
/// <remarks>
/// This can be mutated by adding more configuration sources, which will update its current view.
/// </remarks>
public ConfigurationManager Configuration { get; }

/// <summary>
/// A collection of services for the application to compose. This is useful for adding user provided or framework provided services.
/// </summary>
IConfigurationManager IHostApplicationBuilder.Configuration => Configuration;

/// <inheritdoc />
public IServiceCollection Services => _serviceCollection;

/// <summary>
/// A collection of logging providers for the application to compose. This is useful for adding new logging providers.
/// </summary>
/// <inheritdoc />
public ILoggingBuilder Logging => _logging;

/// <summary>
/// Registers a <see cref="IServiceProviderFactory{TContainerBuilder}" /> instance to be used to create the <see cref="IServiceProvider" />.
/// </summary>
/// <param name="factory">The <see cref="IServiceProviderFactory{TContainerBuilder}" />.</param>
/// <param name="configure">
/// A delegate used to configure the <typeparamref T="TContainerBuilder" />. This can be used to configure services using
/// APIS specific to the <see cref="IServiceProviderFactory{TContainerBuilder}" /> implementation.
/// </param>
/// <typeparam name="TContainerBuilder">The type of builder provided by the <see cref="IServiceProviderFactory{TContainerBuilder}" />.</typeparam>
/// <remarks>
/// <para>
/// <see cref="ConfigureContainer{TContainerBuilder}(IServiceProviderFactory{TContainerBuilder}, Action{TContainerBuilder})"/> is called by <see cref="Build"/>
/// and so the delegate provided by <paramref name="configure"/> will run after all other services have been registered.
/// </para>
/// <para>
/// Multiple calls to <see cref="ConfigureContainer{TContainerBuilder}(IServiceProviderFactory{TContainerBuilder}, Action{TContainerBuilder})"/> will replace
/// the previously stored <paramref name="factory"/> and <paramref name="configure"/> delegate.
/// </para>
/// </remarks>
/// <inheritdoc />
public void ConfigureContainer<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory, Action<TContainerBuilder>? configure = null) where TContainerBuilder : notnull
{
_createServiceProvider = () =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting.Fakes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
using Xunit;

namespace Microsoft.Extensions.Hosting.Tests;

public class IHostApplicationBuilderTests
{
[Fact]
public void TestIHostApplicationBuilderCanBeUsedInExtensionMethod()
{
HostApplicationBuilder builder = Host.CreateEmptyApplicationBuilder(new HostApplicationBuilderSettings()
{
EnvironmentName = "Development"
});

builder.VerifyBuilderWorks();

using IHost host = builder.Build();

// VerifyBuilderWorks should have configured a FakeServiceProviderFactory with the following State.
FakeServiceCollection fakeServices = host.Services.GetRequiredService<FakeServiceCollection>();
Assert.Equal("Hi!", fakeServices.State);
}
}

internal static class HostBuilderExtensions
{
public static void VerifyBuilderWorks(this IHostApplicationBuilder builder)
{
var propertyKey = typeof(HostBuilderExtensions);
builder.Properties[propertyKey] = 3;
Assert.Equal(3, builder.Properties[propertyKey]);

Assert.Equal(1, builder.Configuration.GetChildren().Count());
Assert.Equal(2, builder.Configuration.Sources.Count); // there's an empty source by default
Assert.Equal("Development", builder.Configuration[HostDefaults.EnvironmentKey]);

builder.Configuration.AddInMemoryCollection(new Dictionary<string, string>
{
{ "Key1", "value1" }
});

Assert.Equal(2, builder.Configuration.GetChildren().Count());
Assert.Equal(3, builder.Configuration.Sources.Count);
Assert.Equal("value1", builder.Configuration["Key1"]);
Assert.Null(builder.Configuration["Key2"]);

Assert.True(builder.Environment.IsDevelopment());
Assert.NotNull(builder.Environment.ContentRootFileProvider);

Assert.DoesNotContain(builder.Services, sd => sd.ImplementationType == typeof(ConsoleLoggerProvider));
builder.Logging.AddConsole();
Assert.Contains(builder.Services, sd => sd.ImplementationType == typeof(ConsoleLoggerProvider));

builder.Services.AddSingleton(typeof(IHostApplicationBuilderTests));

builder.ConfigureContainer(new FakeServiceProviderFactory(), container => container.State = "Hi!");
}
}
Loading