Skip to content

Commit 2c175f7

Browse files
authored
Enable nullable in hosting (#28068)
1 parent f98959f commit 2c175f7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+513
-417
lines changed

src/DataProtection/DataProtection/test/HostingTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,15 @@ public async Task StartupContinuesOnFailureToLoadKey()
8282
.Throws(new NotSupportedException("This mock doesn't actually work, but shouldn't kill the server"))
8383
.Verifiable();
8484

85+
var mockServer = new Mock<IServer>();
86+
mockServer.Setup(m => m.Features).Returns(new FeatureCollection());
87+
8588
var builder = new HostBuilder()
8689
.ConfigureServices(s =>
8790
s.AddDataProtection()
8891
.Services
8992
.Replace(ServiceDescriptor.Singleton(mockKeyRing.Object))
90-
.AddSingleton(Mock.Of<IServer>()))
93+
.AddSingleton(mockServer.Object))
9194
.ConfigureWebHost(b => b.UseStartup<TestStartup>());
9295

9396
using (var host = builder.Build())

src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ internal class GenericWebHostBuilder : IWebHostBuilder, ISupportsStartup, ISuppo
2323
{
2424
private readonly IHostBuilder _builder;
2525
private readonly IConfiguration _config;
26-
private object _startupObject;
26+
private object? _startupObject;
2727
private readonly object _startupKey = new object();
2828

29-
private AggregateException _hostingStartupErrors;
30-
private HostingStartupWebHostBuilder _hostingStartupWebHostBuilder;
29+
private AggregateException? _hostingStartupErrors;
30+
private HostingStartupWebHostBuilder? _hostingStartupWebHostBuilder;
3131

3232
public GenericWebHostBuilder(IHostBuilder builder, WebHostBuilderOptions options)
3333
{
@@ -122,7 +122,7 @@ public GenericWebHostBuilder(IHostBuilder builder, WebHostBuilderOptions options
122122

123123
private void ExecuteHostingStartups()
124124
{
125-
var webHostOptions = new WebHostOptions(_config, Assembly.GetEntryAssembly()?.GetName().Name);
125+
var webHostOptions = new WebHostOptions(_config, Assembly.GetEntryAssembly()?.GetName().Name ?? string.Empty);
126126

127127
if (webHostOptions.PreventHostingStartup)
128128
{
@@ -141,7 +141,7 @@ private void ExecuteHostingStartups()
141141

142142
foreach (var attribute in assembly.GetCustomAttributes<HostingStartupAttribute>())
143143
{
144-
var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType);
144+
var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType)!;
145145
hostingStartup.Configure(_hostingStartupWebHostBuilder);
146146
}
147147
}
@@ -240,13 +240,13 @@ public IWebHostBuilder UseStartup([DynamicallyAccessedMembers(StartupLinkerOptio
240240
}
241241

242242
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2006:UnrecognizedReflectionPattern", Justification = "We need to call a generic method on IHostBuilder.")]
243-
private void UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, HostBuilderContext context, IServiceCollection services, object instance = null)
243+
private void UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, HostBuilderContext context, IServiceCollection services, object? instance = null)
244244
{
245245
var webHostBuilderContext = GetWebHostBuilderContext(context);
246246
var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)];
247247

248-
ExceptionDispatchInfo startupError = null;
249-
ConfigureBuilder configureBuilder = null;
248+
ExceptionDispatchInfo? startupError = null;
249+
ConfigureBuilder? configureBuilder = null;
250250

251251
try
252252
{
@@ -281,12 +281,12 @@ private void UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessi
281281
var actionType = typeof(Action<,>).MakeGenericType(typeof(HostBuilderContext), containerType);
282282

283283
// Get the private ConfigureContainer method on this type then close over the container type
284-
var configureCallback = typeof(GenericWebHostBuilder).GetMethod(nameof(ConfigureContainerImpl), BindingFlags.NonPublic | BindingFlags.Instance)
284+
var configureCallback = typeof(GenericWebHostBuilder).GetMethod(nameof(ConfigureContainerImpl), BindingFlags.NonPublic | BindingFlags.Instance)!
285285
.MakeGenericMethod(containerType)
286286
.CreateDelegate(actionType, this);
287287

288288
// _builder.ConfigureContainer<T>(ConfigureContainer);
289-
typeof(IHostBuilder).GetMethod(nameof(IHostBuilder.ConfigureContainer))
289+
typeof(IHostBuilder).GetMethod(nameof(IHostBuilder.ConfigureContainer))!
290290
.MakeGenericMethod(containerType)
291291
.InvokeWithoutWrappingExceptions(_builder, new object[] { configureCallback });
292292
}
@@ -316,7 +316,7 @@ private void UseStartup([DynamicallyAccessedMembers(StartupLinkerOptions.Accessi
316316
});
317317
}
318318

319-
private void ConfigureContainerImpl<TContainer>(HostBuilderContext context, TContainer container)
319+
private void ConfigureContainerImpl<TContainer>(HostBuilderContext context, TContainer container) where TContainer : notnull
320320
{
321321
var instance = context.Properties[_startupKey];
322322
var builder = (ConfigureContainerBuilder)context.Properties[typeof(ConfigureContainerBuilder)];
@@ -347,7 +347,7 @@ private WebHostBuilderContext GetWebHostBuilderContext(HostBuilderContext contex
347347
{
348348
if (!context.Properties.TryGetValue(typeof(WebHostBuilderContext), out var contextVal))
349349
{
350-
var options = new WebHostOptions(context.Configuration, Assembly.GetEntryAssembly()?.GetName().Name);
350+
var options = new WebHostOptions(context.Configuration, Assembly.GetEntryAssembly()?.GetName().Name ?? string.Empty);
351351
var webHostBuilderContext = new WebHostBuilderContext
352352
{
353353
Configuration = context.Configuration,
@@ -370,7 +370,7 @@ public string GetSetting(string key)
370370
return _config[key];
371371
}
372372

373-
public IWebHostBuilder UseSetting(string key, string value)
373+
public IWebHostBuilder UseSetting(string key, string? value)
374374
{
375375
_config[key] = value;
376376
return this;
@@ -386,7 +386,7 @@ public HostServiceProvider(WebHostBuilderContext context)
386386
_context = context;
387387
}
388388

389-
public object GetService(Type serviceType)
389+
public object? GetService(Type serviceType)
390390
{
391391
// The implementation of the HostingEnvironment supports both interfaces
392392
#pragma warning disable CS0618 // Type or member is obsolete

src/Hosting/Hosting/src/GenericHost/GenericWebHostServiceOptions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ namespace Microsoft.AspNetCore.Hosting
88
{
99
internal class GenericWebHostServiceOptions
1010
{
11-
public Action<IApplicationBuilder> ConfigureApplication { get; set; }
11+
public Action<IApplicationBuilder>? ConfigureApplication { get; set; }
1212

13-
public WebHostOptions WebHostOptions { get; set; }
13+
public WebHostOptions WebHostOptions { get; set; } = default!; // Always set when options resolved by DI
1414

15-
public AggregateException HostingStartupExceptions { get; set; }
15+
public AggregateException? HostingStartupExceptions { get; set; }
1616
}
1717
}

src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Microsoft.AspNetCore.Hosting.Views;
1717
using Microsoft.AspNetCore.Http;
1818
using Microsoft.Extensions.Configuration;
19+
using Microsoft.Extensions.FileProviders;
1920
using Microsoft.Extensions.Hosting;
2021
using Microsoft.Extensions.Logging;
2122
using Microsoft.Extensions.Options;
@@ -64,14 +65,14 @@ public async Task StartAsync(CancellationToken cancellationToken)
6465
{
6566
HostingEventSource.Log.HostStart();
6667

67-
var serverAddressesFeature = Server.Features?.Get<IServerAddressesFeature>();
68+
var serverAddressesFeature = Server.Features.Get<IServerAddressesFeature>();
6869
var addresses = serverAddressesFeature?.Addresses;
6970
if (addresses != null && !addresses.IsReadOnly && addresses.Count == 0)
7071
{
7172
var urls = Configuration[WebHostDefaults.ServerUrlsKey];
7273
if (!string.IsNullOrEmpty(urls))
7374
{
74-
serverAddressesFeature.PreferHostingUrls = WebHostUtilities.ParseBool(Configuration, WebHostDefaults.PreferHostingUrlsKey);
75+
serverAddressesFeature!.PreferHostingUrls = WebHostUtilities.ParseBool(Configuration, WebHostDefaults.PreferHostingUrlsKey);
7576

7677
foreach (var value in urls.Split(';', StringSplitOptions.RemoveEmptyEntries))
7778
{
@@ -80,11 +81,11 @@ public async Task StartAsync(CancellationToken cancellationToken)
8081
}
8182
}
8283

83-
RequestDelegate application = null;
84+
RequestDelegate? application = null;
8485

8586
try
8687
{
87-
Action<IApplicationBuilder> configure = Options.ConfigureApplication;
88+
var configure = Options.ConfigureApplication;
8889

8990
if (configure == null)
9091
{
@@ -112,7 +113,9 @@ public async Task StartAsync(CancellationToken cancellationToken)
112113
throw;
113114
}
114115

115-
application = BuildErrorPageApplication(ex);
116+
var showDetailedErrors = HostingEnvironment.IsDevelopment() || Options.WebHostOptions.DetailedErrors;
117+
118+
application = ErrorPageBuilder.BuildErrorPageApplication(HostingEnvironment.ContentRootFileProvider, Logger, showDetailedErrors, ex);
116119
}
117120

118121
var httpApplication = new HostingApplication(application, Logger, DiagnosticListener, HttpContextFactory);
@@ -144,56 +147,6 @@ public async Task StartAsync(CancellationToken cancellationToken)
144147
}
145148
}
146149

147-
private RequestDelegate BuildErrorPageApplication(Exception exception)
148-
{
149-
if (exception is TargetInvocationException tae)
150-
{
151-
exception = tae.InnerException;
152-
}
153-
154-
var showDetailedErrors = HostingEnvironment.IsDevelopment() || Options.WebHostOptions.DetailedErrors;
155-
156-
var model = new ErrorPageModel
157-
{
158-
RuntimeDisplayName = RuntimeInformation.FrameworkDescription
159-
};
160-
var systemRuntimeAssembly = typeof(System.ComponentModel.DefaultValueAttribute).Assembly;
161-
var assemblyVersion = new AssemblyName(systemRuntimeAssembly.FullName).Version.ToString();
162-
var clrVersion = assemblyVersion;
163-
model.RuntimeArchitecture = RuntimeInformation.ProcessArchitecture.ToString();
164-
var currentAssembly = typeof(ErrorPage).Assembly;
165-
model.CurrentAssemblyVesion = currentAssembly
166-
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
167-
.InformationalVersion;
168-
model.ClrVersion = clrVersion;
169-
model.OperatingSystemDescription = RuntimeInformation.OSDescription;
170-
model.ShowRuntimeDetails = showDetailedErrors;
171-
172-
if (showDetailedErrors)
173-
{
174-
var exceptionDetailProvider = new ExceptionDetailsProvider(
175-
HostingEnvironment.ContentRootFileProvider,
176-
Logger,
177-
sourceCodeLineCount: 6);
178-
179-
model.ErrorDetails = exceptionDetailProvider.GetDetails(exception);
180-
}
181-
else
182-
{
183-
model.ErrorDetails = Array.Empty<ExceptionDetails>();
184-
}
185-
186-
var errorPage = new ErrorPage(model);
187-
return context =>
188-
{
189-
context.Response.StatusCode = 500;
190-
context.Response.Headers[HeaderNames.CacheControl] = "no-cache,no-store";
191-
context.Response.Headers[HeaderNames.Pragma] = "no-cache";
192-
context.Response.ContentType = "text/html; charset=utf-8";
193-
return errorPage.ExecuteAsync(context);
194-
};
195-
}
196-
197150
public async Task StopAsync(CancellationToken cancellationToken)
198151
{
199152
try

src/Hosting/Hosting/src/GenericHost/HostingStartupWebHostBuilder.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace Microsoft.AspNetCore.Hosting
1515
internal class HostingStartupWebHostBuilder : IWebHostBuilder, ISupportsStartup, ISupportsUseDefaultServiceProvider
1616
{
1717
private readonly GenericWebHostBuilder _builder;
18-
private Action<WebHostBuilderContext, IConfigurationBuilder> _configureConfiguration;
19-
private Action<WebHostBuilderContext, IServiceCollection> _configureServices;
18+
private Action<WebHostBuilderContext, IConfigurationBuilder>? _configureConfiguration;
19+
private Action<WebHostBuilderContext, IServiceCollection>? _configureServices;
2020

2121
public HostingStartupWebHostBuilder(GenericWebHostBuilder builder)
2222
{
@@ -47,7 +47,7 @@ public IWebHostBuilder ConfigureServices(Action<WebHostBuilderContext, IServiceC
4747

4848
public string GetSetting(string key) => _builder.GetSetting(key);
4949

50-
public IWebHostBuilder UseSetting(string key, string value)
50+
public IWebHostBuilder UseSetting(string key, string? value)
5151
{
5252
_builder.UseSetting(key, value);
5353
return this;

src/Hosting/Hosting/src/Internal/ConfigureBuilder.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ public ConfigureBuilder(MethodInfo configure)
1818

1919
public MethodInfo MethodInfo { get; }
2020

21-
public Action<IApplicationBuilder> Build(object instance) => builder => Invoke(instance, builder);
21+
public Action<IApplicationBuilder> Build(object? instance) => builder => Invoke(instance, builder);
2222

23-
private void Invoke(object instance, IApplicationBuilder builder)
23+
private void Invoke(object? instance, IApplicationBuilder builder)
2424
{
2525
// Create a scope for Configure, this allows creating scoped dependencies
2626
// without the hassle of manually creating a scope.
@@ -50,7 +50,7 @@ private void Invoke(object instance, IApplicationBuilder builder)
5050
parameterInfo.ParameterType.FullName,
5151
parameterInfo.Name,
5252
MethodInfo.Name,
53-
MethodInfo.DeclaringType.FullName), ex);
53+
MethodInfo.DeclaringType?.FullName), ex);
5454
}
5555
}
5656
}

src/Hosting/Hosting/src/Internal/ConfigureContainerBuilder.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,28 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Diagnostics;
56
using System.Reflection;
67

78
namespace Microsoft.AspNetCore.Hosting
89
{
910
internal class ConfigureContainerBuilder
1011
{
11-
public ConfigureContainerBuilder(MethodInfo configureContainerMethod)
12+
public ConfigureContainerBuilder(MethodInfo? configureContainerMethod)
1213
{
1314
MethodInfo = configureContainerMethod;
1415
}
1516

16-
public MethodInfo MethodInfo { get; }
17+
public MethodInfo? MethodInfo { get; }
1718

1819
public Func<Action<object>, Action<object>> ConfigureContainerFilters { get; set; } = f => f;
1920

2021
public Action<object> Build(object instance) => container => Invoke(instance, container);
2122

2223
public Type GetContainerType()
2324
{
25+
Debug.Assert(MethodInfo != null, "Shouldn't be called when there is no Configure method.");
26+
2427
var parameters = MethodInfo.GetParameters();
2528
if (parameters.Length != 1)
2629
{

src/Hosting/Hosting/src/Internal/ConfigureServicesBuilder.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ namespace Microsoft.AspNetCore.Hosting
1010
{
1111
internal class ConfigureServicesBuilder
1212
{
13-
public ConfigureServicesBuilder(MethodInfo configureServices)
13+
public ConfigureServicesBuilder(MethodInfo? configureServices)
1414
{
1515
MethodInfo = configureServices;
1616
}
1717

18-
public MethodInfo MethodInfo { get; }
18+
public MethodInfo? MethodInfo { get; }
1919

20-
public Func<Func<IServiceCollection, IServiceProvider>, Func<IServiceCollection, IServiceProvider>> StartupServiceFilters { get; set; } = f => f;
20+
public Func<Func<IServiceCollection, IServiceProvider?>, Func<IServiceCollection, IServiceProvider?>> StartupServiceFilters { get; set; } = f => f;
2121

22-
public Func<IServiceCollection, IServiceProvider> Build(object instance) => services => Invoke(instance, services);
22+
public Func<IServiceCollection, IServiceProvider?> Build(object instance) => services => Invoke(instance, services);
2323

24-
private IServiceProvider Invoke(object instance, IServiceCollection services)
24+
private IServiceProvider? Invoke(object instance, IServiceCollection services)
2525
{
2626
return StartupServiceFilters(Startup)(services);
2727

28-
IServiceProvider Startup(IServiceCollection serviceCollection) => InvokeCore(instance, serviceCollection);
28+
IServiceProvider? Startup(IServiceCollection serviceCollection) => InvokeCore(instance, serviceCollection);
2929
}
3030

31-
private IServiceProvider InvokeCore(object instance, IServiceCollection services)
31+
private IServiceProvider? InvokeCore(object instance, IServiceCollection services)
3232
{
3333
if (MethodInfo == null)
3434
{
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Reflection;
7+
using System.Runtime.InteropServices;
8+
using Microsoft.AspNetCore.Hosting.Views;
9+
using Microsoft.AspNetCore.Http;
10+
using Microsoft.Extensions.FileProviders;
11+
using Microsoft.Extensions.Logging;
12+
using Microsoft.Extensions.StackTrace.Sources;
13+
using Microsoft.Net.Http.Headers;
14+
15+
namespace Microsoft.AspNetCore.Hosting
16+
{
17+
internal static class ErrorPageBuilder
18+
{
19+
public static RequestDelegate BuildErrorPageApplication(
20+
IFileProvider contentRootFileProvider,
21+
ILogger logger,
22+
bool showDetailedErrors,
23+
Exception exception)
24+
{
25+
if (exception is TargetInvocationException tae)
26+
{
27+
exception = tae.InnerException!;
28+
}
29+
30+
var model = ErrorPageModelBuilder.CreateErrorPageModel(contentRootFileProvider, logger, showDetailedErrors, exception);
31+
32+
var errorPage = new ErrorPage(model);
33+
return context =>
34+
{
35+
context.Response.StatusCode = 500;
36+
context.Response.Headers[HeaderNames.CacheControl] = "no-cache,no-store";
37+
context.Response.Headers[HeaderNames.Pragma] = "no-cache";
38+
context.Response.ContentType = "text/html; charset=utf-8";
39+
return errorPage.ExecuteAsync(context);
40+
};
41+
}
42+
}
43+
}

src/Hosting/Hosting/src/Internal/HostedServiceExecutor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public Task StopAsync(CancellationToken token)
3333

3434
private async Task ExecuteAsync(Func<IHostedService, Task> callback, bool throwOnFirstFailure = true)
3535
{
36-
List<Exception> exceptions = null;
36+
List<Exception>? exceptions = null;
3737

3838
foreach (var service in _services)
3939
{

0 commit comments

Comments
 (0)