/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Hosting/TestHost/test/ClientHandlerTests.cs
755 строк
29 KB
Copilot
Add [Obsolete] attribute to WebHost, IWebHost, and WebHostService
15 авг 2025, 20:33
Не верифицирован
15 авг 2025, 20:33
fe0ccd9
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Net; using System.Net.Http; using System.Text; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.TestHost; public class ClientHandlerTests { [Fact] public async Task SlashUrlEncodedDoesNotGetDecoded() { var handler = new ClientHandler(new PathString(), new InspectingApplication(features => { Assert.True(features.Get<IHttpRequestLifetimeFeature>().RequestAborted.CanBeCanceled); Assert.Equal(HttpProtocol.Http11, features.Get<IHttpRequestFeature>().Protocol); Assert.Equal("GET", features.Get<IHttpRequestFeature>().Method); Assert.Equal("https", features.Get<IHttpRequestFeature>().Scheme); Assert.Equal("/api/a%2Fb c", features.Get<IHttpRequestFeature>().Path); Assert.NotNull(features.Get<IHttpRequestFeature>().Body); Assert.NotNull(features.Get<IHttpRequestFeature>().Headers); Assert.NotNull(features.Get<IHttpResponseFeature>().Headers); Assert.NotNull(features.Get<IHttpResponseBodyFeature>().Stream); Assert.Equal(200, features.Get<IHttpResponseFeature>().StatusCode); Assert.Null(features.Get<IHttpResponseFeature>().ReasonPhrase); Assert.Equal("example.com", features.Get<IHttpRequestFeature>().Headers["host"]); Assert.NotNull(features.Get<IHttpRequestLifetimeFeature>()); })); var httpClient = new HttpClient(handler); await httpClient.GetAsync("https://example.com/api/a%2Fb%20c"); } [Fact] public Task ExpectedKeysAreAvailable() { var handler = new ClientHandler(new PathString("/A/Path/"), new DummyApplication(context => { // TODO: Assert.True(context.RequestAborted.CanBeCanceled); Assert.Equal(HttpProtocol.Http11, context.Request.Protocol); Assert.Equal("GET", context.Request.Method); Assert.Equal("https", context.Request.Scheme); Assert.Equal("/A/Path", context.Request.PathBase.Value); Assert.Equal("/and/file.txt", context.Request.Path.Value); Assert.Equal("?and=query", context.Request.QueryString.Value); Assert.NotNull(context.Request.Body); Assert.NotNull(context.Request.Headers); Assert.NotNull(context.Response.Headers); Assert.NotNull(context.Response.Body); Assert.Equal(200, context.Response.StatusCode); Assert.Null(context.Features.Get<IHttpResponseFeature>().ReasonPhrase); Assert.Equal("example.com", context.Request.Host.Value); return Task.FromResult(0); })); var httpClient = new HttpClient(handler); return httpClient.GetAsync("https://example.com/A/Path/and/file.txt?and=query"); } [Fact] public Task ExpectedKeysAreInFeatures() { var handler = new ClientHandler(new PathString("/A/Path/"), new InspectingApplication(features => { Assert.True(features.Get<IHttpRequestLifetimeFeature>().RequestAborted.CanBeCanceled); Assert.Equal(HttpProtocol.Http11, features.Get<IHttpRequestFeature>().Protocol); Assert.Equal("GET", features.Get<IHttpRequestFeature>().Method); Assert.Equal("https", features.Get<IHttpRequestFeature>().Scheme); Assert.Equal("/A/Path", features.Get<IHttpRequestFeature>().PathBase); Assert.Equal("/and/file.txt", features.Get<IHttpRequestFeature>().Path); Assert.Equal("?and=query", features.Get<IHttpRequestFeature>().QueryString); Assert.NotNull(features.Get<IHttpRequestFeature>().Body); Assert.NotNull(features.Get<IHttpRequestFeature>().Headers); Assert.NotNull(features.Get<IHttpResponseFeature>().Headers); Assert.NotNull(features.Get<IHttpResponseBodyFeature>().Stream); Assert.Equal(200, features.Get<IHttpResponseFeature>().StatusCode); Assert.Null(features.Get<IHttpResponseFeature>().ReasonPhrase); Assert.Equal("example.com", features.Get<IHttpRequestFeature>().Headers["host"]); Assert.NotNull(features.Get<IHttpRequestLifetimeFeature>()); })); var httpClient = new HttpClient(handler); return httpClient.GetAsync("https://example.com/A/Path/and/file.txt?and=query"); } [Fact] public Task SingleSlashNotMovedToPathBase() { var handler = new ClientHandler(new PathString(""), new DummyApplication(context => { Assert.Equal("", context.Request.PathBase.Value); Assert.Equal("/", context.Request.Path.Value); return Task.FromResult(0); })); var httpClient = new HttpClient(handler); return httpClient.GetAsync("https://example.com/"); } [Fact] public Task UserAgentHeaderWorks() { var userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0"; var handler = new ClientHandler(new PathString(""), new DummyApplication(context => { var actualResult = context.Request.Headers.UserAgent; Assert.Equal(userAgent, actualResult); return Task.CompletedTask; })); var httpClient = new HttpClient(handler); httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, userAgent); return httpClient.GetAsync("http://example.com"); } [Fact] public Task ContentLengthWithBodyWorks() { var contentBytes = Encoding.UTF8.GetBytes("This is a content!"); var handler = new ClientHandler(new PathString(""), new DummyApplication(context => { Assert.True(context.Request.CanHaveBody()); Assert.Equal(contentBytes.LongLength, context.Request.ContentLength); Assert.False(context.Request.Headers.ContainsKey(HeaderNames.TransferEncoding)); return Task.CompletedTask; })); var httpClient = new HttpClient(handler); var content = new ByteArrayContent(contentBytes); return httpClient.PostAsync("http://example.com", content); } [Fact] public Task ContentLengthNotPresentWithNoBody() { var handler = new ClientHandler(new PathString(""), new DummyApplication(context => { Assert.False(context.Request.CanHaveBody()); Assert.Null(context.Request.ContentLength); Assert.False(context.Request.Headers.ContainsKey(HeaderNames.TransferEncoding)); return Task.CompletedTask; })); var httpClient = new HttpClient(handler); return httpClient.GetAsync("http://example.com"); } [Fact] public Task ContentLengthWithImplicitChunkedTransferEncodingWorks() { var handler = new ClientHandler(new PathString(""), new DummyApplication(context => { Assert.True(context.Request.CanHaveBody()); Assert.Null(context.Request.ContentLength); Assert.Equal("chunked", context.Request.Headers.TransferEncoding); return Task.CompletedTask; })); var httpClient = new HttpClient(handler); return httpClient.PostAsync("http://example.com", new UnlimitedContent()); } [Fact] public Task ContentLengthWithExplicitChunkedTransferEncodingWorks() { var handler = new ClientHandler(new PathString(""), new DummyApplication(context => { Assert.True(context.Request.CanHaveBody()); Assert.Null(context.Request.ContentLength); Assert.Equal("chunked", context.Request.Headers.TransferEncoding); return Task.CompletedTask; })); var httpClient = new HttpClient(handler); httpClient.DefaultRequestHeaders.TransferEncodingChunked = true; var contentBytes = Encoding.UTF8.GetBytes("This is a content!"); var content = new ByteArrayContent(contentBytes); return httpClient.PostAsync("http://example.com", content); } [Fact] public async Task ServerTrailersSetOnResponseAfterContentRead() { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.AppendTrailer("StartTrailer", "Value!"); await context.Response.WriteAsync("Hello World"); await context.Response.Body.FlushAsync(); // Pause writing response to ensure trailers are written at the end await tcs.Task; await context.Response.WriteAsync("Bye World"); await context.Response.Body.FlushAsync(); context.Response.AppendTrailer("EndTrailer", "Value!"); })); var invoker = new HttpMessageInvoker(handler); var message = new HttpRequestMessage(HttpMethod.Post, "https://example.com/"); var response = await invoker.SendAsync(message, CancellationToken.None); Assert.Empty(response.TrailingHeaders); var responseBody = await response.Content.ReadAsStreamAsync(); int read = await responseBody.ReadAsync(new byte[100], 0, 100); Assert.Equal(11, read); Assert.Empty(response.TrailingHeaders); var readTask = responseBody.ReadAsync(new byte[100], 0, 100); Assert.False(readTask.IsCompleted); tcs.TrySetResult(); read = await readTask; Assert.Equal(9, read); Assert.Empty(response.TrailingHeaders); // Read nothing because we're at the end of the response read = await responseBody.ReadAsync(new byte[100], 0, 100); Assert.Equal(0, read); // Ensure additional reads after end don't effect trailers read = await responseBody.ReadAsync(new byte[100], 0, 100); Assert.Equal(0, read); Assert.Collection(response.TrailingHeaders, kvp => { Assert.Equal("StartTrailer", kvp.Key); Assert.Equal("Value!", kvp.Value.Single()); }, kvp => { Assert.Equal("EndTrailer", kvp.Key); Assert.Equal("Value!", kvp.Value.Single()); }); } [Fact] public Task AdditionalConfigurationAllowsSettingConnectionInfo() { var handler = new ClientHandler(PathString.Empty, new InspectingApplication(features => { Assert.Equal(IPAddress.Parse("1.1.1.1"), features.Get<IHttpConnectionFeature>().RemoteIpAddress); }), context => { context.Connection.RemoteIpAddress = IPAddress.Parse("1.1.1.1"); }); var httpClient = new HttpClient(handler); return httpClient.GetAsync("https://example.com/A/Path/and/file.txt?and=query"); } [Fact] public Task AdditionalConfigurationAllowsOverridingDefaultBehavior() { var handler = new ClientHandler(PathString.Empty, new InspectingApplication(features => { Assert.Equal("?and=something", features.Get<IHttpRequestFeature>().QueryString); }), context => { context.Request.QueryString = new QueryString("?and=something"); }); var httpClient = new HttpClient(handler); return httpClient.GetAsync("https://example.com/A/Path/and/file.txt?and=query"); } [Fact] public async Task ResponseStartAsync() { var hasStartedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var hasAssertedResponseTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); bool? preHasStarted = null; bool? postHasStarted = null; var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { preHasStarted = context.Response.HasStarted; await context.Response.StartAsync(); postHasStarted = context.Response.HasStarted; hasStartedTcs.TrySetResult(); await hasAssertedResponseTcs.Task; })); var invoker = new HttpMessageInvoker(handler); var message = new HttpRequestMessage(HttpMethod.Post, "https://example.com/"); var responseTask = invoker.SendAsync(message, CancellationToken.None); // Ensure StartAsync has been called in response await hasStartedTcs.Task; // Delay so async thread would have had time to attempt to return response await Task.Delay(100); Assert.False(responseTask.IsCompleted, "HttpResponse.StartAsync does not return response"); // Asserted that response return was checked, allow response to finish hasAssertedResponseTcs.TrySetResult(); await responseTask; Assert.False(preHasStarted); Assert.True(postHasStarted); } [Fact] public void Send_ThrowsNotSupportedException() { var handler = new ClientHandler( PathString.Empty, new DummyApplication(context => { return Task.CompletedTask; })); var invoker = new HttpMessageInvoker(handler); var message = new HttpRequestMessage(HttpMethod.Post, "https://example.com/"); Assert.Throws<NotSupportedException>(() => invoker.Send(message, CancellationToken.None)); } [Fact] public async Task ResubmitRequestWorks() { int requestCount = 1; var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { int read = await context.Request.Body.ReadAsync(new byte[100], 0, 100); Assert.Equal(11, read); context.Response.Headers["TestHeader"] = "TestValue:" + requestCount++; })); HttpMessageInvoker invoker = new HttpMessageInvoker(handler); HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, "https://example.com/"); message.Content = new StringContent("Hello World"); HttpResponseMessage response = await invoker.SendAsync(message, CancellationToken.None); Assert.Equal("TestValue:1", response.Headers.GetValues("TestHeader").First()); response = await invoker.SendAsync(message, CancellationToken.None); Assert.Equal("TestValue:2", response.Headers.GetValues("TestHeader").First()); } [Fact] public async Task MiddlewareOnlySetsHeaders() { var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => { context.Response.Headers["TestHeader"] = "TestValue"; return Task.FromResult(0); })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/"); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); } [Fact] public async Task BlockingMiddlewareShouldNotBlockClient() { ManualResetEvent block = new ManualResetEvent(false); var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => { block.WaitOne(); return Task.FromResult(0); })); var httpClient = new HttpClient(handler); Task<HttpResponseMessage> task = httpClient.GetAsync("https://example.com/"); Assert.False(task.IsCompleted); #pragma warning disable xUnit1031 // Do not use blocking task operations in test method Assert.False(task.Wait(50)); #pragma warning restore xUnit1031 // Do not use blocking task operations in test method block.Set(); HttpResponseMessage response = await task; } [Fact] public async Task HeadersAvailableBeforeBodyFinished() { var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.Headers["TestHeader"] = "TestValue"; await context.Response.WriteAsync("BodyStarted,"); await block.Task; await context.Response.WriteAsync("BodyFinished"); })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); block.SetResult(); Assert.Equal("BodyStarted,BodyFinished", await response.Content.ReadAsStringAsync()); } [Fact] public async Task FlushSendsHeaders() { var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.Headers["TestHeader"] = "TestValue"; await context.Response.Body.FlushAsync(); await block.Task; await context.Response.WriteAsync("BodyFinished"); })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); block.SetResult(); Assert.Equal("BodyFinished", await response.Content.ReadAsStringAsync()); } [Fact] public async Task ClientDisposalCloses() { var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.Headers["TestHeader"] = "TestValue"; await context.Response.Body.FlushAsync(); await block.Task; })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); Stream responseStream = await response.Content.ReadAsStreamAsync(); Task<int> readTask = responseStream.ReadAsync(new byte[100], 0, 100); Assert.False(readTask.IsCompleted); responseStream.Dispose(); await Assert.ThrowsAsync<OperationCanceledException>(() => readTask.DefaultTimeout()); block.SetResult(); } [Fact] public async Task ClientCancellationAborts() { var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.Headers["TestHeader"] = "TestValue"; await context.Response.Body.FlushAsync(); await block.Task; })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); Stream responseStream = await response.Content.ReadAsStreamAsync(); CancellationTokenSource cts = new CancellationTokenSource(); Task<int> readTask = responseStream.ReadAsync(new byte[100], 0, 100, cts.Token); Assert.False(readTask.IsCompleted, "Not Completed"); cts.Cancel(); await Assert.ThrowsAsync<OperationCanceledException>(() => readTask.DefaultTimeout()); block.SetResult(); } [Fact] public async Task ExceptionFromDisposedRequestContent() { var requestCount = 0; var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => { requestCount++; return Task.CompletedTask; })); var invoker = new HttpMessageInvoker(handler); Task<HttpResponseMessage> responseTask; using (var message = new HttpRequestMessage(HttpMethod.Post, "https://example.com/")) { message.Content = new StringContent("Hello World"); message.Content.Dispose(); responseTask = invoker.SendAsync(message, CancellationToken.None); } await Assert.ThrowsAsync<ObjectDisposedException>(() => responseTask); Assert.Equal(0, requestCount); } [Fact] public Task ExceptionBeforeFirstWriteIsReported() { var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => { throw new InvalidOperationException("Test Exception"); })); var httpClient = new HttpClient(handler); return Assert.ThrowsAsync<InvalidOperationException>(() => httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead)); } [Fact] public async Task ExceptionAfterFirstWriteIsReported() { var block = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.Headers["TestHeader"] = "TestValue"; await context.Response.WriteAsync("BodyStarted"); await block.Task; throw new InvalidOperationException("Test Exception"); })); var httpClient = new HttpClient(handler); HttpResponseMessage response = await httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead); Assert.Equal("TestValue", response.Headers.GetValues("TestHeader").First()); block.SetResult(); var ex = await Assert.ThrowsAsync<HttpRequestException>(() => response.Content.ReadAsStringAsync()); Assert.IsType<InvalidOperationException>(ex.GetBaseException()); } [Fact] public Task ExceptionFromOnStartingFirstWriteIsReported() { var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => { context.Response.OnStarting(() => { throw new InvalidOperationException(new string('a', 1024 * 32)); }); return context.Response.WriteAsync("Hello World"); })); var httpClient = new HttpClient(handler); return Assert.ThrowsAsync<InvalidOperationException>(() => httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead)); } [Fact] public Task ExceptionFromOnStartingWithNoWriteIsReported() { var handler = new ClientHandler(PathString.Empty, new DummyApplication(context => { context.Response.OnStarting(() => { throw new InvalidOperationException(new string('a', 1024 * 32)); }); return Task.CompletedTask; })); var httpClient = new HttpClient(handler); return Assert.ThrowsAsync<InvalidOperationException>(() => httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead)); } [Fact] public Task ExceptionFromOnStartingWithErrorHandlerIsReported() { var handler = new ClientHandler(PathString.Empty, new DummyApplication(async context => { context.Response.OnStarting(() => { throw new InvalidOperationException(new string('a', 1024 * 32)); }); try { await context.Response.WriteAsync("Hello World"); } catch (Exception ex) { // This is no longer the first write, so it doesn't trigger OnStarting again. // The exception is large enough that it fills the pipe and stalls. await context.Response.WriteAsync(ex.ToString()); } })); var httpClient = new HttpClient(handler); return Assert.ThrowsAsync<InvalidOperationException>(() => httpClient.GetAsync("https://example.com/", HttpCompletionOption.ResponseHeadersRead)); } private class DummyApplication : ApplicationWrapper, IHttpApplication<TestHostingContext> { RequestDelegate _application; public DummyApplication(RequestDelegate application) { _application = application; } internal override object CreateContext(IFeatureCollection features) { return ((IHttpApplication<TestHostingContext>)this).CreateContext(features); } TestHostingContext IHttpApplication<TestHostingContext>.CreateContext(IFeatureCollection contextFeatures) { return new TestHostingContext() { HttpContext = new DefaultHttpContext(contextFeatures) }; } internal override void DisposeContext(object context, Exception exception) { ((IHttpApplication<TestHostingContext>)this).DisposeContext((TestHostingContext)context, exception); } void IHttpApplication<TestHostingContext>.DisposeContext(TestHostingContext context, Exception exception) { } internal override Task ProcessRequestAsync(object context) { return ((IHttpApplication<TestHostingContext>)this).ProcessRequestAsync((TestHostingContext)context); } Task IHttpApplication<TestHostingContext>.ProcessRequestAsync(TestHostingContext context) { return _application(context.HttpContext); } } private class InspectingApplication : ApplicationWrapper, IHttpApplication<TestHostingContext> { Action<IFeatureCollection> _inspector; public InspectingApplication(Action<IFeatureCollection> inspector) { _inspector = inspector; } internal override object CreateContext(IFeatureCollection features) { return ((IHttpApplication<TestHostingContext>)this).CreateContext(features); } TestHostingContext IHttpApplication<TestHostingContext>.CreateContext(IFeatureCollection contextFeatures) { _inspector(contextFeatures); return new TestHostingContext() { HttpContext = new DefaultHttpContext(contextFeatures) }; } internal override void DisposeContext(object context, Exception exception) { ((IHttpApplication<TestHostingContext>)this).DisposeContext((TestHostingContext)context, exception); } void IHttpApplication<TestHostingContext>.DisposeContext(TestHostingContext context, Exception exception) { } internal override Task ProcessRequestAsync(object context) { return ((IHttpApplication<TestHostingContext>)this).ProcessRequestAsync((TestHostingContext)context); } Task IHttpApplication<TestHostingContext>.ProcessRequestAsync(TestHostingContext context) { return Task.FromResult(0); } } private class TestHostingContext { public HttpContext HttpContext { get; set; } } [Fact] public async Task ClientHandlerCreateContextWithDefaultRequestParameters() { // This logger will attempt to access information from HttpRequest once the HttpContext is created var logger = new VerifierLogger(); using var host = new HostBuilder() .ConfigureWebHost(webHostBuilder => { webHostBuilder .UseTestServer() .ConfigureServices(services => { #pragma warning disable ASPDEPR008 // IWebHost is obsolete services.AddSingleton<ILogger<IWebHost>>(logger); #pragma warning restore ASPDEPR008 // IWebHost is obsolete }) .Configure(app => { app.Run(context => { return Task.FromResult(0); }); }); }) .Build(); var server = host.GetTestServer(); await host.StartAsync(); // The HttpContext will be created and the logger will make sure that the HttpRequest exists and contains reasonable values var result = await server.CreateClient().GetStringAsync("/"); } #pragma warning disable ASPDEPR008 // IWebHost is obsolete private class VerifierLogger : ILogger<IWebHost> #pragma warning restore ASPDEPR008 // IWebHost is obsolete { public IDisposable BeginScope<TState>(TState state) => new NoopDispoasble(); public bool IsEnabled(LogLevel logLevel) => true; // This call verifies that fields of HttpRequest are accessed and valid public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) => formatter(state, exception); class NoopDispoasble : IDisposable { public void Dispose() { } } } private class UnlimitedContent : HttpContent { protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { return Task.CompletedTask; } protected override bool TryComputeLength(out long length) { length = -1; return false; } } }