Add log4net logging (#89)

* logging + fixed proxy isses

* Add more logging

* comments

* 1.0.3.1
This commit is contained in:
Stef Heyenrath
2018-02-14 16:13:05 +00:00
committed by GitHub
parent 9778c5adbe
commit e21582aacf
35 changed files with 466 additions and 154 deletions

View File

@@ -1,10 +1,9 @@
using System;
using System.Linq;
using System.Linq;
using WireMock.Server;
using WireMock.Settings;
using WireMock.Validation;
using JetBrains.Annotations;
using Newtonsoft.Json;
using log4net;
namespace WireMock.Net.StandAlone
{
@@ -13,8 +12,10 @@ namespace WireMock.Net.StandAlone
/// </summary>
public static class StandAloneApp
{
private static readonly ILog Log = LogManager.GetLogger(typeof(StandAloneApp));
/// <summary>
/// Start WireMock.Net standalone based on the FluentMockServerSettings.
/// Start WireMock.Net standalone Server based on the FluentMockServerSettings.
/// </summary>
/// <param name="settings">The FluentMockServerSettings</param>
[PublicAPI]
@@ -26,7 +27,7 @@ namespace WireMock.Net.StandAlone
}
/// <summary>
/// Start WireMock.Net standalone based on the commandline arguments.
/// Start WireMock.Net standalone Server based on the commandline arguments.
/// </summary>
/// <param name="args">The commandline arguments</param>
[PublicAPI]
@@ -34,7 +35,7 @@ namespace WireMock.Net.StandAlone
{
Check.NotNull(args, nameof(args));
Console.WriteLine("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
Log.DebugFormat("WireMock.Net server arguments [{0}]", string.Join(", ", args.Select(a => $"'{a}'")));
var parser = new SimpleCommandLineParser();
parser.Parse(args);
@@ -73,11 +74,9 @@ namespace WireMock.Net.StandAlone
};
}
Console.WriteLine("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented));
FluentMockServer server = Start(settings);
Console.WriteLine("WireMock.Net server listening at {0}", string.Join(",", server.Urls));
Log.InfoFormat("WireMock.Net server listening at {0}", string.Join(",", server.Urls));
return server;
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Version>1.0.3</Version>
<Version>1.0.3.1</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -36,10 +36,7 @@
<PackageReference Include="JetBrains.Annotations" Version="10.4.0">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<!-- <PackageReference Include="CommandLineArgumentsParser" Version="3.0.16" /> -->
<!-- <PackageReference Include="Marsonsoft.CommandLineParser" Version="1.0.34" /> -->
<!-- <PackageReference Include="BurnSystems.CommandLine" Version="1.1.0" /> -->
<!-- <ProjectReference Include="..\..\..\CommandLineParser\src\CommandLineArgumentsParser\CommandLineArgumentsParser.csproj" /> -->
<PackageReference Include="log4net" Version="2.0.8" />
</ItemGroup>
<ItemGroup>

View File

@@ -8,51 +8,33 @@ namespace WireMock.Admin.Requests
public class LogEntryModel
{
/// <summary>
/// Gets or sets the unique identifier.
/// </summary>
/// <value>
/// The unique identifier.
/// </value>
/// </summary>
public Guid Guid { get; set; }
/// <summary>
/// Gets or sets the request.
/// </summary>
/// <value>
/// The request.
/// </value>
/// </summary>
public LogRequestModel Request { get; set; }
/// <summary>
/// Gets or sets the response.
/// </summary>
/// <value>
/// The response.
/// </value>
/// </summary>
public LogResponseModel Response { get; set; }
/// <summary>
/// Gets or sets the mapping unique identifier.
/// </summary>
/// <value>
/// The mapping unique identifier.
/// </value>
/// </summary>
public Guid? MappingGuid { get; set; }
/// <summary>
/// Gets or sets the mapping unique title.
/// </summary>
/// <value>
/// The mapping unique title.
/// </value>
/// </summary>
public string MappingTitle { get; set; }
/// <summary>
/// Gets or sets the request match result.
/// </summary>
/// <value>
/// The request match result.
/// </value>
/// </summary>
public LogRequestMatchModel RequestMatchResult { get; set; }
}
}

View File

@@ -11,52 +11,62 @@ namespace WireMock.Admin.Requests
public class LogRequestModel
{
/// <summary>
/// Gets the Client IP Address.
/// The Client IP Address.
/// </summary>
public string ClientIP { get; set; }
/// <summary>
/// Gets the DateTime.
/// The DateTime.
/// </summary>
public DateTime DateTime { get; set; }
/// <summary>
/// Gets or sets the Path.
/// The Path.
/// </summary>
public string Path { get; set; }
/// <summary>
/// Gets or sets the absolete URL.
///The absolete URL.
/// </summary>
public string AbsoluteUrl { get; set; }
/// <summary>
/// Gets the query.
/// The query.
/// </summary>
public IDictionary<string, WireMockList<string>> Query { get; set; }
/// <summary>
/// Gets or sets the method.
/// The method.
/// </summary>
public string Method { get; set; }
/// <summary>
/// Gets or sets the Headers.
/// The Headers.
/// </summary>
public IDictionary<string, WireMockList<string>> Headers { get; set; }
/// <summary>
/// Gets or sets the Cookies.
/// Tthe Cookies.
/// </summary>
public IDictionary<string, string> Cookies { get; set; }
/// <summary>
/// Gets or sets the body.
/// The body (as string).
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the body encoding.
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// The body encoding.
/// </summary>
public EncodingModel BodyEncoding { get; set; }
}

View File

@@ -25,12 +25,17 @@ namespace WireMock.Admin.Requests
public string BodyDestination { get; set; }
/// <summary>
/// Gets or sets the body.
/// The body (as string).
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the body as bytes.
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }

View File

@@ -4,8 +4,10 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using WireMock.HttpsCertificate;
using WireMock.Util;
using WireMock.Validation;
namespace WireMock.Http
@@ -51,20 +53,36 @@ namespace WireMock.Http
return client;
}
public static async Task<ResponseMessage> SendAsync(HttpClient client, RequestMessage requestMessage, string url)
public static async Task<ResponseMessage> SendAsync([NotNull] HttpClient client, [NotNull] RequestMessage requestMessage, string url)
{
Check.NotNull(client, nameof(client));
Check.NotNull(requestMessage, nameof(requestMessage));
var originalUri = new Uri(requestMessage.Url);
var requiredUri = new Uri(url);
var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url);
WireMockList<string> contentTypeHeader = null;
bool contentTypeHeaderPresent = requestMessage.Headers.Any(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase));
if (contentTypeHeaderPresent)
{
contentTypeHeader = requestMessage.Headers[HttpKnownHeaderNames.ContentType];
}
// Set Body if present
if (requestMessage.BodyAsBytes != null)
{
httpRequestMessage.Content = new ByteArrayContent(requestMessage.BodyAsBytes);
}
else if (requestMessage.BodyAsJson != null)
{
httpRequestMessage.Content = new StringContent(JsonConvert.SerializeObject(requestMessage.BodyAsJson), requestMessage.BodyEncoding);
}
else if (requestMessage.Body != null)
{
httpRequestMessage.Content = new StringContent(requestMessage.Body, requestMessage.BodyEncoding);
}
// Overwrite the host header
httpRequestMessage.Headers.Host = requiredUri.Authority;
@@ -90,10 +108,13 @@ namespace WireMock.Http
// Set both content and response headers, replacing URLs in values
var headers = (httpResponseMessage.Content?.Headers.Union(httpResponseMessage.Headers) ?? Enumerable.Empty<KeyValuePair<string, IEnumerable<string>>>()).ToArray();
var contentTypeHeader = headers.FirstOrDefault(header => string.Equals(header.Key, HttpKnownHeaderNames.ContentType, StringComparison.OrdinalIgnoreCase));
if (httpResponseMessage.Content != null)
{
SetBody(httpResponseMessage.Content, contentTypeHeader, responseMessage);
var stream = await httpResponseMessage.Content.ReadAsStreamAsync();
var body = await BodyParser.Parse(stream, contentTypeHeader?.FirstOrDefault());
responseMessage.Body = body.BodyAsString;
responseMessage.BodyAsJson = body.BodyAsJson;
responseMessage.BodyAsBytes = body.BodyAsBytes;
}
foreach (var header in headers)
@@ -115,41 +136,5 @@ namespace WireMock.Http
return responseMessage;
}
private static async void SetBody(HttpContent content, KeyValuePair<string, IEnumerable<string>> contentTypeHeader, ResponseMessage responseMessage)
{
bool contentTypeIsDefault = contentTypeHeader.Equals(default(KeyValuePair<string, IEnumerable<string>>));
string[] textContentTypes = { "text/", "application/xml", "application/javascript", "application/typescript", "application/xhtml+xml" };
if (!contentTypeIsDefault && contentTypeHeader.Value.Any(value => textContentTypes.Any(t => value != null && value.StartsWith(t, StringComparison.OrdinalIgnoreCase))))
{
try
{
responseMessage.Body = await content.ReadAsStringAsync();
}
catch
{
// Reading as string failed, just get the ByteArray.
responseMessage.BodyAsBytes = await content.ReadAsByteArrayAsync();
}
}
else if (!contentTypeIsDefault && contentTypeHeader.Value.Any(value => value != null && value.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)))
{
string stringContent = await content.ReadAsStringAsync();
try
{
responseMessage.BodyAsJson = JsonConvert.DeserializeObject(stringContent, new JsonSerializerSettings { Formatting = Formatting.Indented });
}
catch
{
// JsonConvert failed, just set the Body as string.
responseMessage.Body = stringContent;
}
}
else
{
responseMessage.BodyAsBytes = await content.ReadAsByteArrayAsync();
}
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using log4net;
using Newtonsoft.Json;
#if !NETSTANDARD
using Microsoft.Owin;
@@ -15,6 +16,7 @@ namespace WireMock.Owin
internal class GlobalExceptionMiddleware
#endif
{
private static readonly ILog Log = LogManager.GetLogger(typeof(GlobalExceptionMiddleware));
#if !NETSTANDARD
public GlobalExceptionMiddleware(OwinMiddleware next) : base(next) { }
#else
@@ -42,6 +44,7 @@ namespace WireMock.Owin
}
catch (Exception ex)
{
Log.Error("HttpStatusCode set to 500", ex);
await _responseMapper.MapAsync(new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) }, ctx.Response);
}
}

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WireMock.Util;
#if !NETSTANDARD
using Microsoft.Owin;
#else
@@ -16,7 +17,7 @@ namespace WireMock.Owin
/// <summary>
/// OwinRequestMapper
/// </summary>
public class OwinRequestMapper
internal class OwinRequestMapper
{
/// <summary>
/// MapAsync IOwinRequest to RequestMessage
@@ -43,20 +44,6 @@ namespace WireMock.Owin
#endif
string method = request.Method;
string bodyAsString = null;
byte[] body = null;
Encoding bodyEncoding = null;
if (ParseBody(method) && request.Body != null)
{
using (var streamReader = new StreamReader(request.Body))
{
bodyAsString = await streamReader.ReadToEndAsync();
bodyEncoding = streamReader.CurrentEncoding;
}
body = bodyEncoding.GetBytes(bodyAsString);
}
Dictionary<string, string[]> headers = null;
if (request.Headers.Any())
{
@@ -77,10 +64,16 @@ namespace WireMock.Owin
}
}
return new RequestMessage(url, method, clientIP, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now };
BodyData body = null;
if (request.Body != null && ShouldParseBody(method))
{
body = await BodyParser.Parse(request.Body, request.ContentType);
}
return new RequestMessage(url, method, clientIP, body, headers, cookies) { DateTime = DateTime.Now };
}
private bool ParseBody(string method)
private bool ShouldParseBody(string method)
{
/*
HEAD - No defined body semantics.

View File

@@ -3,9 +3,11 @@ using System.Threading.Tasks;
using WireMock.Logging;
using WireMock.Matchers.Request;
using System.Linq;
using log4net;
using WireMock.Matchers;
using WireMock.Util;
using Newtonsoft.Json;
using WireMock.Http;
#if !NETSTANDARD
using Microsoft.Owin;
#else
@@ -20,6 +22,7 @@ namespace WireMock.Owin
internal class WireMockMiddleware
#endif
{
private static readonly ILog Log = LogManager.GetLogger(typeof(WireMockMiddleware));
private static readonly Task CompletedTask = Task.FromResult(false);
private readonly WireMockMiddlewareOptions _options;
@@ -95,6 +98,7 @@ namespace WireMock.Owin
if (targetMapping == null)
{
logRequest = true;
Log.Warn("HttpStatusCode set to 404 : No matching mapping found");
response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" };
return;
}
@@ -103,9 +107,10 @@ namespace WireMock.Owin
if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null)
{
bool present = request.Headers.TryGetValue("Authorization", out WireMockList<string> authorization);
bool present = request.Headers.TryGetValue(HttpKnownHeaderNames.Authorization, out WireMockList<string> authorization);
if (!present || _options.AuthorizationMatcher.IsMatch(authorization.ToString()) < MatchScores.Perfect)
{
Log.Error("HttpStatusCode set to 401");
response = new ResponseMessage { StatusCode = 401 };
return;
}
@@ -125,6 +130,7 @@ namespace WireMock.Owin
}
catch (Exception ex)
{
Log.Error("HttpStatusCode set to 500", ex);
response = new ResponseMessage { StatusCode = 500, Body = JsonConvert.SerializeObject(ex) };
}
finally

View File

@@ -60,15 +60,20 @@ namespace WireMock
public string RawQuery { get; }
/// <summary>
/// Gets the bodyAsBytes.
/// </summary>
public byte[] BodyAsBytes { get; }
/// <summary>
/// Gets the body.
/// The body as string.
/// </summary>
public string Body { get; }
/// <summary>
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
/// <summary>
/// Gets the Host
/// </summary>
@@ -90,10 +95,45 @@ namespace WireMock
public string Origin { get; }
/// <summary>
/// Gets the body encoding.
/// The body encoding.
/// </summary>
public Encoding BodyEncoding { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
/// </summary>
/// <param name="url">The original url.</param>
/// <param name="method">The HTTP method.</param>
/// <param name="clientIP">The client IP Address.</param>
/// <param name="body">The body.</param>
/// <param name="headers">The headers.</param>
/// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] BodyData body, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
{
Check.NotNull(url, nameof(url));
Check.NotNull(method, nameof(method));
Check.NotNull(clientIP, nameof(clientIP));
Url = url.ToString();
Protocol = url.Scheme;
Host = url.Host;
Port = url.Port;
Origin = $"{url.Scheme}://{url.Host}:{url.Port}";
Path = WebUtility.UrlDecode(url.AbsolutePath);
Method = method.ToLower();
ClientIP = clientIP;
Body = body?.BodyAsString;
BodyEncoding = body?.Encoding;
BodyAsJson = body?.BodyAsJson;
BodyAsBytes = body?.BodyAsBytes;
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
Cookies = cookies;
RawQuery = WebUtility.UrlDecode(url.Query);
Query = ParseQuery(RawQuery);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
/// </summary>

View File

@@ -247,16 +247,9 @@ namespace WireMock.ResponseBuilders
{
Check.NotNull(body, nameof(body));
string jsonBody = JsonConvert.SerializeObject(body, new JsonSerializerSettings { Formatting = Formatting.None, NullValueHandling = NullValueHandling.Ignore });
if (encoding != null && !encoding.Equals(Encoding.UTF8))
{
jsonBody = encoding.GetString(Encoding.UTF8.GetBytes(jsonBody));
ResponseMessage.BodyEncoding = encoding;
}
ResponseMessage.BodyDestination = null;
ResponseMessage.Body = jsonBody;
ResponseMessage.BodyAsJson = body;
ResponseMessage.BodyEncoding = encoding;
return this;
}

View File

@@ -7,6 +7,7 @@ using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Admin.Mappings;
using WireMock.Admin.Requests;
using WireMock.Admin.Settings;
@@ -112,6 +113,7 @@ namespace WireMock.Server
foreach (string filename in Directory.EnumerateFiles(folder).OrderBy(f => f))
{
Log.InfoFormat("Reading Static MappingFile : '{0}'", filename);
ReadStaticMappingAndAddOrUpdate(filename);
}
}
@@ -133,17 +135,22 @@ namespace WireMock.Server
return;
}
var watcher = new EnhancedFileSystemWatcher(folder, "*.json", 500);
Log.InfoFormat("Watching folder '{0}' for new, updated and deleted MappingFiles.", folder);
var watcher = new EnhancedFileSystemWatcher(folder, "*.json", 1000);
watcher.Created += (sender, args) =>
{
Log.InfoFormat("New MappingFile created : '{0}'", args.FullPath);
ReadStaticMappingAndAddOrUpdate(args.FullPath);
};
watcher.Changed += (sender, args) =>
{
Log.InfoFormat("New MappingFile updated : '{0}'", args.FullPath);
ReadStaticMappingAndAddOrUpdate(args.FullPath);
};
watcher.Deleted += (sender, args) =>
{
Log.InfoFormat("New MappingFile deleted : '{0}'", args.FullPath);
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(args.FullPath);
if (Guid.TryParse(filenameWithoutExtension, out Guid guidFromFilename))
@@ -170,13 +177,14 @@ namespace WireMock.Server
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(path);
MappingModel mappingModel = JsonConvert.DeserializeObject<MappingModel>(FileHelper.ReadAllText(path));
if (Guid.TryParse(filenameWithoutExtension, out Guid guidFromFilename))
{
DeserializeAndAddOrUpdateMapping(FileHelper.ReadAllText(path), guidFromFilename, path);
DeserializeAndAddOrUpdateMapping(mappingModel, guidFromFilename, path);
}
else
{
DeserializeAndAddOrUpdateMapping(FileHelper.ReadAllText(path), null, path);
DeserializeAndAddOrUpdateMapping(mappingModel, null, path);
}
}
#endregion
@@ -256,7 +264,7 @@ namespace WireMock.Server
private ResponseMessage SettingsUpdate(RequestMessage requestMessage)
{
var settings = JsonConvert.DeserializeObject<SettingsModel>(requestMessage.Body);
var settings = requestMessage.Body != null ? JsonConvert.DeserializeObject<SettingsModel>(requestMessage.Body) : ((JObject)requestMessage.BodyAsJson).ToObject<SettingsModel>();
if (settings.AllowPartialMapping != null)
_options.AllowPartialMapping = settings.AllowPartialMapping.Value;
@@ -280,6 +288,7 @@ namespace WireMock.Server
if (mapping == null)
{
Log.Warn("HttpStatusCode set to 404 : Mapping not found");
return new ResponseMessage { StatusCode = 404, Body = "Mapping not found" };
}
@@ -292,7 +301,8 @@ namespace WireMock.Server
{
Guid guid = Guid.Parse(requestMessage.Path.TrimStart(AdminMappings.ToCharArray()));
DeserializeAndAddOrUpdateMapping(requestMessage.Body, guid);
MappingModel mappingModel = requestMessage.Body != null ? JsonConvert.DeserializeObject<MappingModel>(requestMessage.Body) : ((JObject)requestMessage.BodyAsJson).ToObject<MappingModel>();
DeserializeAndAddOrUpdateMapping(mappingModel, guid);
return new ResponseMessage { Body = "Mapping added or updated" };
}
@@ -330,10 +340,12 @@ namespace WireMock.Server
}
var model = MappingConverter.ToMappingModel(mapping);
string json = JsonConvert.SerializeObject(model, _settings);
string filename = !string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString();
File.WriteAllText(Path.Combine(folder, filename + ".json"), json);
string filePath = Path.Combine(folder, filename + ".json");
Log.InfoFormat("Saving Mapping to file {0}", filePath);
File.WriteAllText(filePath, JsonConvert.SerializeObject(model, _settings));
}
private static string SanitizeFileName(string name, char replaceChar = '_')
@@ -357,24 +369,25 @@ namespace WireMock.Server
{
try
{
DeserializeAndAddOrUpdateMapping(requestMessage.Body);
MappingModel mappingModel = requestMessage.Body != null ? JsonConvert.DeserializeObject<MappingModel>(requestMessage.Body) : ((JObject)requestMessage.BodyAsJson).ToObject<MappingModel>();
DeserializeAndAddOrUpdateMapping(mappingModel);
}
catch (ArgumentException a)
{
Log.Error("HttpStatusCode set to 400", a);
return new ResponseMessage { StatusCode = 400, Body = a.Message };
}
catch (Exception e)
{
Log.Error("HttpStatusCode set to 500", e);
return new ResponseMessage { StatusCode = 500, Body = e.ToString() };
}
return new ResponseMessage { StatusCode = 201, Body = "Mapping added" };
}
private void DeserializeAndAddOrUpdateMapping(string json, Guid? guid = null, string path = null)
private void DeserializeAndAddOrUpdateMapping(MappingModel mappingModel, Guid? guid = null, string path = null)
{
var mappingModel = JsonConvert.DeserializeObject<MappingModel>(json);
Check.NotNull(mappingModel, nameof(mappingModel));
Check.NotNull(mappingModel.Request, nameof(mappingModel.Request));
Check.NotNull(mappingModel.Response, nameof(mappingModel.Response));
@@ -435,7 +448,10 @@ namespace WireMock.Server
var entry = LogEntries.FirstOrDefault(r => !r.RequestMessage.Path.StartsWith("/__admin/") && r.Guid == guid);
if (entry == null)
return new ResponseMessage { StatusCode = 404, Body = "Request not found" };
{
Log.Warn("HttpStatusCode set to 404 : Request not found");
return new ResponseMessage {StatusCode = 404, Body = "Request not found"};
}
var model = ToLogEntryModel(entry);
@@ -477,6 +493,8 @@ namespace WireMock.Server
Query = logEntry.RequestMessage.Query,
Method = logEntry.RequestMessage.Method,
Body = logEntry.RequestMessage.Body,
BodyAsJson = logEntry.RequestMessage.BodyAsJson,
BodyAsBytes = logEntry.RequestMessage.BodyAsBytes,
Headers = logEntry.RequestMessage.Headers,
Cookies = logEntry.RequestMessage.Cookies,
BodyEncoding = logEntry.RequestMessage.BodyEncoding != null ? new EncodingModel
@@ -491,6 +509,7 @@ namespace WireMock.Server
StatusCode = logEntry.ResponseMessage.StatusCode,
BodyDestination = logEntry.ResponseMessage.BodyDestination,
Body = logEntry.ResponseMessage.Body,
BodyAsJson = logEntry.ResponseMessage.BodyAsJson,
BodyAsBytes = logEntry.ResponseMessage.BodyAsBytes,
BodyOriginal = logEntry.ResponseMessage.BodyOriginal,
BodyAsFile = logEntry.ResponseMessage.BodyAsFile,
@@ -531,7 +550,7 @@ namespace WireMock.Server
#region Requests/find
private ResponseMessage RequestsFind(RequestMessage requestMessage)
{
var requestModel = JsonConvert.DeserializeObject<RequestModel>(requestMessage.Body);
var requestModel = requestMessage.Body != null ? JsonConvert.DeserializeObject<RequestModel>(requestMessage.Body) : ((JObject)requestMessage.BodyAsJson).ToObject<RequestModel>();
var request = (Request)InitRequestBuilder(requestModel);

View File

@@ -6,6 +6,8 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using log4net;
using Newtonsoft.Json;
using WireMock.Http;
using WireMock.Matchers;
using WireMock.Matchers.Request;
@@ -13,7 +15,6 @@ using WireMock.RequestBuilders;
using WireMock.Settings;
using WireMock.Validation;
using WireMock.Owin;
using WireMock.Serialization;
namespace WireMock.Server
{
@@ -22,6 +23,7 @@ namespace WireMock.Server
/// </summary>
public partial class FluentMockServer : IDisposable
{
private static readonly ILog Log = LogManager.GetLogger(typeof(FluentMockServer));
private const int ServerStartDelay = 100;
private readonly IOwinSelfHost _httpServer;
private readonly WireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
@@ -156,6 +158,8 @@ namespace WireMock.Server
private FluentMockServer(IFluentMockServerSettings settings)
{
Log.DebugFormat("WireMock.Net server settings {0}", JsonConvert.SerializeObject(settings, Formatting.Indented));
if (settings.Urls != null)
{
Urls = settings.Urls.Select(u => u.EndsWith("/") ? u : $"{u}/").ToArray();
@@ -315,9 +319,10 @@ namespace WireMock.Server
/// Allows the partial mapping.
/// </summary>
[PublicAPI]
public void AllowPartialMapping()
public void AllowPartialMapping(bool allow = true)
{
_options.AllowPartialMapping = true;
Log.InfoFormat("AllowPartialMapping is set to {0}", allow);
_options.AllowPartialMapping = allow;
}
/// <summary>

View File

@@ -1,5 +1,6 @@
using System;
using JetBrains.Annotations;
using Newtonsoft.Json;
namespace WireMock.Settings
{
@@ -63,10 +64,12 @@ namespace WireMock.Settings
/// <inheritdoc cref="IFluentMockServerSettings.PreWireMockMiddlewareInit"/>
[PublicAPI]
[JsonIgnore]
public Action<object> PreWireMockMiddlewareInit { get; set; }
/// <inheritdoc cref="IFluentMockServerSettings.PostWireMockMiddlewareInit"/>
[PublicAPI]
[JsonIgnore]
public Action<object> PostWireMockMiddlewareInit { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
using System.Text;
namespace WireMock.Util
{
/// <summary>
/// BodyData
/// </summary>
public class BodyData
{
/// <summary>
/// The body encoding.
/// </summary>
public Encoding Encoding { get; set; }
/// <summary>
/// The body as string.
/// </summary>
public string BodyAsString { get; set; }
/// <summary>
/// The body (as JSON object).
/// </summary>
public object BodyAsJson { get; set; }
/// <summary>
/// The body (as bytearray).
/// </summary>
public byte[] BodyAsBytes { get; set; }
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
namespace WireMock.Util
{
internal static class BodyParser
{
private static readonly string[] TextContentTypes = { "text/", "application/xml", "application/javascript", "application/typescript", "application/xhtml+xml" };
private static async Task<Tuple<string, Encoding>> ReadStringAsync(Stream stream)
{
using (var streamReader = new StreamReader(stream))
{
string content = await streamReader.ReadToEndAsync();
return new Tuple<string, Encoding>(content, streamReader.CurrentEncoding);
}
}
private static async Task<byte[]> ReadBytesAsync(Stream stream)
{
using (var memoryStream = new MemoryStream())
{
await stream.CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
}
public static async Task<BodyData> Parse([NotNull] Stream stream, [CanBeNull] string contentTypeHeaderValue)
{
var data = new BodyData();
if (contentTypeHeaderValue != null && TextContentTypes.Any(t => contentTypeHeaderValue.StartsWith(t, StringComparison.OrdinalIgnoreCase)))
{
try
{
var stringData = await ReadStringAsync(stream);
data.BodyAsString = stringData.Item1;
data.Encoding = stringData.Item2;
}
catch
{
// Reading as string failed, just get the ByteArray.
data.BodyAsBytes = await ReadBytesAsync(stream);
}
}
else if (contentTypeHeaderValue != null && contentTypeHeaderValue.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
var stringData = await ReadStringAsync(stream);
data.Encoding = stringData.Item2;
try
{
data.BodyAsJson = JsonConvert.DeserializeObject(stringData.Item1, new JsonSerializerSettings { Formatting = Formatting.Indented });
}
catch
{
// JsonConvert failed, just set the Body as string.
data.BodyAsString = stringData.Item1;
}
}
else
{
data.BodyAsBytes = await ReadBytesAsync(stream);
}
return data;
}
}
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
<AssemblyTitle>WireMock.Net</AssemblyTitle>
<Version>1.0.3</Version>
<Version>1.0.3.1</Version>
<Authors>Alexandre Victoor;Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -32,6 +32,10 @@
<DefineConstants>NETSTANDARD</DefineConstants>
</PropertyGroup>
<ItemGroup>
<None Remove="Server\FluentMockServer.cs~RF44936b9f.TMP" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="11.1.0">
<PrivateAssets>All</PrivateAssets>
@@ -41,7 +45,7 @@
<PackageReference Include="SimMetrics.Net" Version="1.0.4" />
<PackageReference Include="System.Net.Http" Version="4.3.3" />
<PackageReference Include="RestEase" Version="1.4.4" />
<!--<PackageReference Include="OpenSSL.X509Certificate2.Provider" Version="1.0.2" />-->
<PackageReference Include="log4net" Version="2.0.8" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">