mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-30 22:32:56 +02:00
Fix issue with concurrent logging (#63)
* Fix issue with concurrent logging * Fix namespace + code format/cleanup
This commit is contained in:
committed by
Stef Heyenrath
parent
6c38400827
commit
a15e6747b0
@@ -46,6 +46,7 @@ namespace WireMock.Owin
|
|||||||
_host = new WebHostBuilder()
|
_host = new WebHostBuilder()
|
||||||
.Configure(appBuilder =>
|
.Configure(appBuilder =>
|
||||||
{
|
{
|
||||||
|
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
|
||||||
_options.PreWireMockMiddlewareInit?.Invoke(appBuilder);
|
_options.PreWireMockMiddlewareInit?.Invoke(appBuilder);
|
||||||
appBuilder.UseMiddleware<WireMockMiddleware>(_options);
|
appBuilder.UseMiddleware<WireMockMiddleware>(_options);
|
||||||
_options.PostWireMockMiddlewareInit?.Invoke(appBuilder);
|
_options.PostWireMockMiddlewareInit?.Invoke(appBuilder);
|
||||||
|
|||||||
49
src/WireMock.Net/Owin/GlobalExceptionMiddleware.cs
Normal file
49
src/WireMock.Net/Owin/GlobalExceptionMiddleware.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
#if !NETSTANDARD
|
||||||
|
using Microsoft.Owin;
|
||||||
|
#else
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace WireMock.Owin
|
||||||
|
{
|
||||||
|
#if !NETSTANDARD
|
||||||
|
internal class GlobalExceptionMiddleware : OwinMiddleware
|
||||||
|
#else
|
||||||
|
internal class GlobalExceptionMiddleware
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if !NETSTANDARD
|
||||||
|
public GlobalExceptionMiddleware(OwinMiddleware next) : base(next) { }
|
||||||
|
#else
|
||||||
|
public GlobalExceptionMiddleware(RequestDelegate next)
|
||||||
|
{
|
||||||
|
Next = next;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NETSTANDARD
|
||||||
|
public RequestDelegate Next { get; private set; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper();
|
||||||
|
|
||||||
|
#if !NETSTANDARD
|
||||||
|
public override async Task Invoke(IOwinContext ctx)
|
||||||
|
#else
|
||||||
|
public async Task Invoke(HttpContext ctx)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Next?.Invoke(ctx);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await _responseMapper.MapAsync(new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) }, ctx.Response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,6 +61,7 @@ namespace WireMock.Owin
|
|||||||
|
|
||||||
Action<IAppBuilder> startup = app =>
|
Action<IAppBuilder> startup = app =>
|
||||||
{
|
{
|
||||||
|
app.Use<GlobalExceptionMiddleware>();
|
||||||
_options.PreWireMockMiddlewareInit?.Invoke(app);
|
_options.PreWireMockMiddlewareInit?.Invoke(app);
|
||||||
app.Use<WireMockMiddleware>(_options);
|
app.Use<WireMockMiddleware>(_options);
|
||||||
_options.PostWireMockMiddlewareInit?.Invoke(app);
|
_options.PostWireMockMiddlewareInit?.Invoke(app);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using WireMock.Matchers.Request;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
using Newtonsoft.Json;
|
||||||
#if !NETSTANDARD
|
#if !NETSTANDARD
|
||||||
using Microsoft.Owin;
|
using Microsoft.Owin;
|
||||||
#else
|
#else
|
||||||
@@ -124,7 +125,7 @@ namespace WireMock.Owin
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() };
|
response = new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) };
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Util;
|
||||||
#if !NETSTANDARD
|
#if !NETSTANDARD
|
||||||
using Owin;
|
using Owin;
|
||||||
#else
|
#else
|
||||||
@@ -22,7 +23,7 @@ namespace WireMock.Owin
|
|||||||
|
|
||||||
public IList<Mapping> Mappings { get; set; } = new List<Mapping>();
|
public IList<Mapping> Mappings { get; set; } = new List<Mapping>();
|
||||||
|
|
||||||
public ObservableCollection<LogEntry> LogEntries { get; } = new ObservableCollection<LogEntry>();
|
public ObservableCollection<LogEntry> LogEntries { get; } = new ConcurentObservableCollection<LogEntry>();
|
||||||
|
|
||||||
public int? RequestLogExpirationDuration { get; set; }
|
public int? RequestLogExpirationDuration { get; set; }
|
||||||
|
|
||||||
|
|||||||
77
src/WireMock.Net/Util/ConcurentObservableCollection.cs
Normal file
77
src/WireMock.Net/Util/ConcurentObservableCollection.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace WireMock.Util
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A special Collection that overrides methods of <see cref="ObservableCollection{T}"/> to make them thread safe
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of elements in the collection.</typeparam>
|
||||||
|
/// <inheritdoc cref="ObservableCollection{T}" />
|
||||||
|
public class ConcurentObservableCollection<T> : ObservableCollection<T>
|
||||||
|
{
|
||||||
|
private readonly object _lockObject = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:WireMock.Util.ConcurentObservableCollection`1" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public ConcurentObservableCollection() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ConcurentObservableCollection{T}"/> class that contains elements copied from the specified list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="list">The list from which the elements are copied.</param>
|
||||||
|
public ConcurentObservableCollection(List<T> list) : base(list) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ConcurentObservableCollection{T}"/> class that contains elements copied from the specified collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="collection">The collection from which the elements are copied.</param>
|
||||||
|
public ConcurentObservableCollection(IEnumerable<T> collection) : base(collection) { }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ObservableCollection{T}.ClearItems"/>
|
||||||
|
protected override void ClearItems()
|
||||||
|
{
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
base.ClearItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ObservableCollection{T}.RemoveItem"/>
|
||||||
|
protected override void RemoveItem(int index)
|
||||||
|
{
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
base.RemoveItem(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ObservableCollection{T}.InsertItem"/>
|
||||||
|
protected override void InsertItem(int index, T item)
|
||||||
|
{
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
base.InsertItem(index, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ObservableCollection{T}.SetItem"/>
|
||||||
|
protected override void SetItem(int index, T item)
|
||||||
|
{
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
base.SetItem(index, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ObservableCollection{T}.MoveItem"/>
|
||||||
|
protected override void MoveItem(int oldIndex, int newIndex)
|
||||||
|
{
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
base.MoveItem(oldIndex, newIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using NFluent;
|
using NFluent;
|
||||||
using WireMock.RequestBuilders;
|
using WireMock.RequestBuilders;
|
||||||
using WireMock.ResponseBuilders;
|
using WireMock.ResponseBuilders;
|
||||||
@@ -8,7 +13,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace WireMock.Net.Tests
|
namespace WireMock.Net.Tests
|
||||||
{
|
{
|
||||||
public class ObservableLogEntriesTest: IDisposable
|
public class ObservableLogEntriesTest : IDisposable
|
||||||
{
|
{
|
||||||
private FluentMockServer _server;
|
private FluentMockServer _server;
|
||||||
|
|
||||||
@@ -35,6 +40,42 @@ namespace WireMock.Net.Tests
|
|||||||
Check.That(count).Equals(1);
|
Check.That(count).Equals(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ParallelTest()
|
||||||
|
{
|
||||||
|
var expectedCount = 100;
|
||||||
|
|
||||||
|
// Assign
|
||||||
|
_server = FluentMockServer.Start();
|
||||||
|
|
||||||
|
_server
|
||||||
|
.Given(Request.Create()
|
||||||
|
.WithPath("/foo")
|
||||||
|
.UsingGet())
|
||||||
|
.RespondWith(Response.Create()
|
||||||
|
.WithDelay(6)
|
||||||
|
.WithSuccess());
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
_server.LogEntriesChanged += (sender, args) => count++;
|
||||||
|
|
||||||
|
var http = new HttpClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var listOfTasks = new List<Task<HttpResponseMessage>>();
|
||||||
|
for (var i = 0; i < expectedCount; i++)
|
||||||
|
{
|
||||||
|
Thread.Sleep(3);
|
||||||
|
listOfTasks.Add(http.GetAsync(_server.Urls[0] + $"/foo"));
|
||||||
|
}
|
||||||
|
var responses = await Task.WhenAll(listOfTasks);
|
||||||
|
var countResponsesWithStatusNotOk = responses.Where(r => r.StatusCode != HttpStatusCode.OK).Count();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Check.That(countResponsesWithStatusNotOk).Equals(0);
|
||||||
|
Check.That(count).Equals(expectedCount);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_server?.Dispose();
|
_server?.Dispose();
|
||||||
|
|||||||
Reference in New Issue
Block a user