From f47ccd3f72d86a12dd823a2b698f037b4ec30a2e Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Mon, 13 Jul 2020 13:13:20 +0200 Subject: [PATCH 01/16] [browser][wasm] Initial addition of configuring request options in Browser WebAssembly --- .../System.Net.Http/ref/System.Net.Http.cs | 10 ++++++++++ .../System.Net.Http/src/System.Net.Http.csproj | 4 +++- .../BrowserHttpHandler/BrowserHttpHandler.cs | 4 ++-- .../src/System/Net/Http/HttpRequestMessage.cs | 14 ++++++++++++++ .../src/System/Net/Http/HttpRequestOptions.cs | 10 ++++++++++ .../System/Net/Http/HttpRequestOptionsKey.cs | 17 +++++++++++++++++ 6 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index f65651424593f9..714a76b7cc8d4d 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -213,12 +213,22 @@ public HttpRequestMessage(System.Net.Http.HttpMethod method, System.Uri? request public System.Net.Http.Headers.HttpRequestHeaders Headers { get { throw null; } } public System.Net.Http.HttpMethod Method { get { throw null; } set { } } public System.Collections.Generic.IDictionary Properties { get { throw null; } } + public HttpRequestOptions Options { get { throw null; } } public System.Uri? RequestUri { get { throw null; } set { } } public System.Version Version { get { throw null; } set { } } public void Dispose() { } protected virtual void Dispose(bool disposing) { } public override string ToString() { throw null; } } + + public readonly struct HttpRequestOptionsKey + { + public HttpRequestOptionsKey(TKey key) {} + public TKey Key { get { throw null; } } + } + + public sealed class HttpRequestOptions : System.Collections.Generic.Dictionary, object> { } + public partial class HttpResponseMessage : System.IDisposable { public HttpResponseMessage() { } diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 6c03ef3c989843..f62ed5639ea1f6 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -1,4 +1,4 @@ - + Library System.Net.Http @@ -47,6 +47,8 @@ + + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs index eb4a75f592adbd..d5fa6d11fbd6ce 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs @@ -129,7 +129,7 @@ protected internal override async Task SendAsync(HttpReques { var requestObject = new JSObject(); - if (request.Properties.TryGetValue("WebAssemblyFetchOptions", out object? fetchOptionsValue) && + if (request.Options.TryGetValue(new HttpRequestOptionsKey("WebAssemblyFetchOptions"), out object? fetchOptionsValue) && fetchOptionsValue is IDictionary fetchOptions) { foreach (KeyValuePair item in fetchOptions) @@ -221,7 +221,7 @@ protected internal override async Task SendAsync(HttpReques HttpResponseMessage httpResponse = new HttpResponseMessage((HttpStatusCode)status.Status); - bool streamingEnabled = request.Properties.TryGetValue("WebAssemblyEnableStreamingResponse", out object? streamingEnabledValue) && (bool)(streamingEnabledValue ?? false); + bool streamingEnabled = request.Options.TryGetValue(new HttpRequestOptionsKey("WebAssemblyEnableStreamingResponse"), out object? streamingEnabledValue) && (bool)(streamingEnabledValue ?? false); httpResponse.Content = StreamingSupported && streamingEnabled ? new StreamContent(wasmHttpReadStream = new WasmHttpReadStream(status)) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs index 3cbb1d058c3987..4e2ca186dd58c4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs @@ -25,6 +25,7 @@ public class HttpRequestMessage : IDisposable private HttpContent? _content; private bool _disposed; private IDictionary? _properties; + private HttpRequestOptions? _options; public Version Version { @@ -111,6 +112,7 @@ public HttpRequestHeaders Headers internal bool HasHeaders => _headers != null; + [Obsolete("Use Options instead.")] public IDictionary Properties { get @@ -123,6 +125,18 @@ public HttpRequestHeaders Headers } } + public HttpRequestOptions Options + { + get + { + if (_options == null) + { + _options = new HttpRequestOptions(); + } + return _options; + } + } + public HttpRequestMessage() : this(HttpMethod.Get, (Uri?)null) { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs new file mode 100644 index 00000000000000..81c7067ee0eec2 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs @@ -0,0 +1,10 @@ +// 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; + +namespace System.Net.Http +{ + public sealed class HttpRequestOptions : Dictionary, object?> { } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs new file mode 100644 index 00000000000000..23e259b540d0cb --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace System.Net.Http +{ + public readonly struct HttpRequestOptionsKey + { + private readonly TKey _key; + public HttpRequestOptionsKey(TKey key) + { + _key = key; + } + public TKey Key => _key; + } +} From 29a208ecc1ec7b6eabb7fda1857621655d48389a Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Mon, 13 Jul 2020 18:19:59 +0200 Subject: [PATCH 02/16] Fix key code. Not what was proposed --- .../System.Net.Http/ref/System.Net.Http.cs | 10 ++++---- .../BrowserHttpHandler/BrowserHttpHandler.cs | 4 +-- .../src/System/Net/Http/HttpRequestMessage.cs | 25 ++----------------- .../src/System/Net/Http/HttpRequestOptions.cs | 2 +- .../System/Net/Http/HttpRequestOptionsKey.cs | 8 +++--- 5 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index 714a76b7cc8d4d..0bebb7bd02f2f1 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -221,13 +221,13 @@ protected virtual void Dispose(bool disposing) { } public override string ToString() { throw null; } } - public readonly struct HttpRequestOptionsKey + public readonly struct HttpRequestOptionsKey { - public HttpRequestOptionsKey(TKey key) {} - public TKey Key { get { throw null; } } + public HttpRequestOptionsKey(string key) {} + public string Key { get { throw null; } } } - - public sealed class HttpRequestOptions : System.Collections.Generic.Dictionary, object> { } + + public sealed class HttpRequestOptions : System.Collections.Generic.Dictionary { } public partial class HttpResponseMessage : System.IDisposable { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs index d5fa6d11fbd6ce..8e08a9b3a5d1a6 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs @@ -129,7 +129,7 @@ protected internal override async Task SendAsync(HttpReques { var requestObject = new JSObject(); - if (request.Options.TryGetValue(new HttpRequestOptionsKey("WebAssemblyFetchOptions"), out object? fetchOptionsValue) && + if (request.Options.TryGetValue("WebAssemblyFetchOptions", out object? fetchOptionsValue) && fetchOptionsValue is IDictionary fetchOptions) { foreach (KeyValuePair item in fetchOptions) @@ -221,7 +221,7 @@ protected internal override async Task SendAsync(HttpReques HttpResponseMessage httpResponse = new HttpResponseMessage((HttpStatusCode)status.Status); - bool streamingEnabled = request.Options.TryGetValue(new HttpRequestOptionsKey("WebAssemblyEnableStreamingResponse"), out object? streamingEnabledValue) && (bool)(streamingEnabledValue ?? false); + bool streamingEnabled = request.Options.TryGetValue("WebAssemblyEnableStreamingResponse", out object? streamingEnabledValue) && (bool)(streamingEnabledValue ?? false); httpResponse.Content = StreamingSupported && streamingEnabled ? new StreamContent(wasmHttpReadStream = new WasmHttpReadStream(status)) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs index 4e2ca186dd58c4..83ee09fd178103 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestMessage.cs @@ -24,7 +24,6 @@ public class HttpRequestMessage : IDisposable private Version _version; private HttpContent? _content; private bool _disposed; - private IDictionary? _properties; private HttpRequestOptions? _options; public Version Version @@ -113,29 +112,9 @@ public HttpRequestHeaders Headers internal bool HasHeaders => _headers != null; [Obsolete("Use Options instead.")] - public IDictionary Properties - { - get - { - if (_properties == null) - { - _properties = new Dictionary(); - } - return _properties; - } - } + public IDictionary Properties => Options; - public HttpRequestOptions Options - { - get - { - if (_options == null) - { - _options = new HttpRequestOptions(); - } - return _options; - } - } + public HttpRequestOptions Options => _options ??= new HttpRequestOptions(); public HttpRequestMessage() : this(HttpMethod.Get, (Uri?)null) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs index 81c7067ee0eec2..c3799843c200d4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs @@ -6,5 +6,5 @@ namespace System.Net.Http { - public sealed class HttpRequestOptions : Dictionary, object?> { } + public sealed class HttpRequestOptions : Dictionary { } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs index 23e259b540d0cb..f9a6af3aa4bdda 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs @@ -5,13 +5,13 @@ namespace System.Net.Http { - public readonly struct HttpRequestOptionsKey + public readonly struct HttpRequestOptionsKey { - private readonly TKey _key; - public HttpRequestOptionsKey(TKey key) + private readonly string _key; + public HttpRequestOptionsKey(string key) { _key = key; } - public TKey Key => _key; + public string Key => _key; } } From 64e8227a8bc1f21150634b0be89ea4fa30566630 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Tue, 14 Jul 2020 09:29:31 +0200 Subject: [PATCH 03/16] Add TryGetValue and Set as per proposal --- .../System.Net.Http/ref/System.Net.Http.cs | 8 ++++++- .../BrowserHttpHandler/BrowserHttpHandler.cs | 8 ++++--- .../src/System/Net/Http/HttpRequestOptions.cs | 24 ++++++++++++++++--- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index 0bebb7bd02f2f1..1e10b2ea0dbf9e 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -4,6 +4,8 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ +using System.Diagnostics.CodeAnalysis; + namespace System.Net.Http { public partial class ByteArrayContent : System.Net.Http.HttpContent @@ -227,7 +229,11 @@ public HttpRequestOptionsKey(string key) {} public string Key { get { throw null; } } } - public sealed class HttpRequestOptions : System.Collections.Generic.Dictionary { } + public sealed class HttpRequestOptions : System.Collections.Generic.Dictionary + { + public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) { throw null; } + public void Set(HttpRequestOptionsKey key, TValue value) { throw null; } + } public partial class HttpResponseMessage : System.IDisposable { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs index 8e08a9b3a5d1a6..bae461c029bc0d 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs @@ -32,6 +32,9 @@ internal sealed class BrowserHttpHandler : HttpMessageHandler private static readonly JSObject? s_fetch = (JSObject)System.Runtime.InteropServices.JavaScript.Runtime.GetGlobalObject("fetch"); private static readonly JSObject? s_window = (JSObject)System.Runtime.InteropServices.JavaScript.Runtime.GetGlobalObject("window"); + private static readonly HttpRequestOptionsKey EnableStreamingResponse = new HttpRequestOptionsKey("WebAssemblyEnableStreamingResponse"); + private static readonly HttpRequestOptionsKey> FetchOptions = new HttpRequestOptionsKey>("WebAssemblyFetchOptions"); + /// /// Gets whether the current Browser supports streaming responses /// @@ -129,8 +132,7 @@ protected internal override async Task SendAsync(HttpReques { var requestObject = new JSObject(); - if (request.Options.TryGetValue("WebAssemblyFetchOptions", out object? fetchOptionsValue) && - fetchOptionsValue is IDictionary fetchOptions) + if (request.Options.TryGetValue>(FetchOptions, out IDictionary? fetchOptions)) { foreach (KeyValuePair item in fetchOptions) { @@ -221,7 +223,7 @@ protected internal override async Task SendAsync(HttpReques HttpResponseMessage httpResponse = new HttpResponseMessage((HttpStatusCode)status.Status); - bool streamingEnabled = request.Options.TryGetValue("WebAssemblyEnableStreamingResponse", out object? streamingEnabledValue) && (bool)(streamingEnabledValue ?? false); + request.Options.TryGetValue(EnableStreamingResponse, out bool streamingEnabled); httpResponse.Content = StreamingSupported && streamingEnabled ? new StreamContent(wasmHttpReadStream = new WasmHttpReadStream(status)) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs index c3799843c200d4..40b03db38be71a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs @@ -1,10 +1,28 @@ // 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.Diagnostics.CodeAnalysis; namespace System.Net.Http { - public sealed class HttpRequestOptions : Dictionary { } -} + public sealed class HttpRequestOptions : Dictionary + { + public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) + { + value = default(TValue); + var ourValueResult = base.TryGetValue(key.Key, out object? _value); + if (ourValueResult && _value is TValue) + { + value = (TValue)_value; + return true; + } + return false; + } + + public void Set(HttpRequestOptionsKey key, TValue value) + { + base.Add(key.Key, value); + } + } +} \ No newline at end of file From b0e55eef689b841b43911a23340bc736f5837cb0 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Tue, 14 Jul 2020 11:03:25 +0200 Subject: [PATCH 04/16] Add missing obsolete attribute --- src/libraries/System.Net.Http/ref/System.Net.Http.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index 1e10b2ea0dbf9e..101d8fa530a4e0 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -214,6 +214,7 @@ public HttpRequestMessage(System.Net.Http.HttpMethod method, System.Uri? request public System.Net.Http.HttpContent? Content { get { throw null; } set { } } public System.Net.Http.Headers.HttpRequestHeaders Headers { get { throw null; } } public System.Net.Http.HttpMethod Method { get { throw null; } set { } } + [Obsolete("Use Options instead.")] public System.Collections.Generic.IDictionary Properties { get { throw null; } } public HttpRequestOptions Options { get { throw null; } } public System.Uri? RequestUri { get { throw null; } set { } } From d22d48279205f8c735215c703812c293e64a7982 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Tue, 14 Jul 2020 11:03:47 +0200 Subject: [PATCH 05/16] Address review comments --- .../Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs | 10 +++++++--- .../src/System/Net/Http/HttpRequestOptions.cs | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs index bae461c029bc0d..490591ed8b93c6 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpHandler.cs @@ -132,7 +132,7 @@ protected internal override async Task SendAsync(HttpReques { var requestObject = new JSObject(); - if (request.Options.TryGetValue>(FetchOptions, out IDictionary? fetchOptions)) + if (request.Options.TryGetValue(FetchOptions, out IDictionary? fetchOptions)) { foreach (KeyValuePair item in fetchOptions) { @@ -223,9 +223,13 @@ protected internal override async Task SendAsync(HttpReques HttpResponseMessage httpResponse = new HttpResponseMessage((HttpStatusCode)status.Status); - request.Options.TryGetValue(EnableStreamingResponse, out bool streamingEnabled); + bool streamingEnabled = false; + if (StreamingSupported) + { + request.Options.TryGetValue(EnableStreamingResponse, out streamingEnabled); + } - httpResponse.Content = StreamingSupported && streamingEnabled + httpResponse.Content = streamingEnabled ? new StreamContent(wasmHttpReadStream = new WasmHttpReadStream(status)) : (HttpContent)new BrowserHttpContent(status); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs index 40b03db38be71a..9d7d3ec9faeed8 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs @@ -10,13 +10,13 @@ public sealed class HttpRequestOptions : Dictionary { public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) { - value = default(TValue); - var ourValueResult = base.TryGetValue(key.Key, out object? _value); - if (ourValueResult && _value is TValue) + if (base.TryGetValue(key.Key, out object? _value) && _value is TValue tvalue) { - value = (TValue)_value; + value = tvalue; return true; } + + value = default(TValue); return false; } From 4739203066afb708455e366688ce9f06fc17d911 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Tue, 14 Jul 2020 14:29:12 +0200 Subject: [PATCH 06/16] Update tests to use Options and not obsolete Properties. --- ...tFactoryServiceCollectionExtensionsTest.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs index 6e526dbdad572b..e61f871cb36418 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs @@ -950,11 +950,11 @@ public async Task AddHttpClient_MessageHandler_SingletonDependency() Assert.Same( services.GetRequiredService(), - request.Properties[nameof(SingletonService)]); + request.Options[nameof(SingletonService)]); Assert.Same( client.Service, - request.Properties[nameof(SingletonService)]); + request.Options[nameof(SingletonService)]); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -981,15 +981,15 @@ public async Task AddHttpClient_MessageHandler_Scope_SingletonDependency() Assert.Same( services.GetRequiredService(), - request.Properties[nameof(SingletonService)]); + request.Options[nameof(SingletonService)]); Assert.Same( scope.ServiceProvider.GetRequiredService(), - request.Properties[nameof(SingletonService)]); + request.Options[nameof(SingletonService)]); Assert.Same( client.Service, - request.Properties[nameof(SingletonService)]); + request.Options[nameof(SingletonService)]); } } @@ -1037,7 +1037,7 @@ public async Task AddHttpClient_MessageHandler_Scope_ScopedDependency() Assert.NotSame( scope.ServiceProvider.GetRequiredService(), - request.Properties[nameof(ScopedService)]); + request.Options[nameof(ScopedService)]); Assert.Same( scope.ServiceProvider.GetRequiredService(), @@ -1045,7 +1045,7 @@ public async Task AddHttpClient_MessageHandler_Scope_ScopedDependency() Assert.NotSame( client.Service, - request.Properties[nameof(ScopedService)]); + request.Options[nameof(ScopedService)]); } } @@ -1071,11 +1071,11 @@ public async Task AddHttpClient_MessageHandler_TransientDependency() Assert.NotSame( services.GetRequiredService(), - request.Properties[nameof(TransientService)]); + request.Options[nameof(TransientService)]); Assert.NotSame( client.Service, - request.Properties[nameof(TransientService)]); + request.Options[nameof(TransientService)]); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -1102,11 +1102,11 @@ public async Task AddHttpClient_MessageHandler_Scope_TransientDependency() Assert.NotSame( services.GetRequiredService(), - request.Properties[nameof(TransientService)]); + request.Options[nameof(TransientService)]); Assert.NotSame( client.Service, - request.Properties[nameof(TransientService)]); + request.Options[nameof(TransientService)]); } } @@ -1304,7 +1304,7 @@ public HandlerWithSingletonService(SingletonService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - request.Properties[nameof(SingletonService)] = Service; + request.Options[nameof(SingletonService)] = Service; return Task.FromResult(new HttpResponseMessage()); } } @@ -1320,7 +1320,7 @@ public HandlerWithScopedService(ScopedService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - request.Properties[nameof(ScopedService)] = Service; + request.Options[nameof(ScopedService)] = Service; return Task.FromResult(new HttpResponseMessage()); } } @@ -1336,7 +1336,7 @@ public HandlerWithTransientService(TransientService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - request.Properties[nameof(TransientService)] = Service; + request.Options[nameof(TransientService)] = Service; return Task.FromResult(new HttpResponseMessage()); } } From 710106577ccb3bfdea4c246dc7210f45283e3f4b Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Wed, 15 Jul 2020 06:12:59 +0200 Subject: [PATCH 07/16] Implement IDictionary explicitly --- .../System.Net.Http/ref/System.Net.Http.cs | 21 +++- .../src/System/Net/Http/HttpRequestOptions.cs | 95 ++++++++++++++++++- 2 files changed, 111 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index 101d8fa530a4e0..e7efe99b4fd2f2 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -230,8 +230,25 @@ public HttpRequestOptionsKey(string key) {} public string Key { get { throw null; } } } - public sealed class HttpRequestOptions : System.Collections.Generic.Dictionary - { + public sealed class HttpRequestOptions : System.Collections.Generic.IDictionary + { + public HttpRequestOptions() { } + public void Add(string key, object? value) { throw null; } + public bool ContainsKey(string key) { throw null; } + public System.Collections.Generic.ICollection Keys { get { throw null; } } + public bool Remove(string key) { throw null; } + public bool TryGetValue(string key, out object? value) { throw null; } + public System.Collections.Generic.ICollection Values { get { throw null; } } + public object? this[string key] { get { throw null; } set { } } + public void Add(System.Collections.Generic.KeyValuePair item) { throw null; } + public void Clear() { throw null; } + public bool Contains(System.Collections.Generic.KeyValuePair item) { throw null; } + public void CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { throw null; } + public int Count { get { throw null; } } + public bool IsReadOnly { get { throw null; } } + public bool Remove(System.Collections.Generic.KeyValuePair item) { throw null; } + public System.Collections.Generic.IEnumerator> GetEnumerator() { throw null; } + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) { throw null; } public void Set(HttpRequestOptionsKey key, TValue value) { throw null; } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs index 9d7d3ec9faeed8..1f13b7b8a73e03 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs @@ -6,11 +6,100 @@ namespace System.Net.Http { - public sealed class HttpRequestOptions : Dictionary + public sealed class HttpRequestOptions : IDictionary { + private IDictionary Options { get; } = new Dictionary(); + + public void Add(string key, object? value) + { + Options.Add(key, value); + } + + public bool ContainsKey(string key) + { + return Options.ContainsKey(key); + } + + public ICollection Keys + { + get { return Options.Keys; } + } + + public bool Remove(string key) + { + return Options.Remove(key); + } + + public bool TryGetValue(string key, out object? value) + { + return Options.TryGetValue(key, out value); + } + + public ICollection Values + { + get { return Options.Values; } + } + + public object? this[string key] + { + get + { + return Options[key]; + } + set + { + Options[key] = value; + } + } + + public void Add(KeyValuePair item) + { + Options.Add(item); + } + + public void Clear() + { + Options.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return Options.Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + Options.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return Options.Count; } + } + + public bool IsReadOnly + { + get { return Options.IsReadOnly; } + } + + public bool Remove(KeyValuePair item) + { + return Options.Remove(item); + } + + public IEnumerator> GetEnumerator() + { + return Options.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return ((System.Collections.IEnumerable)Options).GetEnumerator(); + } + public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) { - if (base.TryGetValue(key.Key, out object? _value) && _value is TValue tvalue) + if (TryGetValue(key.Key, out object? _value) && _value is TValue tvalue) { value = tvalue; return true; @@ -22,7 +111,7 @@ public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhe public void Set(HttpRequestOptionsKey key, TValue value) { - base.Add(key.Key, value); + Add(key.Key, value); } } } \ No newline at end of file From 8886161aca1d8d8752566ca6472e9d1a00eba21f Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Wed, 15 Jul 2020 07:01:04 +0200 Subject: [PATCH 08/16] Update tests to use Options and not obsolete Properties. --- .../tests/FunctionalTests/HttpRequestMessageTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs index 5e8928b7db9f25..8f5ff80d998d27 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs @@ -154,7 +154,7 @@ public void Properties_SetPropertiesAndGetTheirValue_MatchingValues() Assert.Equal(version, rm.Version); Assert.NotNull(rm.Headers); - Assert.NotNull(rm.Properties); + Assert.NotNull(rm.Options); } [Fact] From f62bc163fe0988e3310a5ee689d017ea2d28b5fb Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Wed, 15 Jul 2020 08:20:38 +0200 Subject: [PATCH 09/16] Add HttpRequestOptions source to the System.Net.Http.Unit.Tests project to fix build. --- .../tests/UnitTests/System.Net.Http.Unit.Tests.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj index 9ca98181f81fbb..01c061ae0a2464 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj @@ -206,6 +206,10 @@ Link="ProductionCode\System\Net\Http\RequestRetryType.cs" /> + + Date: Wed, 15 Jul 2020 17:13:37 +0200 Subject: [PATCH 10/16] Address review comments - explicit --- .../System.Net.Http/ref/System.Net.Http.cs | 33 ++++--- .../src/System/Net/Http/HttpRequestOptions.cs | 99 ++++--------------- .../System/Net/Http/HttpRequestOptionsKey.cs | 5 +- 3 files changed, 38 insertions(+), 99 deletions(-) diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index 8db572bf7bcfc8..735f4e7710ab94 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -232,22 +232,23 @@ public HttpRequestOptionsKey(string key) {} public sealed class HttpRequestOptions : System.Collections.Generic.IDictionary { - public HttpRequestOptions() { } - public void Add(string key, object? value) { throw null; } - public bool ContainsKey(string key) { throw null; } - public System.Collections.Generic.ICollection Keys { get { throw null; } } - public bool Remove(string key) { throw null; } - public bool TryGetValue(string key, out object? value) { throw null; } - public System.Collections.Generic.ICollection Values { get { throw null; } } - public object? this[string key] { get { throw null; } set { } } - public void Add(System.Collections.Generic.KeyValuePair item) { throw null; } - public void Clear() { throw null; } - public bool Contains(System.Collections.Generic.KeyValuePair item) { throw null; } - public void CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { throw null; } - public int Count { get { throw null; } } - public bool IsReadOnly { get { throw null; } } - public bool Remove(System.Collections.Generic.KeyValuePair item) { throw null; } - public System.Collections.Generic.IEnumerator> GetEnumerator() { throw null; } + void System.Collections.Generic.IDictionary.Add(string key, object? value) { throw null; } + System.Collections.Generic.ICollection System.Collections.Generic.IDictionary.Keys { get { throw null; } } + System.Collections.Generic.ICollection System.Collections.Generic.IDictionary.Values { get { throw null; } } + bool System.Collections.Generic.IDictionary.Remove(string key) { throw null; } + bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair item) { throw null; } + bool System.Collections.Generic.IDictionary.TryGetValue(string key, out object? value) { throw null; } + + object? System.Collections.Generic.IDictionary.this[string key] { get { throw null; } set { } } + void System.Collections.Generic.ICollection>.Add(System.Collections.Generic.KeyValuePair item) { throw null; } + void System.Collections.Generic.ICollection>.Clear() { throw null; } + bool System.Collections.Generic.ICollection>.Contains(System.Collections.Generic.KeyValuePair item) { throw null; } + bool System.Collections.Generic.IDictionary.ContainsKey(string key) { throw null; } + void System.Collections.Generic.ICollection>.CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { throw null; } + int System.Collections.Generic.ICollection>.Count { get { throw null; } } + bool System.Collections.Generic.ICollection>.IsReadOnly { get { throw null; } } + // public bool Remove(System.Collections.Generic.KeyValuePair item) { throw null; } + System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() { throw null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) { throw null; } public void Set(HttpRequestOptionsKey key, TValue value) { throw null; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs index 1f13b7b8a73e03..bdf9c063a7cddc 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs @@ -8,39 +8,8 @@ namespace System.Net.Http { public sealed class HttpRequestOptions : IDictionary { - private IDictionary Options { get; } = new Dictionary(); - - public void Add(string key, object? value) - { - Options.Add(key, value); - } - - public bool ContainsKey(string key) - { - return Options.ContainsKey(key); - } - - public ICollection Keys - { - get { return Options.Keys; } - } - - public bool Remove(string key) - { - return Options.Remove(key); - } - - public bool TryGetValue(string key, out object? value) - { - return Options.TryGetValue(key, out value); - } - - public ICollection Values - { - get { return Options.Values; } - } - - public object? this[string key] + private Dictionary Options { get; } = new Dictionary(); + object? IDictionary.this[string key] { get { @@ -51,52 +20,22 @@ public object? this[string key] Options[key] = value; } } - - public void Add(KeyValuePair item) - { - Options.Add(item); - } - - public void Clear() - { - Options.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return Options.Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - Options.CopyTo(array, arrayIndex); - } - - public int Count - { - get { return Options.Count; } - } - - public bool IsReadOnly - { - get { return Options.IsReadOnly; } - } - - public bool Remove(KeyValuePair item) - { - return Options.Remove(item); - } - - public IEnumerator> GetEnumerator() - { - return Options.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return ((System.Collections.IEnumerable)Options).GetEnumerator(); - } - + ICollection IDictionary.Keys => Options.Keys; + ICollection IDictionary.Values => Options.Values; + int ICollection>.Count => Options.Count; + bool ICollection>.IsReadOnly => ((IDictionary)Options).IsReadOnly; + void IDictionary.Add(string key, object? value) => Options.Add(key, value); + void ICollection>.Add(KeyValuePair item) => ((IDictionary)Options).Add(item); + void ICollection>.Clear() => Options.Clear(); + bool ICollection>.Contains(KeyValuePair item) => ((IDictionary)Options).Contains(item); + bool IDictionary.ContainsKey(string key) => Options.ContainsKey(key); + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) => + ((IDictionary)Options).CopyTo(array, arrayIndex); + IEnumerator> IEnumerable>.GetEnumerator() => Options.GetEnumerator(); + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => ((System.Collections.IEnumerable)Options).GetEnumerator(); + bool IDictionary.Remove(string key) => Options.Remove(key); + bool ICollection>.Remove(KeyValuePair item) => ((IDictionary)Options).Remove(item); + bool IDictionary.TryGetValue(string key, out object? value) => Options.TryGetValue(key, out value); public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) { if (TryGetValue(key.Key, out object? _value) && _value is TValue tvalue) @@ -111,7 +50,7 @@ public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhe public void Set(HttpRequestOptionsKey key, TValue value) { - Add(key.Key, value); + Options[key.Key] = value; } } } \ No newline at end of file diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs index f9a6af3aa4bdda..f51f8ebf162fe7 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptionsKey.cs @@ -7,11 +7,10 @@ namespace System.Net.Http { public readonly struct HttpRequestOptionsKey { - private readonly string _key; + public string Key { get; } public HttpRequestOptionsKey(string key) { - _key = key; + Key = key; } - public string Key => _key; } } From 3d5d7fa939f560fd65cbeace7880a1390473e137 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Thu, 16 Jul 2020 09:13:22 +0200 Subject: [PATCH 11/16] Fix build error cannot convert from 'string' to 'System.Net.Http.HttpRequestOptionsKey' --- .../System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs index bdf9c063a7cddc..195eb0d10fe621 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpRequestOptions.cs @@ -38,7 +38,7 @@ public sealed class HttpRequestOptions : IDictionary bool IDictionary.TryGetValue(string key, out object? value) => Options.TryGetValue(key, out value); public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) { - if (TryGetValue(key.Key, out object? _value) && _value is TValue tvalue) + if (Options.TryGetValue(key.Key, out object? _value) && _value is TValue tvalue) { value = tvalue; return true; From 7398927d9d8b4da87f802eb9fe9017bde5854abe Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Thu, 16 Jul 2020 11:27:21 +0200 Subject: [PATCH 12/16] Add tests for HttpRequestOptions --- ...tFactoryServiceCollectionExtensionsTest.cs | 48 ++- .../System.Net.Http/ref/System.Net.Http.cs | 2 - ...me.InteropServices.JavaScript.Tests.csproj | 1 + .../JavaScript/Http/HttpRequestMessageTest.cs | 377 ++++++++++++++++++ 4 files changed, 412 insertions(+), 16 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs diff --git a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs index e61f871cb36418..9342d41c8d0b69 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs @@ -948,13 +948,17 @@ public async Task AddHttpClient_MessageHandler_SingletonDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#nullable enable + request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(SingletonService)), out SingletonService? optService); +#nullable disable + Assert.Same( services.GetRequiredService(), - request.Options[nameof(SingletonService)]); + optService); Assert.Same( client.Service, - request.Options[nameof(SingletonService)]); + optService); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -979,17 +983,21 @@ public async Task AddHttpClient_MessageHandler_Scope_SingletonDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#nullable enable + request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(SingletonService)), out SingletonService? optService); +#nullable disable + Assert.Same( services.GetRequiredService(), - request.Options[nameof(SingletonService)]); + optService); Assert.Same( scope.ServiceProvider.GetRequiredService(), - request.Options[nameof(SingletonService)]); + optService); Assert.Same( client.Service, - request.Options[nameof(SingletonService)]); + optService); } } @@ -1035,9 +1043,13 @@ public async Task AddHttpClient_MessageHandler_Scope_ScopedDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#nullable enable + request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(ScopedService)), out ScopedService? optService); +#nullable disable + Assert.NotSame( scope.ServiceProvider.GetRequiredService(), - request.Options[nameof(ScopedService)]); + optService); Assert.Same( scope.ServiceProvider.GetRequiredService(), @@ -1045,7 +1057,7 @@ public async Task AddHttpClient_MessageHandler_Scope_ScopedDependency() Assert.NotSame( client.Service, - request.Options[nameof(ScopedService)]); + optService); } } @@ -1069,13 +1081,17 @@ public async Task AddHttpClient_MessageHandler_TransientDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#nullable enable + request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(TransientService)), out TransientService? optService); +#nullable disable + Assert.NotSame( services.GetRequiredService(), - request.Options[nameof(TransientService)]); + optService); Assert.NotSame( client.Service, - request.Options[nameof(TransientService)]); + optService); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -1100,13 +1116,17 @@ public async Task AddHttpClient_MessageHandler_Scope_TransientDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#nullable enable + request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(TransientService)), out TransientService? optService); +#nullable disable + Assert.NotSame( services.GetRequiredService(), - request.Options[nameof(TransientService)]); + optService); Assert.NotSame( client.Service, - request.Options[nameof(TransientService)]); + optService); } } @@ -1304,7 +1324,7 @@ public HandlerWithSingletonService(SingletonService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - request.Options[nameof(SingletonService)] = Service; + request.Options.Set(new HttpRequestOptionsKey(nameof(SingletonService)), Service); return Task.FromResult(new HttpResponseMessage()); } } @@ -1320,7 +1340,7 @@ public HandlerWithScopedService(ScopedService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - request.Options[nameof(ScopedService)] = Service; + request.Options.Set(new HttpRequestOptionsKey(nameof(ScopedService)), Service); return Task.FromResult(new HttpResponseMessage()); } } @@ -1336,7 +1356,7 @@ public HandlerWithTransientService(TransientService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { - request.Options[nameof(TransientService)] = Service; + request.Options.Set(new HttpRequestOptionsKey(nameof(TransientService)), Service); return Task.FromResult(new HttpResponseMessage()); } } diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index 735f4e7710ab94..ef93293b5c2674 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -238,7 +238,6 @@ public sealed class HttpRequestOptions : System.Collections.Generic.IDictionary< bool System.Collections.Generic.IDictionary.Remove(string key) { throw null; } bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair item) { throw null; } bool System.Collections.Generic.IDictionary.TryGetValue(string key, out object? value) { throw null; } - object? System.Collections.Generic.IDictionary.this[string key] { get { throw null; } set { } } void System.Collections.Generic.ICollection>.Add(System.Collections.Generic.KeyValuePair item) { throw null; } void System.Collections.Generic.ICollection>.Clear() { throw null; } @@ -247,7 +246,6 @@ public sealed class HttpRequestOptions : System.Collections.Generic.IDictionary< void System.Collections.Generic.ICollection>.CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { throw null; } int System.Collections.Generic.ICollection>.Count { get { throw null; } } bool System.Collections.Generic.ICollection>.IsReadOnly { get { throw null; } } - // public bool Remove(System.Collections.Generic.KeyValuePair item) { throw null; } System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() { throw null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } public bool TryGetValue(HttpRequestOptionsKey key, [MaybeNullWhen(false)] out TValue value) { throw null; } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Tests.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Tests.csproj index 0bb06264f93e83..89e9002a6809fa 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.Tests.csproj @@ -15,5 +15,6 @@ + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs new file mode 100644 index 00000000000000..bed90c0c99730f --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs @@ -0,0 +1,377 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.IO; +using System.Net.Http.Headers; +using System.Net.Http; +using System.Net; +using System.Threading.Tasks; + +using Xunit; +using Xunit.Abstractions; + +namespace System.Runtime.InteropServices.JavaScript.Http.Tests +{ + public class HttpRequestMessageTest + { + private readonly Version _expectedRequestMessageVersion = HttpVersion.Version11; + private HttpRequestOptionsKey EnableStreamingResponse = new HttpRequestOptionsKey("WebAssemblyEnableStreamingResponse"); +#nullable enable + private HttpRequestOptionsKey> FetchOptions = new HttpRequestOptionsKey>("WebAssemblyFetchOptions"); +#nullable disable + + [Fact] + public void Ctor_Default_CorrectDefaults() + { + var rm = new HttpRequestMessage(); + + Assert.Equal(HttpMethod.Get, rm.Method); + Assert.Null(rm.Content); + Assert.Null(rm.RequestUri); + } + + [Fact] + public void Ctor_RelativeStringUri_CorrectValues() + { + var rm = new HttpRequestMessage(HttpMethod.Post, "/relative"); + + Assert.Equal(HttpMethod.Post, rm.Method); + Assert.Equal(_expectedRequestMessageVersion, rm.Version); + Assert.Null(rm.Content); + Assert.Equal(new Uri("/relative", UriKind.Relative), rm.RequestUri); + } + + [Fact] + public void Ctor_AbsoluteStringUri_CorrectValues() + { + var rm = new HttpRequestMessage(HttpMethod.Post, "http://host/absolute/"); + + Assert.Equal(HttpMethod.Post, rm.Method); + Assert.Equal(_expectedRequestMessageVersion, rm.Version); + Assert.Null(rm.Content); + Assert.Equal(new Uri("http://host/absolute/"), rm.RequestUri); + } + + [Fact] + public void Ctor_NullStringUri_Accepted() + { + var rm = new HttpRequestMessage(HttpMethod.Put, (string)null); + + Assert.Null(rm.RequestUri); + Assert.Equal(HttpMethod.Put, rm.Method); + Assert.Equal(_expectedRequestMessageVersion, rm.Version); + Assert.Null(rm.Content); + } + + [Fact] + public void Ctor_RelativeUri_CorrectValues() + { + var uri = new Uri("/relative", UriKind.Relative); + var rm = new HttpRequestMessage(HttpMethod.Post, uri); + + Assert.Equal(HttpMethod.Post, rm.Method); + Assert.Equal(_expectedRequestMessageVersion, rm.Version); + Assert.Null(rm.Content); + Assert.Equal(uri, rm.RequestUri); + } + + [Fact] + public void Ctor_AbsoluteUri_CorrectValues() + { + var uri = new Uri("http://host/absolute/"); + var rm = new HttpRequestMessage(HttpMethod.Post, uri); + + Assert.Equal(HttpMethod.Post, rm.Method); + Assert.Equal(_expectedRequestMessageVersion, rm.Version); + Assert.Null(rm.Content); + Assert.Equal(uri, rm.RequestUri); + } + + [Fact] + public void Ctor_NullUri_Accepted() + { + var rm = new HttpRequestMessage(HttpMethod.Put, (Uri)null); + + Assert.Null(rm.RequestUri); + Assert.Equal(HttpMethod.Put, rm.Method); + Assert.Equal(_expectedRequestMessageVersion, rm.Version); + Assert.Null(rm.Content); + } + + [Fact] + public void Ctor_NullMethod_ThrowsArgumentNullException() + { + Assert.Throws(() => new HttpRequestMessage(null, "http://example.com")); + } + + [Fact] + public void Ctor_NonHttpUri_ThrowsArgumentException() + { + AssertExtensions.Throws("requestUri", () => new HttpRequestMessage(HttpMethod.Put, "ftp://example.com")); + } + + [Fact] + public void Dispose_DisposeObject_ContentGetsDisposedAndSettersWillThrowButGettersStillWork() + { + var rm = new HttpRequestMessage(HttpMethod.Get, "http://example.com"); + var content = new MockContent(); + rm.Content = content; + Assert.False(content.IsDisposed); + + rm.Dispose(); + rm.Dispose(); // Multiple calls don't throw. + + Assert.True(content.IsDisposed); + Assert.Throws(() => { rm.Method = HttpMethod.Put; }); + Assert.Throws(() => { rm.RequestUri = null; }); + Assert.Throws(() => { rm.Version = new Version(1, 0); }); + Assert.Throws(() => { rm.Content = null; }); + + // Property getters should still work after disposing. + Assert.Equal(HttpMethod.Get, rm.Method); + Assert.Equal(new Uri("http://example.com"), rm.RequestUri); + Assert.Equal(_expectedRequestMessageVersion, rm.Version); + Assert.Equal(content, rm.Content); + } + + [Fact] + public void Properties_SetOptionsAndGetTheirValue_MatchingValues() + { + var rm = new HttpRequestMessage(); + + var content = new MockContent(); + var uri = new Uri("https://example.com"); + var version = new Version(1, 0); + var method = new HttpMethod("custom"); + + rm.Content = content; + rm.Method = method; + rm.RequestUri = uri; + rm.Version = version; + + Assert.Equal(content, rm.Content); + Assert.Equal(uri, rm.RequestUri); + Assert.Equal(method, rm.Method); + Assert.Equal(version, rm.Version); + + Assert.NotNull(rm.Headers); + Assert.NotNull(rm.Options); + } + +#nullable enable + [Fact] + public void Properties_SetOptionsAndGetTheirValue_Set_FetchOptions() + { + var rm = new HttpRequestMessage(); + + var content = new MockContent(); + var uri = new Uri("https://example.com"); + var version = new Version(1, 0); + var method = new HttpMethod("custom"); + + rm.Content = content; + rm.Method = method; + rm.RequestUri = uri; + rm.Version = version; + + var fetchme = new Dictionary(); + fetchme.Add("hic", null); + fetchme.Add("sunt", 4444); + fetchme.Add("dracones", new List()); + rm.Options.Set(FetchOptions, fetchme); + + Assert.Equal(content, rm.Content); + Assert.Equal(uri, rm.RequestUri); + Assert.Equal(method, rm.Method); + Assert.Equal(version, rm.Version); + + Assert.NotNull(rm.Headers); + Assert.NotNull(rm.Options); + + rm.Options.TryGetValue(FetchOptions, out IDictionary? fetchOptionsValue); + Assert.NotNull(fetchOptionsValue); + if (fetchOptionsValue != null) + { + foreach (var item in fetchOptionsValue) + { + Assert.True(fetchme.ContainsKey(item.Key)); + } + } + } +#nullable disable + +#nullable enable + [Fact] + public void Properties_SetOptionsAndGetTheirValue_NotSet_FetchOptions() + { + var rm = new HttpRequestMessage(); + + var content = new MockContent(); + var uri = new Uri("https://example.com"); + var version = new Version(1, 0); + var method = new HttpMethod("custom"); + + rm.Content = content; + rm.Method = method; + rm.RequestUri = uri; + rm.Version = version; + + Assert.Equal(content, rm.Content); + Assert.Equal(uri, rm.RequestUri); + Assert.Equal(method, rm.Method); + Assert.Equal(version, rm.Version); + + Assert.NotNull(rm.Headers); + Assert.NotNull(rm.Options); + + rm.Options.TryGetValue(FetchOptions, out IDictionary? fetchOptionsValue); + Assert.Null(fetchOptionsValue); + } +#nullable disable + + [Fact] + public void Properties_SetOptionsAndGetTheirValue_Set_EnableStreamingResponse() + { + var rm = new HttpRequestMessage(); + + var content = new MockContent(); + var uri = new Uri("https://example.com"); + var version = new Version(1, 0); + var method = new HttpMethod("custom"); + + rm.Content = content; + rm.Method = method; + rm.RequestUri = uri; + rm.Version = version; + + rm.Options.Set(EnableStreamingResponse, true); + + Assert.Equal(content, rm.Content); + Assert.Equal(uri, rm.RequestUri); + Assert.Equal(method, rm.Method); + Assert.Equal(version, rm.Version); + + Assert.NotNull(rm.Headers); + Assert.NotNull(rm.Options); + + rm.Options.TryGetValue(EnableStreamingResponse, out bool streamingEnabledValue); + Assert.True(streamingEnabledValue); + } + + [Fact] + public void Properties_SetOptionsAndGetTheirValue_NotSet_EnableStreamingResponse() + { + var rm = new HttpRequestMessage(); + + var content = new MockContent(); + var uri = new Uri("https://example.com"); + var version = new Version(1, 0); + var method = new HttpMethod("custom"); + + rm.Content = content; + rm.Method = method; + rm.RequestUri = uri; + rm.Version = version; + + Assert.Equal(content, rm.Content); + Assert.Equal(uri, rm.RequestUri); + Assert.Equal(method, rm.Method); + Assert.Equal(version, rm.Version); + + Assert.NotNull(rm.Headers); + Assert.NotNull(rm.Options); + ((IDictionary)rm.Options)[nameof(content)] = "asdf"; + + rm.Options.TryGetValue(EnableStreamingResponse, out bool streamingEnabledValue); + Assert.False(streamingEnabledValue); + } + + [Fact] + public void RequestUri_SetNonHttpUri_ThrowsArgumentException() + { + var rm = new HttpRequestMessage(); + AssertExtensions.Throws("value", () => { rm.RequestUri = new Uri("ftp://example.com"); }); + } + + [Fact] + public void Version_SetToNull_ThrowsArgumentNullException() + { + var rm = new HttpRequestMessage(); + Assert.Throws(() => { rm.Version = null; }); + } + + [Fact] + public void Method_SetToNull_ThrowsArgumentNullException() + { + var rm = new HttpRequestMessage(); + Assert.Throws(() => { rm.Method = null; }); + } + + [Fact] + public void ToString_DefaultAndNonDefaultInstance_DumpAllFields() + { + var rm = new HttpRequestMessage(); + string expected = + "Method: GET, RequestUri: '', Version: " + + _expectedRequestMessageVersion.ToString(2) + + $", Content: , Headers:{Environment.NewLine}{{{Environment.NewLine}}}"; + Assert.Equal(expected, rm.ToString()); + + rm.Method = HttpMethod.Put; + rm.RequestUri = new Uri("http://a.com/"); + rm.Version = new Version(1, 0); + rm.Content = new StringContent("content"); + + // Note that there is no Content-Length header: The reason is that the value for Content-Length header + // doesn't get set by StringContent..ctor, but only if someone actually accesses the ContentLength property. + Assert.Equal( + "Method: PUT, RequestUri: 'http://a.com/', Version: 1.0, Content: " + typeof(StringContent).ToString() + ", Headers:" + Environment.NewLine + + $"{{{Environment.NewLine}" + + " Content-Type: text/plain; charset=utf-8" + Environment.NewLine + + "}", rm.ToString()); + + rm.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain", 0.2)); + rm.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml", 0.1)); + rm.Headers.Add("Custom-Request-Header", "value1"); + rm.Content.Headers.Add("Custom-Content-Header", "value2"); + + Assert.Equal( + "Method: PUT, RequestUri: 'http://a.com/', Version: 1.0, Content: " + typeof(StringContent).ToString() + ", Headers:" + Environment.NewLine + + "{" + Environment.NewLine + + " Accept: text/plain; q=0.2" + Environment.NewLine + + " Accept: text/xml; q=0.1" + Environment.NewLine + + " Custom-Request-Header: value1" + Environment.NewLine + + " Content-Type: text/plain; charset=utf-8" + Environment.NewLine + + " Custom-Content-Header: value2" + Environment.NewLine + + "}", rm.ToString()); + } + + #region Helper methods + + private class MockContent : HttpContent + { + public bool IsDisposed { get; private set; } + + protected override bool TryComputeLength(out long length) + { + throw new NotImplementedException(); + } + +#nullable enable + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) + { +#nullable disable + throw new NotImplementedException(); + } + + protected override void Dispose(bool disposing) + { + IsDisposed = true; + base.Dispose(disposing); + } + } + + #endregion + } +} From ea78e61453e6e20503ad90a2264fa646d896c1e8 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Thu, 16 Jul 2020 14:02:43 +0200 Subject: [PATCH 13/16] Fix test build --- .../InteropServices/JavaScript/Http/HttpRequestMessageTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs index bed90c0c99730f..80a8cd126f1562 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/Http/HttpRequestMessageTest.cs @@ -281,7 +281,6 @@ public void Properties_SetOptionsAndGetTheirValue_NotSet_EnableStreamingResponse Assert.NotNull(rm.Headers); Assert.NotNull(rm.Options); - ((IDictionary)rm.Options)[nameof(content)] = "asdf"; rm.Options.TryGetValue(EnableStreamingResponse, out bool streamingEnabledValue); Assert.False(streamingEnabledValue); From d6b49c5564ed9fc558488266753878b298ba8519 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Fri, 17 Jul 2020 12:46:01 +0200 Subject: [PATCH 14/16] Add special case code for NETFRAMEWORK for API change. --- ...tFactoryServiceCollectionExtensionsTest.cs | 74 ++++++++++++++++++- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs index 9342d41c8d0b69..8f33a97b1c82a5 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs @@ -948,10 +948,18 @@ public async Task AddHttpClient_MessageHandler_SingletonDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#if NETFRAMEWORK + Assert.Same( + services.GetRequiredService(), + request.Properties[nameof(SingletonService)]); + + Assert.Same( + client.Service, + request.Properties[nameof(SingletonService)]); +#else #nullable enable request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(SingletonService)), out SingletonService? optService); #nullable disable - Assert.Same( services.GetRequiredService(), optService); @@ -959,6 +967,7 @@ public async Task AddHttpClient_MessageHandler_SingletonDependency() Assert.Same( client.Service, optService); +#endif } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -983,6 +992,19 @@ public async Task AddHttpClient_MessageHandler_Scope_SingletonDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#if NETFRAMEWORK + Assert.Same( + services.GetRequiredService(), + request.Properties[nameof(SingletonService)]); + + Assert.Same( + scope.ServiceProvider.GetRequiredService(), + request.Properties[nameof(SingletonService)]); + + Assert.Same( + client.Service, + request.Properties[nameof(SingletonService)]); +#else #nullable enable request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(SingletonService)), out SingletonService? optService); #nullable disable @@ -999,6 +1021,7 @@ public async Task AddHttpClient_MessageHandler_Scope_SingletonDependency() client.Service, optService); } +#endif } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -1043,10 +1066,22 @@ public async Task AddHttpClient_MessageHandler_Scope_ScopedDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#if NETFRAMEWORK + Assert.NotSame( + scope.ServiceProvider.GetRequiredService(), + request.Properties[nameof(ScopedService)]); + + Assert.Same( + scope.ServiceProvider.GetRequiredService(), + client.Service); + + Assert.NotSame( + client.Service, + request.Properties[nameof(ScopedService)]); +#else #nullable enable request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(ScopedService)), out ScopedService? optService); #nullable disable - Assert.NotSame( scope.ServiceProvider.GetRequiredService(), optService); @@ -1059,6 +1094,7 @@ public async Task AddHttpClient_MessageHandler_Scope_ScopedDependency() client.Service, optService); } +#endif } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -1081,10 +1117,18 @@ public async Task AddHttpClient_MessageHandler_TransientDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#if NETFRAMEWORK + Assert.NotSame( + services.GetRequiredService(), + request.Properties[nameof(TransientService)]); + + Assert.NotSame( + client.Service, + request.Properties[nameof(TransientService)]); +#else #nullable enable request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(TransientService)), out TransientService? optService); #nullable disable - Assert.NotSame( services.GetRequiredService(), optService); @@ -1092,6 +1136,7 @@ public async Task AddHttpClient_MessageHandler_TransientDependency() Assert.NotSame( client.Service, optService); +#endif } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -1116,10 +1161,18 @@ public async Task AddHttpClient_MessageHandler_Scope_TransientDependency() var request = new HttpRequestMessage(HttpMethod.Get, "http://example.com/"); var response = await client.HttpClient.SendAsync(request); +#if NETFRAMEWORK + Assert.NotSame( + services.GetRequiredService(), + request.Properties[nameof(TransientService)]); + + Assert.NotSame( + client.Service, + request.Properties[nameof(TransientService)]); +#else #nullable enable request.Options.TryGetValue(new HttpRequestOptionsKey(nameof(TransientService)), out TransientService? optService); #nullable disable - Assert.NotSame( services.GetRequiredService(), optService); @@ -1128,6 +1181,7 @@ public async Task AddHttpClient_MessageHandler_Scope_TransientDependency() client.Service, optService); } +#endif } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -1324,7 +1378,11 @@ public HandlerWithSingletonService(SingletonService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { +#if NETFRAMEWORK + request.Properties[nameof(SingletonService)] = Service; +#else request.Options.Set(new HttpRequestOptionsKey(nameof(SingletonService)), Service); +#endif return Task.FromResult(new HttpResponseMessage()); } } @@ -1340,7 +1398,11 @@ public HandlerWithScopedService(ScopedService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { +#if NETFRAMEWORK + request.Properties[nameof(ScopedService)] = Service; +#else request.Options.Set(new HttpRequestOptionsKey(nameof(ScopedService)), Service); +#endif return Task.FromResult(new HttpResponseMessage()); } } @@ -1356,7 +1418,11 @@ public HandlerWithTransientService(TransientService service) protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { +#if NETFRAMEWORK + request.Properties[nameof(TransientService)] = Service; +#else request.Options.Set(new HttpRequestOptionsKey(nameof(TransientService)), Service); +#endif return Task.FromResult(new HttpResponseMessage()); } } From 1b5683ed02cb68c6dbb878034b8d7413bca661d2 Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Fri, 17 Jul 2020 14:11:41 +0200 Subject: [PATCH 15/16] #endif out of place fix --- .../HttpClientFactoryServiceCollectionExtensionsTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs index 8f33a97b1c82a5..820ced97b08708 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs @@ -1020,8 +1020,8 @@ public async Task AddHttpClient_MessageHandler_Scope_SingletonDependency() Assert.Same( client.Service, optService); - } #endif + } } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] @@ -1093,8 +1093,8 @@ public async Task AddHttpClient_MessageHandler_Scope_ScopedDependency() Assert.NotSame( client.Service, optService); - } #endif + } } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] From 23f1bc8121125a29ba5a941fdc8249958f36245b Mon Sep 17 00:00:00 2001 From: Kenneth Pouncey Date: Fri, 17 Jul 2020 15:50:42 +0200 Subject: [PATCH 16/16] #endif out of place fix --- .../HttpClientFactoryServiceCollectionExtensionsTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs index 820ced97b08708..fec6276e6ce26d 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/DependencyInjection/HttpClientFactoryServiceCollectionExtensionsTest.cs @@ -1180,8 +1180,8 @@ public async Task AddHttpClient_MessageHandler_Scope_TransientDependency() Assert.NotSame( client.Service, optService); - } #endif + } } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]