diff --git a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs index 319806f2ae8e5..ac217fa34612e 100644 --- a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs +++ b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs @@ -66,7 +66,8 @@ public abstract partial class HttpMessageHandlerBuilder { protected HttpMessageHandlerBuilder() { } public abstract System.Collections.Generic.IList AdditionalHandlers { get; } - public abstract string Name { get; set; } + [System.Diagnostics.CodeAnalysis.DisallowNull] + public abstract string? Name { get; set; } public abstract System.Net.Http.HttpMessageHandler PrimaryHandler { get; set; } public virtual System.IServiceProvider Services { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } public abstract System.Net.Http.HttpMessageHandler Build(); diff --git a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.csproj b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.csproj index 6a1e04cab8df7..e11bcbec0e67a 100644 --- a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.csproj +++ b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) + enable diff --git a/src/libraries/Microsoft.Extensions.Http/src/ActiveHandlerTrackingEntry.cs b/src/libraries/Microsoft.Extensions.Http/src/ActiveHandlerTrackingEntry.cs index c5f57d03453e7..54453271946e8 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/ActiveHandlerTrackingEntry.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/ActiveHandlerTrackingEntry.cs @@ -13,16 +13,16 @@ namespace Microsoft.Extensions.Http // for the 'expiry' pool simplifies the threading requirements significantly. internal sealed class ActiveHandlerTrackingEntry { - private static readonly TimerCallback _timerCallback = (s) => ((ActiveHandlerTrackingEntry)s).Timer_Tick(); + private static readonly TimerCallback _timerCallback = (s) => ((ActiveHandlerTrackingEntry)s!).Timer_Tick(); private readonly object _lock; private bool _timerInitialized; - private Timer _timer; - private TimerCallback _callback; + private Timer? _timer; + private TimerCallback? _callback; public ActiveHandlerTrackingEntry( string name, LifetimeTrackingHttpMessageHandler handler, - IServiceScope scope, + IServiceScope? scope, TimeSpan lifetime) { Name = name; @@ -39,7 +39,7 @@ public ActiveHandlerTrackingEntry( public string Name { get; } - public IServiceScope Scope { get; } + public IServiceScope? Scope { get; } public void StartExpiryTimer(TimerCallback callback) { diff --git a/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpClientFactory.cs b/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpClientFactory.cs index 943a68ebf6ab9..dcbf57b7e22b6 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpClientFactory.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpClientFactory.cs @@ -17,7 +17,7 @@ namespace Microsoft.Extensions.Http { internal class DefaultHttpClientFactory : IHttpClientFactory, IHttpMessageHandlerFactory { - private static readonly TimerCallback _cleanupCallback = (s) => ((DefaultHttpClientFactory)s).CleanupTimer_Tick(); + private static readonly TimerCallback _cleanupCallback = (s) => ((DefaultHttpClientFactory)s!).CleanupTimer_Tick(); private readonly ILogger _logger; private readonly IServiceProvider _services; private readonly IServiceScopeFactory _scopeFactory; @@ -37,7 +37,7 @@ internal class DefaultHttpClientFactory : IHttpClientFactory, IHttpMessageHandle // // There's no need for the factory itself to be disposable. If you stop using it, eventually everything will // get reclaimed. - private Timer _cleanupTimer; + private Timer? _cleanupTimer; private readonly object _cleanupTimerLock; private readonly object _cleanupActiveLock; @@ -116,7 +116,7 @@ public HttpMessageHandler CreateHandler(string name!!) internal ActiveHandlerTrackingEntry CreateHandlerEntry(string name) { IServiceProvider services = _services; - var scope = (IServiceScope)null; + var scope = (IServiceScope?)null; HttpClientFactoryOptions options = _optionsMonitor.Get(name); if (!options.SuppressHandlerScope) @@ -169,15 +169,15 @@ void Configure(HttpMessageHandlerBuilder b) } // Internal for tests - internal void ExpiryTimer_Tick(object state) + internal void ExpiryTimer_Tick(object? state) { - var active = (ActiveHandlerTrackingEntry)state; + var active = (ActiveHandlerTrackingEntry)state!; // The timer callback should be the only one removing from the active collection. If we can't find // our entry in the collection, then this is a bug. - bool removed = _activeHandlers.TryRemove(active.Name, out Lazy found); + bool removed = _activeHandlers.TryRemove(active.Name, out Lazy? found); Debug.Assert(removed, "Entry not found. We should always be able to remove the entry"); - Debug.Assert(object.ReferenceEquals(active, found.Value), "Different entry found. The entry should not have been replaced"); + Debug.Assert(object.ReferenceEquals(active, found!.Value), "Different entry found. The entry should not have been replaced"); // At this point the handler is no longer 'active' and will not be handed out to any new clients. // However we haven't dropped our strong reference to the handler, so we can't yet determine if @@ -216,7 +216,7 @@ internal virtual void StopCleanupTimer() { lock (_cleanupTimerLock) { - _cleanupTimer.Dispose(); + _cleanupTimer!.Dispose(); _cleanupTimer = null; } } @@ -257,7 +257,7 @@ internal void CleanupTimer_Tick() for (int i = 0; i < initialCount; i++) { // Since we're the only one removing from _expired, TryDequeue must always succeed. - _expiredHandlers.TryDequeue(out ExpiredHandlerTrackingEntry entry); + _expiredHandlers.TryDequeue(out ExpiredHandlerTrackingEntry? entry); Debug.Assert(entry != null, "Entry was null, we should always get an entry back from TryDequeue"); if (entry.CanDispose) @@ -305,12 +305,12 @@ public static class EventIds public static readonly EventId HandlerExpired = new EventId(103, "HandlerExpired"); } - private static readonly Action _cleanupCycleStart = LoggerMessage.Define( + private static readonly Action _cleanupCycleStart = LoggerMessage.Define( LogLevel.Debug, EventIds.CleanupCycleStart, "Starting HttpMessageHandler cleanup cycle with {InitialCount} items"); - private static readonly Action _cleanupCycleEnd = LoggerMessage.Define( + private static readonly Action _cleanupCycleEnd = LoggerMessage.Define( LogLevel.Debug, EventIds.CleanupCycleEnd, "Ending HttpMessageHandler cleanup cycle after {ElapsedMilliseconds}ms - processed: {DisposedCount} items - remaining: {RemainingItems} items"); @@ -320,7 +320,7 @@ public static class EventIds EventIds.CleanupItemFailed, "HttpMessageHandler.Dispose() threw an unhandled exception for client: '{ClientName}'"); - private static readonly Action _handlerExpired = LoggerMessage.Define( + private static readonly Action _handlerExpired = LoggerMessage.Define( LogLevel.Debug, EventIds.HandlerExpired, "HttpMessageHandler expired after {HandlerLifetime}ms for client '{ClientName}'"); diff --git a/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpMessageHandlerBuilder.cs b/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpMessageHandlerBuilder.cs index 3b8f2324289b1..5fb76dac971aa 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpMessageHandlerBuilder.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DefaultHttpMessageHandlerBuilder.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net.Http; namespace Microsoft.Extensions.Http @@ -14,9 +15,10 @@ public DefaultHttpMessageHandlerBuilder(IServiceProvider services) Services = services; } - private string _name; + private string? _name; - public override string Name + [DisallowNull] + public override string? Name { get => _name; set diff --git a/src/libraries/Microsoft.Extensions.Http/src/DefaultTypedHttpClientFactory.cs b/src/libraries/Microsoft.Extensions.Http/src/DefaultTypedHttpClientFactory.cs index 4b913fc8d4dc9..dcc6f89781408 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DefaultTypedHttpClientFactory.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DefaultTypedHttpClientFactory.cs @@ -33,15 +33,15 @@ public class Cache { private static readonly Func _createActivator = () => ActivatorUtilities.CreateFactory(typeof(TClient), new Type[] { typeof(HttpClient), }); - private ObjectFactory _activator; + private ObjectFactory? _activator; private bool _initialized; - private object _lock; + private object? _lock; public ObjectFactory Activator => LazyInitializer.EnsureInitialized( ref _activator, ref _initialized, ref _lock, - _createActivator); + _createActivator)!; } } } diff --git a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientBuilderExtensions.cs b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientBuilderExtensions.cs index 8162d9af2ec84..281c29573b8d7 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientBuilderExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientBuilderExtensions.cs @@ -488,11 +488,11 @@ public static IHttpClientBuilder SetHandlerLifetime(this IHttpClientBuilder buil // See comments on HttpClientMappingRegistry. private static void ReserveClient(IHttpClientBuilder builder, Type type, string name, bool validateSingleType) { - var registry = (HttpClientMappingRegistry)builder.Services.Single(sd => sd.ServiceType == typeof(HttpClientMappingRegistry)).ImplementationInstance; + var registry = (HttpClientMappingRegistry?)builder.Services.Single(sd => sd.ServiceType == typeof(HttpClientMappingRegistry)).ImplementationInstance; Debug.Assert(registry != null); // Check for same name registered to two types. This won't work because we rely on named options for the configuration. - if (registry.NamedClientRegistrations.TryGetValue(name, out Type otherType) && + if (registry.NamedClientRegistrations.TryGetValue(name, out Type? otherType) && // Allow using the same name with multiple types in some cases (see callers). validateSingleType && diff --git a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs index fa21613fa936e..eaa1fa2f465b0 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/DependencyInjection/HttpClientFactoryServiceCollectionExtensions.cs @@ -508,7 +508,7 @@ public static IHttpClientBuilder AddHttpClient(this IServiceCollection services! var builder = new DefaultHttpClientBuilder(services, name); builder.ConfigureHttpClient(configureClient); - builder.AddTypedClientCore(validateSingleType: false); // name was explictly provided + builder.AddTypedClientCore(validateSingleType: false); // name was explicitly provided return builder; } diff --git a/src/libraries/Microsoft.Extensions.Http/src/ExpiredHandlerTrackingEntry.cs b/src/libraries/Microsoft.Extensions.Http/src/ExpiredHandlerTrackingEntry.cs index b5c53f810a26c..1973f24f625fe 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/ExpiredHandlerTrackingEntry.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/ExpiredHandlerTrackingEntry.cs @@ -20,7 +20,7 @@ public ExpiredHandlerTrackingEntry(ActiveHandlerTrackingEntry other) Scope = other.Scope; _livenessTracker = new WeakReference(other.Handler); - InnerHandler = other.Handler.InnerHandler; + InnerHandler = other.Handler.InnerHandler!; } public bool CanDispose => !_livenessTracker.IsAlive; @@ -29,6 +29,6 @@ public ExpiredHandlerTrackingEntry(ActiveHandlerTrackingEntry other) public string Name { get; } - public IServiceScope Scope { get; } + public IServiceScope? Scope { get; } } } diff --git a/src/libraries/Microsoft.Extensions.Http/src/HttpMessageHandlerBuilder.cs b/src/libraries/Microsoft.Extensions.Http/src/HttpMessageHandlerBuilder.cs index 9bbe559fe6a91..7eef2a1cc38e6 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/HttpMessageHandlerBuilder.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/HttpMessageHandlerBuilder.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net.Http; @@ -26,7 +27,8 @@ public abstract class HttpMessageHandlerBuilder /// and is public for unit testing purposes only. Setting the outside of /// testing scenarios may have unpredictable results. /// - public abstract string Name { get; set; } + [DisallowNull] + public abstract string? Name { get; set; } /// /// Gets or sets the primary . @@ -50,7 +52,7 @@ public abstract class HttpMessageHandlerBuilder /// (default) this will be a reference to a scoped service provider that has the same /// lifetime as the handler being created. /// - public virtual IServiceProvider Services { get; } + public virtual IServiceProvider Services { get; } = null!; /// /// Creates an . diff --git a/src/libraries/Microsoft.Extensions.Http/src/Logging/HttpHeadersLogValue.cs b/src/libraries/Microsoft.Extensions.Http/src/Logging/HttpHeadersLogValue.cs index dc92d3f659dfa..802192c4a905c 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Logging/HttpHeadersLogValue.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/Logging/HttpHeadersLogValue.cs @@ -14,10 +14,10 @@ internal sealed class HttpHeadersLogValue : IReadOnlyList _shouldRedactHeaderValue; - private string _formatted; - private List> _values; + private string? _formatted; + private List>? _values; - public HttpHeadersLogValue(Kind kind, HttpHeaders headers, HttpHeaders contentHeaders, Func shouldRedactHeaderValue) + public HttpHeadersLogValue(Kind kind, HttpHeaders headers, HttpHeaders? contentHeaders, Func shouldRedactHeaderValue) { _kind = kind; _shouldRedactHeaderValue = shouldRedactHeaderValue; @@ -28,7 +28,7 @@ public HttpHeadersLogValue(Kind kind, HttpHeaders headers, HttpHeaders contentHe public HttpHeaders Headers { get; } - public HttpHeaders ContentHeaders { get; } + public HttpHeaders? ContentHeaders { get; } private List> Values { diff --git a/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingHttpMessageHandler.cs b/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingHttpMessageHandler.cs index c7c502be236e0..f0a1959c8f379 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingHttpMessageHandler.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingHttpMessageHandler.cs @@ -16,7 +16,7 @@ namespace Microsoft.Extensions.Http.Logging public class LoggingHttpMessageHandler : DelegatingHandler { private ILogger _logger; - private readonly HttpClientFactoryOptions _options; + private readonly HttpClientFactoryOptions? _options; private static readonly Func _shouldNotRedactHeaderValue = (header) => false; @@ -72,13 +72,13 @@ public static class EventIds private static readonly LogDefineOptions _skipEnabledCheckLogDefineOptions = new LogDefineOptions() { SkipEnabledCheck = true }; - private static readonly Action _requestStart = LoggerMessage.Define( + private static readonly Action _requestStart = LoggerMessage.Define( LogLevel.Information, EventIds.RequestStart, "Sending HTTP request {HttpMethod} {Uri}", _skipEnabledCheckLogDefineOptions); - private static readonly Action _requestEnd = LoggerMessage.Define( + private static readonly Action _requestEnd = LoggerMessage.Define( LogLevel.Information, EventIds.RequestEnd, "Received HTTP response headers after {ElapsedMilliseconds}ms - {StatusCode}"); diff --git a/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingScopeHttpMessageHandler.cs b/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingScopeHttpMessageHandler.cs index 6b9536b92e01e..3ac0b12889242 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingScopeHttpMessageHandler.cs +++ b/src/libraries/Microsoft.Extensions.Http/src/Logging/LoggingScopeHttpMessageHandler.cs @@ -16,7 +16,7 @@ namespace Microsoft.Extensions.Http.Logging public class LoggingScopeHttpMessageHandler : DelegatingHandler { private ILogger _logger; - private readonly HttpClientFactoryOptions _options; + private readonly HttpClientFactoryOptions? _options; private static readonly Func _shouldNotRedactHeaderValue = (header) => false; @@ -72,19 +72,19 @@ public static class EventIds public static readonly EventId ResponseHeader = new EventId(103, "RequestPipelineResponseHeader"); } - private static readonly Func _beginRequestPipelineScope = LoggerMessage.DefineScope("HTTP {HttpMethod} {Uri}"); + private static readonly Func _beginRequestPipelineScope = LoggerMessage.DefineScope("HTTP {HttpMethod} {Uri}"); - private static readonly Action _requestPipelineStart = LoggerMessage.Define( + private static readonly Action _requestPipelineStart = LoggerMessage.Define( LogLevel.Information, EventIds.PipelineStart, "Start processing HTTP request {HttpMethod} {Uri}"); - private static readonly Action _requestPipelineEnd = LoggerMessage.Define( + private static readonly Action _requestPipelineEnd = LoggerMessage.Define( LogLevel.Information, EventIds.PipelineEnd, "End processing HTTP request after {ElapsedMilliseconds}ms - {StatusCode}"); - public static IDisposable BeginRequestPipelineScope(ILogger logger, HttpRequestMessage request) + public static IDisposable? BeginRequestPipelineScope(ILogger logger, HttpRequestMessage request) { return _beginRequestPipelineScope(logger, request.Method, GetUriString(request.RequestUri)); } diff --git a/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj b/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj index 968c50578d890..5e40a002ca65c 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj +++ b/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj @@ -2,11 +2,11 @@ $(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) + enable true false true - Annotations The HttpClient factory is a pattern for configuring and retrieving named HttpClients in a composable way. The HttpClient factory provides extensibility to plug in DelegatingHandlers that address cross-cutting concerns such as service location, load balancing, and reliability. The default HttpClient factory provides built-in diagnostics and logging and manages the lifetimes of connections in a performant way. Commonly Used Types: