-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Minimal hosting #31825
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
Merged
Merged
Minimal hosting #31825
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
dbbe9fa
Port WebApplication WIP
halter73 2858a94
Remove private copy of Host's ConfigureDefaults
halter73 def631b
Add sample. "Fix" startup.
halter73 c9b9432
Add IAsyncDisposable support
halter73 dbf2382
Add unit tests and make IServer replaceable
halter73 c53f5a9
Hide WebApplication.Dispose in favor of DisposeAsync
halter73 3cc8665
seal WebApplication and WebApplicationBuilder
halter73 cae4c27
Add logging config functional test
halter73 14d6d72
Update MinimalSample to use WebApplication!!!
halter73 9cebfd1
Seal Configuration and add WebApplicationBuilder_CanClearDefaultLogge…
halter73 dcb450d
Explain why it's OK to noop in ConfigurationHostBuilder
halter73 abc566b
Match the proposed API
halter73 30d67c9
Make Configure(Web)?HostBuilder public
halter73 a02158b
missed one
halter73 5e11585
Fix host builder case sensitivity and add tests.
halter73 6da3d33
"NotFound" -> string.Empty
halter73 6af9e02
Address PR feedback
halter73 ebbda68
Fix handling of ASPNETCORE_ environment variables
halter73 8aeaa4a
Add WebHostEnvironment.ApplyConfigurationSettings
halter73 1184f79
cleanup
halter73 b430995
React to API review feedback
halter73 ed47002
Addresses IEnumerable<string> -> ICollection<string>
halter73 c9f8fdc
Addresses -> Urls
halter73 a1136f7
Make Urls non-nullable
halter73 bae765b
Add more tests
halter73 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
|
||
namespace Microsoft.AspNetCore.Hosting | ||
{ | ||
// This exists solely to bootstrap the configuration | ||
internal class BootstrapHostBuilder : IHostBuilder | ||
{ | ||
public IDictionary<object, object> Properties { get; } = new Dictionary<object, object>(); | ||
private readonly HostBuilderContext _context; | ||
private readonly Configuration _configuration; | ||
private readonly WebHostEnvironment _environment; | ||
|
||
public BootstrapHostBuilder(Configuration configuration, WebHostEnvironment webHostEnvironment) | ||
{ | ||
_configuration = configuration; | ||
_environment = webHostEnvironment; | ||
_context = new HostBuilderContext(Properties) | ||
{ | ||
Configuration = configuration, | ||
HostingEnvironment = webHostEnvironment | ||
}; | ||
} | ||
|
||
public IHost Build() | ||
{ | ||
// HostingHostBuilderExtensions.ConfigureDefaults should never call this. | ||
throw new InvalidOperationException(); | ||
} | ||
|
||
public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate) | ||
{ | ||
configureDelegate(_context, _configuration); | ||
_environment.ApplyConfigurationSettings(_configuration); | ||
_configuration.ChangeBasePath(_environment.ContentRootPath); | ||
return this; | ||
} | ||
|
||
public IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate) | ||
{ | ||
// This is not called by HostingHostBuilderExtensions.ConfigureDefaults currently, but that could change in the future. | ||
// If this does get called in the future, it should be called again at a later stage on the ConfigureHostBuilder. | ||
return this; | ||
} | ||
|
||
public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate) | ||
{ | ||
configureDelegate(_configuration); | ||
_environment.ApplyConfigurationSettings(_configuration); | ||
_configuration.ChangeBasePath(_environment.ContentRootPath); | ||
return this; | ||
} | ||
|
||
public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate) | ||
{ | ||
// HostingHostBuilderExtensions.ConfigureDefaults calls this via ConfigureLogging | ||
// during the initial config stage. It should be called again later on the ConfigureHostBuilder. | ||
return this; | ||
} | ||
|
||
public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory) where TContainerBuilder : notnull | ||
{ | ||
// This is not called by HostingHostBuilderExtensions.ConfigureDefaults currently, but that chould change in the future. | ||
// If this does get called in the future, it should be called again at a later stage on the ConfigureHostBuilder. | ||
return this; | ||
} | ||
|
||
public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> factory) where TContainerBuilder : notnull | ||
{ | ||
// HostingHostBuilderExtensions.ConfigureDefaults calls this via UseDefaultServiceProvider | ||
// during the initial config stage. It should be called again later on the ConfigureHostBuilder. | ||
return this; | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.FileProviders; | ||
using Microsoft.Extensions.Primitives; | ||
|
||
// TODO: Microsft.Extensions.Configuration API Proposal | ||
namespace Microsoft.AspNetCore.Builder | ||
{ | ||
/// <summary> | ||
/// Configuration is mutable configuration object. It is both a configuration builder and an IConfigurationRoot. | ||
/// As sources are added, it updates its current view of configuration. Once Build is called, configuration is frozen. | ||
/// </summary> | ||
public sealed class Configuration : IConfigurationRoot, IConfigurationBuilder | ||
{ | ||
private readonly ConfigurationBuilder _builder = new(); | ||
private IConfigurationRoot _configuration; | ||
|
||
/// <summary> | ||
/// Gets or sets a configuration value. | ||
/// </summary> | ||
/// <param name="key">The configuration key.</param> | ||
/// <returns>The configuration value.</returns> | ||
public string this[string key] { get => _configuration[key]; set => _configuration[key] = value; } | ||
|
||
/// <summary> | ||
/// Gets a configuration sub-section with the specified key. | ||
/// </summary> | ||
/// <param name="key">The key of the configuration section.</param> | ||
/// <returns>The <see cref="IConfigurationSection"/>.</returns> | ||
/// <remarks> | ||
/// This method will never return <c>null</c>. If no matching sub-section is found with the specified key, | ||
/// an empty <see cref="IConfigurationSection"/> will be returned. | ||
/// </remarks> | ||
public IConfigurationSection GetSection(string key) | ||
{ | ||
return _configuration.GetSection(key); | ||
} | ||
|
||
/// <summary> | ||
/// Gets the immediate descendant configuration sub-sections. | ||
/// </summary> | ||
/// <returns>The configuration sub-sections.</returns> | ||
public IEnumerable<IConfigurationSection> GetChildren() => _configuration.GetChildren(); | ||
|
||
IDictionary<string, object> IConfigurationBuilder.Properties => _builder.Properties; | ||
|
||
// TODO: Handle modifications to Sources and keep the configuration root in sync | ||
IList<IConfigurationSource> IConfigurationBuilder.Sources => Sources; | ||
|
||
internal IList<IConfigurationSource> Sources { get; } | ||
|
||
IEnumerable<IConfigurationProvider> IConfigurationRoot.Providers => _configuration.Providers; | ||
|
||
/// <summary> | ||
/// Creates a new <see cref="Configuration"/>. | ||
/// </summary> | ||
public Configuration() | ||
{ | ||
_configuration = _builder.Build(); | ||
|
||
var sources = new ConfigurationSources(_builder.Sources, UpdateConfigurationRoot); | ||
|
||
Sources = sources; | ||
} | ||
|
||
internal void ChangeBasePath(string path) | ||
{ | ||
this.SetBasePath(path); | ||
UpdateConfigurationRoot(); | ||
} | ||
|
||
internal void ChangeFileProvider(IFileProvider fileProvider) | ||
{ | ||
this.SetFileProvider(fileProvider); | ||
UpdateConfigurationRoot(); | ||
} | ||
|
||
private void UpdateConfigurationRoot() | ||
{ | ||
var current = _configuration; | ||
if (current is IDisposable disposable) | ||
{ | ||
disposable.Dispose(); | ||
} | ||
_configuration = _builder.Build(); | ||
} | ||
|
||
IConfigurationBuilder IConfigurationBuilder.Add(IConfigurationSource source) | ||
{ | ||
Sources.Add(source); | ||
return this; | ||
} | ||
|
||
IConfigurationRoot IConfigurationBuilder.Build() | ||
{ | ||
// No more modification is expected after this final build | ||
UpdateConfigurationRoot(); | ||
return this; | ||
} | ||
|
||
IChangeToken IConfiguration.GetReloadToken() | ||
{ | ||
// REVIEW: Is this correct? | ||
return _configuration.GetReloadToken(); | ||
} | ||
|
||
void IConfigurationRoot.Reload() | ||
{ | ||
_configuration.Reload(); | ||
} | ||
|
||
// On source modifications, we rebuild configuration | ||
private class ConfigurationSources : IList<IConfigurationSource> | ||
{ | ||
private readonly IList<IConfigurationSource> _sources; | ||
private readonly Action _sourcesModified; | ||
|
||
public ConfigurationSources(IList<IConfigurationSource> sources, Action sourcesModified) | ||
{ | ||
_sources = sources; | ||
_sourcesModified = sourcesModified; | ||
} | ||
|
||
public IConfigurationSource this[int index] | ||
{ | ||
get => _sources[index]; | ||
set | ||
{ | ||
_sources[index] = value; | ||
_sourcesModified(); | ||
} | ||
} | ||
|
||
public int Count => _sources.Count; | ||
|
||
public bool IsReadOnly => _sources.IsReadOnly; | ||
|
||
public void Add(IConfigurationSource item) | ||
{ | ||
_sources.Add(item); | ||
_sourcesModified(); | ||
} | ||
|
||
public void Clear() | ||
{ | ||
_sources.Clear(); | ||
_sourcesModified(); | ||
} | ||
|
||
public bool Contains(IConfigurationSource item) | ||
{ | ||
return _sources.Contains(item); | ||
} | ||
|
||
public void CopyTo(IConfigurationSource[] array, int arrayIndex) | ||
{ | ||
_sources.CopyTo(array, arrayIndex); | ||
} | ||
|
||
public IEnumerator<IConfigurationSource> GetEnumerator() | ||
{ | ||
return _sources.GetEnumerator(); | ||
} | ||
|
||
public int IndexOf(IConfigurationSource item) | ||
{ | ||
return _sources.IndexOf(item); | ||
} | ||
|
||
public void Insert(int index, IConfigurationSource item) | ||
{ | ||
_sources.Insert(index, item); | ||
_sourcesModified(); | ||
} | ||
|
||
public bool Remove(IConfigurationSource item) | ||
{ | ||
var removed = _sources.Remove(item); | ||
_sourcesModified(); | ||
return removed; | ||
} | ||
|
||
public void RemoveAt(int index) | ||
{ | ||
_sources.RemoveAt(index); | ||
_sourcesModified(); | ||
} | ||
|
||
IEnumerator IEnumerable.GetEnumerator() | ||
{ | ||
return GetEnumerator(); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.