Merge pull request #23 from mikeparker/delegating-handler-support

Add ability to insert delegating handlers into HttpClient
This commit is contained in:
Mike Parker 2019-10-22 18:22:10 +01:00 коммит произвёл GitHub
Родитель d8bb2f659e 414e68650e
Коммит 63f6ed34df
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 116 добавлений и 17 удалений

Просмотреть файл

@ -102,7 +102,7 @@ namespace HttpOverStream.Client
await request.Content.CopyToAsync(stream).ConfigureAwait(false);
}
_logger.LogVerbose("HttpOS Client: stream.FlushAsync");
_logger.LogVerbose("HttpOS Client: stream.FlushAsync");
await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
_logger.LogVerbose("HttpOS Client: Finished writing request");
}, cancellationToken);

Просмотреть файл

@ -0,0 +1,49 @@
using System;
using System.Net.Http;
using HttpOverStream.Logging;
namespace HttpOverStream.NamedPipe
{
public class NamedPipeHttpClientBuilder
{
private string _pipeName;
private ILoggerHttpOverStream _logger;
private DelegatingHandler _outerHandler;
private TimeSpan? _perRequestTimeout;
private Version _httpVersion;
public NamedPipeHttpClientBuilder(string pipeName)
{
_pipeName = pipeName;
}
public NamedPipeHttpClientBuilder WithLogger(ILoggerHttpOverStream logger)
{
_logger = logger;
return this;
}
public NamedPipeHttpClientBuilder WithDelegatingHandler(DelegatingHandler outerHandler)
{
_outerHandler = outerHandler;
return this;
}
public NamedPipeHttpClientBuilder WithPerRequestTimeout(TimeSpan perRequestTimeout)
{
_perRequestTimeout = perRequestTimeout;
return this;
}
public NamedPipeHttpClientBuilder WithHttpVersion(Version httpVersion)
{
_httpVersion = httpVersion;
return this;
}
public HttpClient Build()
{
return NamedPipeHttpClientFactory.ForPipeName(_pipeName, _logger, _perRequestTimeout, _httpVersion, _outerHandler);
}
}
}

Просмотреть файл

@ -7,13 +7,21 @@ namespace HttpOverStream.NamedPipe
{
public class NamedPipeHttpClientFactory
{
public static HttpClient ForPipeName(string pipeName, ILoggerHttpOverStream logger = null, TimeSpan? perRequestTimeout = null, Version httpVersion = null)
public static HttpClient ForPipeName(string pipeName, ILoggerHttpOverStream logger = null, TimeSpan? perRequestTimeout = null, Version httpVersion = null, DelegatingHandler outerHandler = null )
{
var httpClient = new HttpClient(new DialMessageHandler(new NamedPipeDialer(pipeName), logger, httpVersion))
var innerHandler = new DialMessageHandler(new NamedPipeDialer(pipeName), logger, httpVersion);
HttpClient httpClient;
if (outerHandler != null)
{
BaseAddress = new Uri("http://localhost")
};
outerHandler.InnerHandler = innerHandler;
httpClient = new HttpClient(outerHandler);
}
else
{
httpClient = new HttpClient(innerHandler);
}
httpClient.BaseAddress = new Uri("http://localhost");
if (perRequestTimeout != null)
{
httpClient.Timeout = perRequestTimeout.Value;

Просмотреть файл

@ -105,15 +105,17 @@ namespace HttpOverStream.Server.Owin.Tests
{
for (int i = 0; i < numberOfRequests; i++)
{
var client = new HttpClient(new DialMessageHandler(new NamedPipeDialer(TestContext.TestName), null, httpVersion));
client.Timeout = TimeSpan.FromSeconds(5);
var client = new NamedPipeHttpClientBuilder(TestContext.TestName)
.WithPerRequestTimeout(TimeSpan.FromSeconds(5))
.WithHttpVersion(httpVersion)
.WithDelegatingHandler(new TestLoggingHandler())
.Build();
var result = await client.GetAsync("http://localhost/api/e2e-tests/hello-world");
Assert.AreEqual("Hello World", await result.Content.ReadAsAsync<string>());
}
}
}
[TestMethod]
public async Task TestGetStressTest_ClientBeforeServer()
{
@ -140,8 +142,9 @@ namespace HttpOverStream.Server.Owin.Tests
{
for (int i = 0; i < numberOfRequests; i++)
{
var client2 = new HttpClient(new DialMessageHandler(new NamedPipeDialer(TestContext.TestName)));
client2.Timeout = TimeSpan.FromSeconds(5);
var client2 = new NamedPipeHttpClientBuilder(TestContext.TestName)
.WithPerRequestTimeout(TimeSpan.FromSeconds(5))
.Build();
var result = await client2.GetAsync("http://localhost/api/e2e-tests/hello-world");
Assert.AreEqual("Hello World", await result.Content.ReadAsAsync<string>());
}
@ -161,8 +164,9 @@ namespace HttpOverStream.Server.Owin.Tests
{
using (CustomListenerHost.Start(SetupDefaultAppBuilder, new NamedPipeListener(TestContext.TestName)))
{
var client = new HttpClient(new DialMessageHandler(new NamedPipeDialer(TestContext.TestName)));
client.Timeout = TimeSpan.FromSeconds(1);
var client = new NamedPipeHttpClientBuilder(TestContext.TestName)
.WithPerRequestTimeout(TimeSpan.FromSeconds(1))
.Build();
var badContent = new StringContent("{ ", Encoding.UTF8, "application/broken");
var result = await client.PostAsJsonAsync("http://localhost/api/e2e-tests/hello", badContent);
var wlcMsg = await result.Content.ReadAsAsync<WelcomeMessage>();
@ -189,7 +193,7 @@ namespace HttpOverStream.Server.Owin.Tests
{
using (CustomListenerHost.Start(SetupDefaultAppBuilder, new NamedPipeListener(TestContext.TestName)))
{
var client = new HttpClient(new DialMessageHandler(new NamedPipeDialer(TestContext.TestName)));
var client = NamedPipeHttpClientFactory.ForPipeName(TestContext.TestName);
try
{
var badContent = new StringContent("{ }");
@ -273,7 +277,7 @@ namespace HttpOverStream.Server.Owin.Tests
{
using (CustomListenerHost.Start(SetupDefaultAppBuilder, new NamedPipeListener(TestContext.TestName)))
{
var client = new HttpClient(new DialMessageHandler(new NamedPipeDialer(TestContext.TestName)));
var client = NamedPipeHttpClientFactory.ForPipeName(TestContext.TestName);
var result = await client.PostAsJsonAsync("http://localhost/api/e2e-tests/hello", new PersonMessage { Name = "Test" });
var wlcMsg = await result.Content.ReadAsAsync<WelcomeMessage>();
Assert.AreEqual("Hello Test", wlcMsg.Text);
@ -283,7 +287,7 @@ namespace HttpOverStream.Server.Owin.Tests
[TestMethod]
public async Task TestPost_WhenNoServerListening_ThrowsTimeoutException()
{
var client = new HttpClient(new DialMessageHandler(new NamedPipeDialer(TestContext.TestName)));
var client = NamedPipeHttpClientFactory.ForPipeName(TestContext.TestName);
await Assert.ThrowsExceptionAsync<TimeoutException>(async () => await client.PostAsJsonAsync("http://localhost/api/e2e-tests/hello", new PersonMessage { Name = "Test" }));
}
@ -334,8 +338,7 @@ namespace HttpOverStream.Server.Owin.Tests
{
using (CustomListenerHost.Start(SetupDefaultAppBuilder, new NamedPipeListener(TestContext.TestName)))
{
var client = new HttpClient(new DialMessageHandler(new NamedPipeDialer(TestContext.TestName)));
client.Timeout = TimeSpan.FromMilliseconds(100);
var client = NamedPipeHttpClientFactory.ForPipeName(TestContext.TestName, null, TimeSpan.FromMilliseconds(100));
var sw = Stopwatch.StartNew();
await Assert.ThrowsExceptionAsync<TaskCanceledException>(async () =>
{

Просмотреть файл

@ -80,6 +80,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="TestLoggingHandler.cs" />
<Compile Include="EndToEndTests.cs" />
<Compile Include="OnceTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

Просмотреть файл

@ -0,0 +1,38 @@
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace HttpOverStream.Server.Owin.Tests
{
public class TestLoggingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var correlationId = Guid.NewGuid();
LogRequest(request, correlationId);
var stopwatch = Stopwatch.StartNew();
var response = await base.SendAsync(request, cancellationToken);
stopwatch.Stop();
LogResponse(request, response, stopwatch.Elapsed, correlationId);
return response;
}
private void LogRequest(HttpRequestMessage request, Guid correlationId)
{
if (request == null)
{
Console.WriteLine("Null request");
return;
}
Console.WriteLine($"[{correlationId}] {request.Method?.Method} {request.RequestUri}");
}
private void LogResponse(HttpRequestMessage request, HttpResponseMessage response, TimeSpan stopwatchElapsed, Guid correlationId)
{
Console.WriteLine($"[{correlationId}] {request?.Method?.Method} {request?.RequestUri} -> {(int)response.StatusCode} {response.StatusCode} took {(int)stopwatchElapsed.TotalMilliseconds}ms");
}
}
}