diff --git a/examples/WireMock.Net.WebApplication/WireMockService.cs b/examples/WireMock.Net.WebApplication/WireMockService.cs
index 486f25b0..4aa28e14 100644
--- a/examples/WireMock.Net.WebApplication/WireMockService.cs
+++ b/examples/WireMock.Net.WebApplication/WireMockService.cs
@@ -1,8 +1,9 @@
-using System.Threading;
+using System;
+using System.Threading;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
+using WireMock.Admin.Requests;
using WireMock.Logging;
-using WireMock.Models.Requests;
using WireMock.Server;
using WireMock.Settings;
@@ -49,6 +50,11 @@ namespace WireMock.Net.WebApplication
string message = JsonConvert.SerializeObject(logEntryModel, Formatting.Indented);
_logger.LogDebug("Admin[{0}] {1}", isAdminrequest, message);
}
+
+ public void Error(string formatString, Exception exception)
+ {
+ _logger.LogError(formatString, exception.Message);
+ }
}
public WireMockService(ILogger logger, WireMockServerSettings settings)
diff --git a/src/WireMock.Net.Abstractions/IRequestMessage.cs b/src/WireMock.Net.Abstractions/IRequestMessage.cs
new file mode 100644
index 00000000..99281257
--- /dev/null
+++ b/src/WireMock.Net.Abstractions/IRequestMessage.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections.Generic;
+using WireMock.Types;
+using WireMock.Util;
+
+namespace WireMock
+{
+ ///
+ /// IRequestMessage
+ ///
+ public interface IRequestMessage
+ {
+ ///
+ /// Gets the Client IP Address.
+ ///
+ string ClientIP { get; }
+
+ ///
+ /// Gets the url (relative).
+ ///
+ string Url { get; }
+
+ ///
+ /// Gets the AbsoluteUrl.
+ ///
+ string AbsoluteUrl { get; }
+
+ ///
+ /// The ProxyUrl (if a proxy is used).
+ ///
+ string ProxyUrl { get; }
+
+ ///
+ /// Gets the DateTime.
+ ///
+ DateTime DateTime { get; }
+
+ ///
+ /// Gets the path (relative).
+ ///
+ string Path { get; }
+
+ ///
+ /// Gets the AbsolutePath.
+ ///
+ string AbsolutePath { get; }
+
+ ///
+ /// Gets the path segments.
+ ///
+ string[] PathSegments { get; }
+
+ ///
+ /// Gets the absolute path segments.
+ ///
+ string[] AbsolutePathSegments { get; }
+
+ ///
+ /// Gets the method.
+ ///
+ string Method { get; }
+
+ ///
+ /// Gets the headers.
+ ///
+ IDictionary> Headers { get; }
+
+ ///
+ /// Gets the cookies.
+ ///
+ IDictionary Cookies { get; }
+
+ ///
+ /// Gets the query.
+ ///
+ IDictionary> Query { get; }
+
+ ///
+ /// Gets the raw query.
+ ///
+ string RawQuery { get; }
+
+ ///
+ /// The body.
+ ///
+ IBodyData BodyData { get; }
+
+ ///
+ /// The original body as string. Convenience getter for Handlebars.
+ ///
+ string Body { get; }
+
+ ///
+ /// The body (as JSON object). Convenience getter for Handlebars.
+ ///
+ object BodyAsJson { get; }
+
+ ///
+ /// The body (as bytearray). Convenience getter for Handlebars.
+ ///
+ byte[] BodyAsBytes { get; }
+
+ ///
+ /// The detected body type. Convenience getter for Handlebars.
+ ///
+ string DetectedBodyType { get; }
+
+ ///
+ /// The detected body type from the Content-Type header. Convenience getter for Handlebars.
+ ///
+ string DetectedBodyTypeFromContentType { get; }
+
+ ///
+ /// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
+ ///
+ string DetectedCompression { get; }
+
+ ///
+ /// Gets the Host
+ ///
+ string Host { get; }
+
+ ///
+ /// Gets the protocol
+ ///
+ string Protocol { get; }
+
+ ///
+ /// Gets the port
+ ///
+ int Port { get; }
+
+ ///
+ /// Gets the origin
+ ///
+ string Origin { get; }
+
+ // WireMockList GetParameter(string key, bool ignoreCase = false);
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/IResponseMessage.cs b/src/WireMock.Net.Abstractions/IResponseMessage.cs
new file mode 100644
index 00000000..ebfd4b0b
--- /dev/null
+++ b/src/WireMock.Net.Abstractions/IResponseMessage.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using WireMock.ResponseBuilders;
+using WireMock.Types;
+using WireMock.Util;
+
+namespace WireMock
+{
+ ///
+ /// IResponseMessage
+ ///
+ public interface IResponseMessage
+ {
+ ///
+ /// The Body.
+ ///
+ IBodyData BodyData { get; }
+
+ ///
+ /// Gets the body destination (SameAsSource, String or Bytes).
+ ///
+ string BodyDestination { get; }
+
+ ///
+ /// Gets or sets the body.
+ ///
+ string BodyOriginal { get; }
+
+ ///
+ /// Gets the Fault percentage.
+ ///
+ double? FaultPercentage { get; }
+
+ ///
+ /// The FaultType.
+ ///
+ FaultType FaultType { get; }
+
+ ///
+ /// Gets the headers.
+ ///
+ IDictionary> Headers { get; }
+
+ ///
+ /// Gets or sets the status code.
+ ///
+ object StatusCode { get; }
+
+ //void AddHeader(string name, params string[] values);
+ //void AddHeader(string name, string value);
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Logging/ILogEntry.cs b/src/WireMock.Net.Abstractions/Logging/ILogEntry.cs
new file mode 100644
index 00000000..b6d17704
--- /dev/null
+++ b/src/WireMock.Net.Abstractions/Logging/ILogEntry.cs
@@ -0,0 +1,80 @@
+using System;
+using WireMock.Matchers.Request;
+
+namespace WireMock.Logging
+{
+ public interface ILogEntry
+ {
+ ///
+ /// Gets the unique identifier.
+ ///
+ ///
+ /// The unique identifier.
+ ///
+ Guid Guid { get; }
+
+ ///
+ /// Gets the mapping unique identifier.
+ ///
+ ///
+ /// The mapping unique identifier.
+ ///
+ Guid? MappingGuid { get; }
+
+ ///
+ /// Gets the mapping unique title.
+ ///
+ ///
+ /// The mapping unique title.
+ ///
+ string MappingTitle { get; }
+
+ ///
+ /// Gets the partial mapping unique identifier.
+ ///
+ ///
+ /// The mapping unique identifier.
+ ///
+ Guid? PartialMappingGuid { get; }
+
+ ///
+ /// Gets the partial mapping unique title.
+ ///
+ ///
+ /// The mapping unique title.
+ ///
+ string PartialMappingTitle { get; }
+
+ ///
+ /// Gets the partial match result.
+ ///
+ ///
+ /// The request match result.
+ ///
+ IRequestMatchResult PartialMatchResult { get; }
+
+ ///
+ /// Gets the request match result.
+ ///
+ ///
+ /// The request match result.
+ ///
+ IRequestMatchResult RequestMatchResult { get; }
+
+ ///
+ /// Gets the request message.
+ ///
+ ///
+ /// The request message.
+ ///
+ IRequestMessage RequestMessage { get; }
+
+ ///
+ /// Gets the response message.
+ ///
+ ///
+ /// The response message.
+ ///
+ IResponseMessage ResponseMessage { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatchResult.cs b/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatchResult.cs
new file mode 100644
index 00000000..f38e733f
--- /dev/null
+++ b/src/WireMock.Net.Abstractions/Matchers/Request/IRequestMatchResult.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+
+namespace WireMock.Matchers.Request
+{
+ ///
+ /// IRequestMatchResult
+ ///
+ public interface IRequestMatchResult : IComparable
+ {
+ ///
+ /// Gets the match percentage.
+ ///
+ ///
+ /// The match percentage.
+ ///
+ double AverageTotalScore { get; }
+
+ ///
+ /// Gets or sets a value indicating whether this instance is perfect match.
+ ///
+ ///
+ /// true if this instance is perfect match; otherwise, false.
+ ///
+ bool IsPerfectMatch { get; }
+
+ ///
+ /// Gets the match details.
+ ///
+ IList MatchDetails { get; }
+
+ ///
+ /// Gets or sets the total number of matches.
+ ///
+ ///
+ /// The total number of matches.
+ ///
+ int TotalNumber { get; }
+
+ ///
+ /// Gets or sets the match-score.
+ ///
+ ///
+ /// The match-score.
+ ///
+ double TotalScore { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/Request/MatchDetail.cs b/src/WireMock.Net.Abstractions/Matchers/Request/MatchDetail.cs
similarity index 100%
rename from src/WireMock.Net/Matchers/Request/MatchDetail.cs
rename to src/WireMock.Net.Abstractions/Matchers/Request/MatchDetail.cs
diff --git a/src/WireMock.Net/ResponseBuilders/FaultType.cs b/src/WireMock.Net.Abstractions/ResponseBuilders/FaultType.cs
similarity index 100%
rename from src/WireMock.Net/ResponseBuilders/FaultType.cs
rename to src/WireMock.Net.Abstractions/ResponseBuilders/FaultType.cs
diff --git a/src/WireMock.Net.Abstractions/Server/IWireMockServer.cs b/src/WireMock.Net.Abstractions/Server/IWireMockServer.cs
index fe24f15e..ca822beb 100644
--- a/src/WireMock.Net.Abstractions/Server/IWireMockServer.cs
+++ b/src/WireMock.Net.Abstractions/Server/IWireMockServer.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using JetBrains.Annotations;
using WireMock.Admin.Mappings;
+using WireMock.Logging;
namespace WireMock.Server
{
@@ -16,13 +17,20 @@ namespace WireMock.Server
///
bool IsStarted { get; }
- //IEnumerable LogEntries { get; }
+ ///
+ /// Gets the request logs.
+ ///
+ IEnumerable LogEntries { get; }
///
/// Gets the mappings as MappingModels.
///
IEnumerable MappingModels { get; }
+ ///
+ /// Gets the mappings.
+ ///
+ //[PublicAPI]
//IEnumerable Mappings { get; }
///
diff --git a/src/WireMock.Net.Abstractions/Util/IBodyData.cs b/src/WireMock.Net.Abstractions/Util/IBodyData.cs
new file mode 100644
index 00000000..e9223df4
--- /dev/null
+++ b/src/WireMock.Net.Abstractions/Util/IBodyData.cs
@@ -0,0 +1,61 @@
+using System.Text;
+using WireMock.Types;
+
+namespace WireMock.Util
+{
+ ///
+ /// IBodyData
+ ///
+ public interface IBodyData
+ {
+ ///
+ /// The body (as bytearray).
+ ///
+ byte[] BodyAsBytes { get; set; }
+
+ ///
+ /// Gets or sets the body as a file.
+ ///
+ string BodyAsFile { get; set; }
+
+ ///
+ /// Is the body as file cached?
+ ///
+ bool? BodyAsFileIsCached { get; set; }
+
+ ///
+ /// The body (as JSON object).
+ ///
+ object BodyAsJson { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings.
+ ///
+ bool? BodyAsJsonIndented { get; set; }
+
+ ///
+ /// The body as string, this is defined when BodyAsString or BodyAsJson are not null.
+ ///
+ string BodyAsString { get; set; }
+
+ ///
+ /// The detected body type (detection based on body content).
+ ///
+ BodyType DetectedBodyType { get; set; }
+
+ ///
+ /// The detected body type (detection based on Content-Type).
+ ///
+ BodyType DetectedBodyTypeFromContentType { get; set; }
+
+ ///
+ /// The detected compression.
+ ///
+ string DetectedCompression { get; set; }
+
+ ///
+ /// The body encoding.
+ ///
+ Encoding Encoding { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockANumberOfCallsAssertions.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockANumberOfCallsAssertions.cs
index aff156e4..f830be07 100644
--- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockANumberOfCallsAssertions.cs
+++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockANumberOfCallsAssertions.cs
@@ -5,10 +5,10 @@ namespace WireMock.FluentAssertions
{
public class WireMockANumberOfCallsAssertions
{
- private readonly WireMockServer _server;
+ private readonly IWireMockServer _server;
private readonly int _callsCount;
- public WireMockANumberOfCallsAssertions(WireMockServer server, int callsCount)
+ public WireMockANumberOfCallsAssertions(IWireMockServer server, int callsCount)
{
_server = server;
_callsCount = callsCount;
diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs
index 41f89b66..52f8b12d 100644
--- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs
+++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs
@@ -8,9 +8,9 @@ namespace WireMock.FluentAssertions
{
public class WireMockAssertions
{
- private readonly WireMockServer _instance;
+ private readonly IWireMockServer _instance;
- public WireMockAssertions(WireMockServer instance, int? callsCount)
+ public WireMockAssertions(IWireMockServer instance, int? callsCount)
{
_instance = instance;
}
diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockReceivedAssertions.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockReceivedAssertions.cs
index 1728a895..0eba33b7 100644
--- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockReceivedAssertions.cs
+++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockReceivedAssertions.cs
@@ -4,9 +4,9 @@ using WireMock.Server;
// ReSharper disable once CheckNamespace
namespace WireMock.FluentAssertions
{
- public class WireMockReceivedAssertions : ReferenceTypeAssertions
+ public class WireMockReceivedAssertions : ReferenceTypeAssertions
{
- public WireMockReceivedAssertions(WireMockServer server)
+ public WireMockReceivedAssertions(IWireMockServer server)
{
Subject = server;
}
diff --git a/src/WireMock.Net.FluentAssertions/Extensions/WireMockExtensions.cs b/src/WireMock.Net.FluentAssertions/Extensions/WireMockExtensions.cs
index cd174e4e..e638f6cf 100644
--- a/src/WireMock.Net.FluentAssertions/Extensions/WireMockExtensions.cs
+++ b/src/WireMock.Net.FluentAssertions/Extensions/WireMockExtensions.cs
@@ -5,7 +5,7 @@ namespace WireMock.FluentAssertions
{
public static class WireMockExtensions
{
- public static WireMockReceivedAssertions Should(this WireMockServer instance)
+ public static WireMockReceivedAssertions Should(this IWireMockServer instance)
{
return new WireMockReceivedAssertions(instance);
}
diff --git a/src/WireMock.Net.FluentAssertions/WireMock.Net.FluentAssertions.csproj b/src/WireMock.Net.FluentAssertions/WireMock.Net.FluentAssertions.csproj
index 1a6d02d5..1c89aa71 100644
--- a/src/WireMock.Net.FluentAssertions/WireMock.Net.FluentAssertions.csproj
+++ b/src/WireMock.Net.FluentAssertions/WireMock.Net.FluentAssertions.csproj
@@ -35,7 +35,7 @@
-
+
diff --git a/src/WireMock.Net/IMapping.cs b/src/WireMock.Net/IMapping.cs
index 8da094c4..71d93743 100644
--- a/src/WireMock.Net/IMapping.cs
+++ b/src/WireMock.Net/IMapping.cs
@@ -99,7 +99,7 @@ namespace WireMock
///
/// The request message.
/// The Next State.
- /// The .
+ /// The .
RequestMatchResult GetRequestMatchResult(RequestMessage requestMessage, [CanBeNull] string nextState);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Logging/LogEntry.cs b/src/WireMock.Net/Logging/LogEntry.cs
index 053a8d66..885705ba 100644
--- a/src/WireMock.Net/Logging/LogEntry.cs
+++ b/src/WireMock.Net/Logging/LogEntry.cs
@@ -6,78 +6,33 @@ namespace WireMock.Logging
///
/// LogEntry
///
- public class LogEntry
+ public class LogEntry : ILogEntry
{
- ///
- /// Gets or sets the unique identifier.
- ///
- ///
- /// The unique identifier.
- ///
+ ///
public Guid Guid { get; set; }
- ///
- /// Gets or sets the request message.
- ///
- ///
- /// The request message.
- ///
- public RequestMessage RequestMessage { get; set; }
+ ///
+ public IRequestMessage RequestMessage { get; set; }
- ///
- /// Gets or sets the response message.
- ///
- ///
- /// The response message.
- ///
- public ResponseMessage ResponseMessage { get; set; }
+ ///
+ public IResponseMessage ResponseMessage { get; set; }
- ///
- /// Gets or sets the request match result.
- ///
- ///
- /// The request match result.
- ///
- public RequestMatchResult RequestMatchResult { get; set; }
+ ///
+ public IRequestMatchResult RequestMatchResult { get; set; }
- ///
- /// Gets or sets the mapping unique identifier.
- ///
- ///
- /// The mapping unique identifier.
- ///
+ ///
public Guid? MappingGuid { get; set; }
- ///
- /// Gets or sets the mapping unique title.
- ///
- ///
- /// The mapping unique title.
- ///
+ ///
public string MappingTitle { get; set; }
- ///
- /// Gets or sets the partial mapping unique identifier.
- ///
- ///
- /// The mapping unique identifier.
- ///
+ ///
public Guid? PartialMappingGuid { get; set; }
- ///
- /// Gets or sets the partial mapping unique title.
- ///
- ///
- /// The mapping unique title.
- ///
+ ///
public string PartialMappingTitle { get; set; }
- ///
- /// Gets or sets the partial match result.
- ///
- ///
- /// The request match result.
- ///
- public RequestMatchResult PartialMatchResult { get; set; }
+ ///
+ public IRequestMatchResult PartialMatchResult { get; set; }
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/Request/IRequestMatcher.cs b/src/WireMock.Net/Matchers/Request/IRequestMatcher.cs
index b4c725fa..5c2cbad1 100644
--- a/src/WireMock.Net/Matchers/Request/IRequestMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/IRequestMatcher.cs
@@ -15,6 +15,6 @@ namespace WireMock.Matchers.Request
///
/// A value between 0.0 - 1.0 of the similarity.
///
- double GetMatchingScore([NotNull] RequestMessage requestMessage, [NotNull] RequestMatchResult requestMatchResult);
+ double GetMatchingScore([NotNull] IRequestMessage requestMessage, [NotNull] RequestMatchResult requestMatchResult);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/Request/RequestMatchResult.cs b/src/WireMock.Net/Matchers/Request/RequestMatchResult.cs
index 45254b70..0b78625d 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMatchResult.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMatchResult.cs
@@ -7,43 +7,21 @@ namespace WireMock.Matchers.Request
///
/// RequestMatchResult
///
- public class RequestMatchResult : IComparable
+ public class RequestMatchResult : IRequestMatchResult
{
- ///
- /// Gets or sets the match-score.
- ///
- ///
- /// The match-score.
- ///
+ ///
public double TotalScore => MatchDetails.Sum(md => md.Score);
- ///
- /// Gets or sets the total number of matches.
- ///
- ///
- /// The total number of matches.
- ///
+ ///
public int TotalNumber => MatchDetails.Count;
- ///
- /// Gets or sets a value indicating whether this instance is perfect match.
- ///
- ///
- /// true if this instance is perfect match; otherwise, false.
- ///
+ ///
public bool IsPerfectMatch => Math.Abs(TotalScore - TotalNumber) < MatchScores.Tolerance;
- ///
- /// Gets the match percentage.
- ///
- ///
- /// The match percentage.
- ///
+ ///
public double AverageTotalScore => TotalNumber == 0 ? 0.0 : TotalScore / TotalNumber;
- ///
- /// Gets the match details.
- ///
+ ///
public IList MatchDetails { get; } = new List();
///
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
index c2234996..93fe0adb 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
@@ -99,13 +99,13 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = CalculateMatchScore(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
- private double CalculateMatchScore(RequestMessage requestMessage, IMatcher matcher)
+ private double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
{
// Check if the matcher is a IObjectMatcher
if (matcher is IObjectMatcher objectMatcher)
@@ -136,7 +136,7 @@ namespace WireMock.Matchers.Request
return MatchScores.Mismatch;
}
- private double CalculateMatchScore(RequestMessage requestMessage)
+ private double CalculateMatchScore(IRequestMessage requestMessage)
{
if (Matchers != null && Matchers.Any())
{
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs
index 4ea2e2eb..78f7d678 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs
@@ -51,13 +51,13 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
- private double IsMatch(RequestMessage requestMessage)
+ private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs
index 50e681e4..f2d456c3 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs
@@ -34,7 +34,7 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
if (!RequestMatchers.Any())
{
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs
index 50e4c93c..44b57745 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs
@@ -91,13 +91,13 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
- private double IsMatch(RequestMessage requestMessage)
+ private double IsMatch(IRequestMessage requestMessage)
{
if (requestMessage.Cookies == null)
{
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs
index 5cdeeacf..2b920e48 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs
@@ -92,13 +92,13 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
- private double IsMatch(RequestMessage requestMessage)
+ private double IsMatch(IRequestMessage requestMessage)
{
if (requestMessage.Headers == null)
{
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageMethodMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageMethodMatcher.cs
index 3ea3ff3d..d62587e3 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageMethodMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageMethodMatcher.cs
@@ -31,13 +31,13 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = MatchBehaviourHelper.Convert(_matchBehaviour, IsMatch(requestMessage));
return requestMatchResult.AddScore(GetType(), score);
}
- private double IsMatch(RequestMessage requestMessage)
+ private double IsMatch(IRequestMessage requestMessage)
{
return MatchScores.ToScore(Methods.Contains(requestMessage.Method, StringComparer.OrdinalIgnoreCase));
}
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs
index db486063..9b8d19f7 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageParamMatcher.cs
@@ -84,20 +84,20 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = MatchBehaviourHelper.Convert(_matchBehaviour, IsMatch(requestMessage));
return requestMatchResult.AddScore(GetType(), score);
}
- private double IsMatch(RequestMessage requestMessage)
+ private double IsMatch(IRequestMessage requestMessage)
{
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query)));
}
- WireMockList valuesPresentInRequestMessage = requestMessage.GetParameter(Key, IgnoreCase ?? false);
+ WireMockList valuesPresentInRequestMessage = ((RequestMessage) requestMessage).GetParameter(Key, IgnoreCase ?? false);
if (valuesPresentInRequestMessage == null)
{
// Key is not present at all, just return Mismatch
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs
index 0504e5f2..c1106614 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs
@@ -53,13 +53,13 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
- private double IsMatch(RequestMessage requestMessage)
+ private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs
index f4ffde5d..2741dcc0 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageScenarioAndStateMatcher.cs
@@ -32,7 +32,7 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch();
return requestMatchResult.AddScore(GetType(), score);
diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs
index 47432cb2..f437fbd2 100644
--- a/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs
+++ b/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs
@@ -51,13 +51,13 @@ namespace WireMock.Matchers.Request
}
///
- public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult)
+ public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
- private double IsMatch(RequestMessage requestMessage)
+ private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
diff --git a/src/WireMock.Net/RequestMessage.cs b/src/WireMock.Net/RequestMessage.cs
index 361db0ea..85edef65 100644
--- a/src/WireMock.Net/RequestMessage.cs
+++ b/src/WireMock.Net/RequestMessage.cs
@@ -15,131 +15,81 @@ namespace WireMock
///
/// The RequestMessage.
///
- public class RequestMessage
+ public class RequestMessage : IRequestMessage
{
- ///
- /// Gets the Client IP Address.
- ///
+ ///
public string ClientIP { get; }
- ///
- /// Gets the url (relative).
- ///
+ ///
public string Url { get; }
- ///
- /// Gets the AbsoluteUrl.
- ///
+ ///
public string AbsoluteUrl { get; }
- ///
- /// The ProxyUrl (if a proxy is used).
- ///
+ ///
public string ProxyUrl { get; set; }
- ///
- /// Gets the DateTime.
- ///
+ ///
public DateTime DateTime { get; set; }
- ///
- /// Gets the path (relative).
- ///
+ ///
public string Path { get; }
- ///
- /// Gets the AbsolutePath.
- ///
+ ///
public string AbsolutePath { get; }
- ///
- /// Gets the path segments.
- ///
+ ///
public string[] PathSegments { get; }
- ///
- /// Gets the absolute path segments.
- ///
+ ///
public string[] AbsolutePathSegments { get; }
- ///
- /// Gets the method.
- ///
+ ///
public string Method { get; }
- ///
- /// Gets the headers.
- ///
+ ///
public IDictionary> Headers { get; }
- ///
- /// Gets the cookies.
- ///
+ ///
public IDictionary Cookies { get; }
- ///
- /// Gets the query.
- ///
+ ///
public IDictionary> Query { get; }
- ///
- /// Gets the raw query.
- ///
+ ///
public string RawQuery { get; }
- ///
- /// The body.
- ///
- public BodyData BodyData { get; }
+ ///
+ public IBodyData BodyData { get; }
- ///
- /// The original body as string. Convenience getter for Handlebars.
- ///
+ ///
public string Body { get; }
- ///
- /// The body (as JSON object). Convenience getter for Handlebars.
- ///
+ ///
public object BodyAsJson { get; }
- ///
- /// The body (as bytearray). Convenience getter for Handlebars.
- ///
+ ///
public byte[] BodyAsBytes { get; }
- ///
- /// The detected body type. Convenience getter for Handlebars.
- ///
+ ///
public string DetectedBodyType { get; }
- ///
- /// The detected body type from the Content-Type header. Convenience getter for Handlebars.
- ///
+ ///
public string DetectedBodyTypeFromContentType { get; }
- ///
- /// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
- ///
+ ///
public string DetectedCompression { get; }
- ///
- /// Gets the Host
- ///
+ ///
public string Host { get; }
- ///
- /// Gets the protocol
- ///
+ ///
public string Protocol { get; }
- ///
- /// Gets the port
- ///
+ ///
public int Port { get; }
- ///
- /// Gets the origin
- ///
+ ///
public string Origin { get; }
///
diff --git a/src/WireMock.Net/ResponseMessage.cs b/src/WireMock.Net/ResponseMessage.cs
index 4a6c81a4..0c35a25d 100644
--- a/src/WireMock.Net/ResponseMessage.cs
+++ b/src/WireMock.Net/ResponseMessage.cs
@@ -12,41 +12,27 @@ namespace WireMock
///
/// The ResponseMessage.
///
- public class ResponseMessage
+ public class ResponseMessage : IResponseMessage
{
- ///
- /// Gets the headers.
- ///
+ ///
public IDictionary> Headers { get; set; } = new Dictionary>();
- ///
- /// Gets or sets the status code.
- ///
+ ///
public object StatusCode { get; set; }
- ///
- /// Gets or sets the body.
- ///
+ ///
public string BodyOriginal { get; set; }
- ///
- /// Gets or sets the body destination (SameAsSource, String or Bytes).
- ///
+ ///
public string BodyDestination { get; set; }
- ///
- /// The Body.
- ///
- public BodyData BodyData { get; set; }
+ ///
+ public IBodyData BodyData { get; set; }
- ///
- /// The FaultType.
- ///
+ ///
public FaultType FaultType { get; set; }
- ///
- /// Gets or sets the Fault percentage.
- ///
+ ///
public double? FaultPercentage { get; set; }
///
diff --git a/src/WireMock.Net/Serialization/LogEntryMapper.cs b/src/WireMock.Net/Serialization/LogEntryMapper.cs
index b20b1471..5266537a 100644
--- a/src/WireMock.Net/Serialization/LogEntryMapper.cs
+++ b/src/WireMock.Net/Serialization/LogEntryMapper.cs
@@ -10,7 +10,7 @@ namespace WireMock.Serialization
{
internal static class LogEntryMapper
{
- public static LogEntryModel Map(LogEntry logEntry)
+ public static LogEntryModel Map(ILogEntry logEntry)
{
var logRequestModel = new LogRequestModel
{
@@ -124,7 +124,7 @@ namespace WireMock.Serialization
};
}
- private static LogRequestMatchModel Map(RequestMatchResult matchResult)
+ private static LogRequestMatchModel Map(IRequestMatchResult matchResult)
{
if (matchResult == null)
{
diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs
index c569a52b..8665401d 100644
--- a/src/WireMock.Net/Server/WireMockServer.Admin.cs
+++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs
@@ -1,984 +1,984 @@
-using JetBrains.Annotations;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using WireMock.Admin.Mappings;
-using WireMock.Admin.Scenarios;
-using WireMock.Admin.Settings;
-using WireMock.Http;
-using WireMock.Logging;
-using WireMock.Matchers;
-using WireMock.Matchers.Request;
-using WireMock.RequestBuilders;
-using WireMock.ResponseBuilders;
-using WireMock.ResponseProviders;
-using WireMock.Serialization;
-using WireMock.Settings;
-using WireMock.Types;
-using WireMock.Util;
-using WireMock.Validation;
-
-namespace WireMock.Server
-{
- ///
- /// The fluent mock server.
- ///
- public partial class WireMockServer
- {
- private const int EnhancedFileSystemWatcherTimeoutMs = 1000;
- private const int AdminPriority = int.MinValue;
- private const int ProxyPriority = 1000;
- private const string ContentTypeJson = "application/json";
- private const string AdminFiles = "/__admin/files";
- private const string AdminMappings = "/__admin/mappings";
- private const string AdminRequests = "/__admin/requests";
- private const string AdminSettings = "/__admin/settings";
- private const string AdminScenarios = "/__admin/scenarios";
- private const string QueryParamReloadStaticMappings = "reloadStaticMappings";
-
- private readonly RegexMatcher _adminRequestContentTypeJson = new ContentTypeMatcher(ContentTypeJson, true);
- private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
- private readonly RegexMatcher _adminRequestsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/requests\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
-
- private readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
- {
- Formatting = Formatting.Indented,
- NullValueHandling = NullValueHandling.Ignore
- };
-
- private readonly JsonSerializerSettings _settingsIncludeNullValues = new JsonSerializerSettings
- {
- Formatting = Formatting.Indented,
- NullValueHandling = NullValueHandling.Include
- };
-
- #region InitAdmin
- private void InitAdmin()
- {
- // __admin/settings
- Given(Request.Create().WithPath(AdminSettings).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(SettingsGet));
- Given(Request.Create().WithPath(AdminSettings).UsingMethod("PUT", "POST").WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(SettingsUpdate));
-
- // __admin/mappings
- Given(Request.Create().WithPath(AdminMappings).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsGet));
- Given(Request.Create().WithPath(AdminMappings).UsingPost().WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsPost));
- Given(Request.Create().WithPath(AdminMappings).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsDelete));
-
- // __admin/mappings/reset
- Given(Request.Create().WithPath(AdminMappings + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsReset));
-
- // __admin/mappings/{guid}
- Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingGet));
- Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingPut().WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingPut));
- Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingDelete));
-
- // __admin/mappings/save
- Given(Request.Create().WithPath(AdminMappings + "/save").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsSave));
-
- // __admin/requests
- Given(Request.Create().WithPath(AdminRequests).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestsGet));
- Given(Request.Create().WithPath(AdminRequests).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestsDelete));
-
- // __admin/requests/reset
- Given(Request.Create().WithPath(AdminRequests + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestsDelete));
-
- // __admin/request/{guid}
- Given(Request.Create().WithPath(_adminRequestsGuidPathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestGet));
- Given(Request.Create().WithPath(_adminRequestsGuidPathMatcher).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestDelete));
-
- // __admin/requests/find
- Given(Request.Create().WithPath(AdminRequests + "/find").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestsFind));
-
- // __admin/scenarios
- Given(Request.Create().WithPath(AdminScenarios).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosGet));
- Given(Request.Create().WithPath(AdminScenarios).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset));
-
- // __admin/scenarios/reset
- Given(Request.Create().WithPath(AdminScenarios + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset));
-
- // __admin/files/{filename}
- Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FilePost));
- Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingPut()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FilePut));
- Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FileGet));
- Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingHead()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FileHead));
- Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FileDelete));
- }
- #endregion
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using WireMock.Admin.Mappings;
+using WireMock.Admin.Scenarios;
+using WireMock.Admin.Settings;
+using WireMock.Http;
+using WireMock.Logging;
+using WireMock.Matchers;
+using WireMock.Matchers.Request;
+using WireMock.RequestBuilders;
+using WireMock.ResponseBuilders;
+using WireMock.ResponseProviders;
+using WireMock.Serialization;
+using WireMock.Settings;
+using WireMock.Types;
+using WireMock.Util;
+using WireMock.Validation;
- #region StaticMappings
- ///
- [PublicAPI]
- public void SaveStaticMappings([CanBeNull] string folder = null)
- {
- foreach (var mapping in Mappings.Where(m => !m.IsAdminInterface))
- {
- SaveMappingToFile(mapping, folder);
- }
+namespace WireMock.Server
+{
+ ///
+ /// The fluent mock server.
+ ///
+ public partial class WireMockServer
+ {
+ private const int EnhancedFileSystemWatcherTimeoutMs = 1000;
+ private const int AdminPriority = int.MinValue;
+ private const int ProxyPriority = 1000;
+ private const string ContentTypeJson = "application/json";
+ private const string AdminFiles = "/__admin/files";
+ private const string AdminMappings = "/__admin/mappings";
+ private const string AdminRequests = "/__admin/requests";
+ private const string AdminSettings = "/__admin/settings";
+ private const string AdminScenarios = "/__admin/scenarios";
+ private const string QueryParamReloadStaticMappings = "reloadStaticMappings";
+
+ private readonly RegexMatcher _adminRequestContentTypeJson = new ContentTypeMatcher(ContentTypeJson, true);
+ private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
+ private readonly RegexMatcher _adminRequestsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/requests\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
+
+ private readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
+ {
+ Formatting = Formatting.Indented,
+ NullValueHandling = NullValueHandling.Ignore
+ };
+
+ private readonly JsonSerializerSettings _settingsIncludeNullValues = new JsonSerializerSettings
+ {
+ Formatting = Formatting.Indented,
+ NullValueHandling = NullValueHandling.Include
+ };
+
+ #region InitAdmin
+ private void InitAdmin()
+ {
+ // __admin/settings
+ Given(Request.Create().WithPath(AdminSettings).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(SettingsGet));
+ Given(Request.Create().WithPath(AdminSettings).UsingMethod("PUT", "POST").WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(SettingsUpdate));
+
+ // __admin/mappings
+ Given(Request.Create().WithPath(AdminMappings).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsGet));
+ Given(Request.Create().WithPath(AdminMappings).UsingPost().WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsPost));
+ Given(Request.Create().WithPath(AdminMappings).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsDelete));
+
+ // __admin/mappings/reset
+ Given(Request.Create().WithPath(AdminMappings + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsReset));
+
+ // __admin/mappings/{guid}
+ Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingGet));
+ Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingPut().WithHeader(HttpKnownHeaderNames.ContentType, _adminRequestContentTypeJson)).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingPut));
+ Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingDelete));
+
+ // __admin/mappings/save
+ Given(Request.Create().WithPath(AdminMappings + "/save").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsSave));
+
+ // __admin/requests
+ Given(Request.Create().WithPath(AdminRequests).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestsGet));
+ Given(Request.Create().WithPath(AdminRequests).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestsDelete));
+
+ // __admin/requests/reset
+ Given(Request.Create().WithPath(AdminRequests + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestsDelete));
+
+ // __admin/request/{guid}
+ Given(Request.Create().WithPath(_adminRequestsGuidPathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestGet));
+ Given(Request.Create().WithPath(_adminRequestsGuidPathMatcher).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestDelete));
+
+ // __admin/requests/find
+ Given(Request.Create().WithPath(AdminRequests + "/find").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(RequestsFind));
+
+ // __admin/scenarios
+ Given(Request.Create().WithPath(AdminScenarios).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosGet));
+ Given(Request.Create().WithPath(AdminScenarios).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset));
+
+ // __admin/scenarios/reset
+ Given(Request.Create().WithPath(AdminScenarios + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(ScenariosReset));
+
+ // __admin/files/{filename}
+ Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FilePost));
+ Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingPut()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FilePut));
+ Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FileGet));
+ Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingHead()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FileHead));
+ Given(Request.Create().WithPath(_adminFilesFilenamePathMatcher).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(FileDelete));
+ }
+ #endregion
+
+ #region StaticMappings
+ ///
+ [PublicAPI]
+ public void SaveStaticMappings([CanBeNull] string folder = null)
+ {
+ foreach (var mapping in Mappings.Where(m => !m.IsAdminInterface))
+ {
+ SaveMappingToFile(mapping, folder);
+ }
}
- ///
- [PublicAPI]
- public void ReadStaticMappings([CanBeNull] string folder = null)
- {
- if (folder == null)
- {
- folder = _settings.FileSystemHandler.GetMappingFolder();
- }
-
- if (!_settings.FileSystemHandler.FolderExists(folder))
- {
- _settings.Logger.Info("The Static Mapping folder '{0}' does not exist, reading Static MappingFiles will be skipped.", folder);
- return;
- }
-
- foreach (string filename in _settings.FileSystemHandler.EnumerateFiles(folder, _settings.WatchStaticMappingsInSubdirectories == true).OrderBy(f => f))
- {
- _settings.Logger.Info("Reading Static MappingFile : '{0}'", filename);
-
- try
- {
- ReadStaticMappingAndAddOrUpdate(filename);
- }
- catch
- {
- _settings.Logger.Error("Static MappingFile : '{0}' could not be read. This file will be skipped.", filename);
- }
- }
+ ///
+ [PublicAPI]
+ public void ReadStaticMappings([CanBeNull] string folder = null)
+ {
+ if (folder == null)
+ {
+ folder = _settings.FileSystemHandler.GetMappingFolder();
+ }
+
+ if (!_settings.FileSystemHandler.FolderExists(folder))
+ {
+ _settings.Logger.Info("The Static Mapping folder '{0}' does not exist, reading Static MappingFiles will be skipped.", folder);
+ return;
+ }
+
+ foreach (string filename in _settings.FileSystemHandler.EnumerateFiles(folder, _settings.WatchStaticMappingsInSubdirectories == true).OrderBy(f => f))
+ {
+ _settings.Logger.Info("Reading Static MappingFile : '{0}'", filename);
+
+ try
+ {
+ ReadStaticMappingAndAddOrUpdate(filename);
+ }
+ catch
+ {
+ _settings.Logger.Error("Static MappingFile : '{0}' could not be read. This file will be skipped.", filename);
+ }
+ }
}
- ///
- [PublicAPI]
- public void WatchStaticMappings([CanBeNull] string folder = null)
- {
- if (folder == null)
- {
- folder = _settings.FileSystemHandler.GetMappingFolder();
- }
-
- if (!_settings.FileSystemHandler.FolderExists(folder))
- {
- return;
- }
-
- bool includeSubdirectories = _settings.WatchStaticMappingsInSubdirectories == true;
- string includeSubdirectoriesText = includeSubdirectories ? " and Subdirectories" : string.Empty;
-
- _settings.Logger.Info($"Watching folder '{folder}'{includeSubdirectoriesText} for new, updated and deleted MappingFiles.");
-
- var watcher = new EnhancedFileSystemWatcher(folder, "*.json", EnhancedFileSystemWatcherTimeoutMs)
- {
- IncludeSubdirectories = includeSubdirectories
- };
-
- watcher.Created += (sender, args) =>
- {
- _settings.Logger.Info("MappingFile created : '{0}', reading file.", args.FullPath);
- if (!ReadStaticMappingAndAddOrUpdate(args.FullPath))
- {
- _settings.Logger.Error("Unable to read MappingFile '{0}'.", args.FullPath);
- }
- };
- watcher.Changed += (sender, args) =>
- {
- _settings.Logger.Info("MappingFile updated : '{0}', reading file.", args.FullPath);
- if (!ReadStaticMappingAndAddOrUpdate(args.FullPath))
- {
- _settings.Logger.Error("Unable to read MappingFile '{0}'.", args.FullPath);
- }
- };
- watcher.Deleted += (sender, args) =>
- {
- _settings.Logger.Info("MappingFile deleted : '{0}'", args.FullPath);
- string filenameWithoutExtension = Path.GetFileNameWithoutExtension(args.FullPath);
-
- if (Guid.TryParse(filenameWithoutExtension, out Guid guidFromFilename))
- {
- DeleteMapping(guidFromFilename);
- }
- else
- {
- DeleteMapping(args.FullPath);
- }
- };
-
- watcher.EnableRaisingEvents = true;
+ ///
+ [PublicAPI]
+ public void WatchStaticMappings([CanBeNull] string folder = null)
+ {
+ if (folder == null)
+ {
+ folder = _settings.FileSystemHandler.GetMappingFolder();
+ }
+
+ if (!_settings.FileSystemHandler.FolderExists(folder))
+ {
+ return;
+ }
+
+ bool includeSubdirectories = _settings.WatchStaticMappingsInSubdirectories == true;
+ string includeSubdirectoriesText = includeSubdirectories ? " and Subdirectories" : string.Empty;
+
+ _settings.Logger.Info($"Watching folder '{folder}'{includeSubdirectoriesText} for new, updated and deleted MappingFiles.");
+
+ var watcher = new EnhancedFileSystemWatcher(folder, "*.json", EnhancedFileSystemWatcherTimeoutMs)
+ {
+ IncludeSubdirectories = includeSubdirectories
+ };
+
+ watcher.Created += (sender, args) =>
+ {
+ _settings.Logger.Info("MappingFile created : '{0}', reading file.", args.FullPath);
+ if (!ReadStaticMappingAndAddOrUpdate(args.FullPath))
+ {
+ _settings.Logger.Error("Unable to read MappingFile '{0}'.", args.FullPath);
+ }
+ };
+ watcher.Changed += (sender, args) =>
+ {
+ _settings.Logger.Info("MappingFile updated : '{0}', reading file.", args.FullPath);
+ if (!ReadStaticMappingAndAddOrUpdate(args.FullPath))
+ {
+ _settings.Logger.Error("Unable to read MappingFile '{0}'.", args.FullPath);
+ }
+ };
+ watcher.Deleted += (sender, args) =>
+ {
+ _settings.Logger.Info("MappingFile deleted : '{0}'", args.FullPath);
+ string filenameWithoutExtension = Path.GetFileNameWithoutExtension(args.FullPath);
+
+ if (Guid.TryParse(filenameWithoutExtension, out Guid guidFromFilename))
+ {
+ DeleteMapping(guidFromFilename);
+ }
+ else
+ {
+ DeleteMapping(args.FullPath);
+ }
+ };
+
+ watcher.EnableRaisingEvents = true;
}
- ///
- [PublicAPI]
- public bool ReadStaticMappingAndAddOrUpdate([NotNull] string path)
- {
- Check.NotNull(path, nameof(path));
-
- string filenameWithoutExtension = Path.GetFileNameWithoutExtension(path);
-
- if (FileHelper.TryReadMappingFileWithRetryAndDelay(_settings.FileSystemHandler, path, out string value))
- {
- var mappingModels = DeserializeJsonToArray(value);
- foreach (var mappingModel in mappingModels)
- {
- if (mappingModels.Length == 1 && Guid.TryParse(filenameWithoutExtension, out Guid guidFromFilename))
- {
- ConvertMappingAndRegisterAsRespondProvider(mappingModel, guidFromFilename, path);
- }
- else
- {
- ConvertMappingAndRegisterAsRespondProvider(mappingModel, null, path);
- }
- }
-
- return true;
- }
-
- return false;
- }
- #endregion
-
- #region Proxy and Record
- private HttpClient _httpClientForProxy;
-
- private void InitProxyAndRecord(IWireMockServerSettings settings)
- {
- _httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.ProxyAndRecordSettings);
-
- var respondProvider = Given(Request.Create().WithPath("/*").UsingAnyMethod());
- if (settings.StartAdminInterface == true)
- {
- respondProvider.AtPriority(ProxyPriority);
- }
-
- respondProvider.RespondWith(new ProxyAsyncResponseProvider(ProxyAndRecordAsync, settings));
- }
-
- private async Task ProxyAndRecordAsync(RequestMessage requestMessage, IWireMockServerSettings settings)
- {
- var requestUri = new Uri(requestMessage.Url);
- var proxyUri = new Uri(settings.ProxyAndRecordSettings.Url);
- var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
-
- var responseMessage = await HttpClientHelper.SendAsync(
- _httpClientForProxy,
- requestMessage,
- proxyUriWithRequestPathAndQuery.AbsoluteUri,
- !settings.DisableJsonBodyParsing.GetValueOrDefault(false),
- !settings.DisableRequestBodyDecompressing.GetValueOrDefault(false)
- );
-
- if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
- (settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile))
- {
- var mapping = ToMapping(requestMessage, responseMessage, settings.ProxyAndRecordSettings.BlackListedHeaders ?? new string[] { }, settings.ProxyAndRecordSettings.BlackListedCookies ?? new string[] { });
-
- if (settings.ProxyAndRecordSettings.SaveMapping)
- {
- _options.Mappings.TryAdd(mapping.Guid, mapping);
- }
-
- if (settings.ProxyAndRecordSettings.SaveMappingToFile)
- {
- SaveMappingToFile(mapping);
- }
- }
-
- return responseMessage;
- }
-
- private IMapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage, string[] blacklistedHeaders, string[] blacklistedCookies)
- {
- var request = Request.Create();
- request.WithPath(requestMessage.Path);
- request.UsingMethod(requestMessage.Method);
-
- requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
- requestMessage.Cookies.Loop((key, value) =>
- {
- if (!blacklistedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
- {
- request.WithCookie(key, value);
- }
- });
-
- var allBlackListedHeaders = new List(blacklistedHeaders) { "Cookie" };
- requestMessage.Headers.Loop((key, value) =>
- {
- if (!allBlackListedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
- {
- request.WithHeader(key, value.ToArray());
- }
- });
-
- switch (requestMessage.BodyData?.DetectedBodyType)
- {
- case BodyType.Json:
- request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson));
- break;
-
- case BodyType.String:
- request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsString));
- break;
-
- case BodyType.Bytes:
- request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes));
- break;
- }
-
- var response = Response.Create(responseMessage);
-
- return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null);
- }
- #endregion
-
- #region Settings
- private ResponseMessage SettingsGet(RequestMessage requestMessage)
- {
- var model = new SettingsModel
- {
- AllowPartialMapping = _options.AllowPartialMapping,
- MaxRequestLogCount = _options.MaxRequestLogCount,
- RequestLogExpirationDuration = _options.RequestLogExpirationDuration,
- GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds,
- AllowBodyForAllHttpMethods = _options.AllowBodyForAllHttpMethods
- };
-
- return ToJson(model);
- }
-
- private ResponseMessage SettingsUpdate(RequestMessage requestMessage)
- {
- var settings = DeserializeObject(requestMessage);
- _options.MaxRequestLogCount = settings.MaxRequestLogCount;
- _options.RequestLogExpirationDuration = settings.RequestLogExpirationDuration;
-
- if (settings.AllowPartialMapping != null)
- {
- _options.AllowPartialMapping = settings.AllowPartialMapping.Value;
- }
-
- if (settings.GlobalProcessingDelay != null)
- {
- _options.RequestProcessingDelay = TimeSpan.FromMilliseconds(settings.GlobalProcessingDelay.Value);
- }
-
- if (settings.AllowBodyForAllHttpMethods != null)
- {
- _options.AllowBodyForAllHttpMethods = settings.AllowBodyForAllHttpMethods.Value;
- }
-
- return ResponseMessageBuilder.Create("Settings updated");
- }
- #endregion Settings
-
- #region Mapping/{guid}
- private ResponseMessage MappingGet(RequestMessage requestMessage)
- {
- Guid guid = ParseGuidFromRequestMessage(requestMessage);
- var mapping = Mappings.FirstOrDefault(m => !m.IsAdminInterface && m.Guid == guid);
-
- if (mapping == null)
- {
- _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found");
- return ResponseMessageBuilder.Create("Mapping not found", 404);
- }
-
- var model = _mappingConverter.ToMappingModel(mapping);
-
- return ToJson(model);
- }
-
- private ResponseMessage MappingPut(RequestMessage requestMessage)
- {
- Guid guid = ParseGuidFromRequestMessage(requestMessage);
-
- var mappingModel = DeserializeObject(requestMessage);
- Guid? guidFromPut = ConvertMappingAndRegisterAsRespondProvider(mappingModel, guid);
-
- return ResponseMessageBuilder.Create("Mapping added or updated", 200, guidFromPut);
- }
-
- private ResponseMessage MappingDelete(RequestMessage requestMessage)
- {
- Guid guid = ParseGuidFromRequestMessage(requestMessage);
-
- if (DeleteMapping(guid))
- {
- return ResponseMessageBuilder.Create("Mapping removed", 200, guid);
- }
-
- return ResponseMessageBuilder.Create("Mapping not found", 404);
- }
-
- private Guid ParseGuidFromRequestMessage(RequestMessage requestMessage)
- {
- return Guid.Parse(requestMessage.Path.Substring(AdminMappings.Length + 1));
- }
- #endregion Mapping/{guid}
-
- #region Mappings
- private ResponseMessage MappingsSave(RequestMessage requestMessage)
- {
- SaveStaticMappings();
-
- return ResponseMessageBuilder.Create("Mappings saved to disk");
- }
-
- private void SaveMappingToFile(IMapping mapping, string folder = null)
- {
- if (folder == null)
- {
- folder = _settings.FileSystemHandler.GetMappingFolder();
- }
-
- if (!_settings.FileSystemHandler.FolderExists(folder))
- {
- _settings.FileSystemHandler.CreateFolder(folder);
- }
-
- var model = _mappingConverter.ToMappingModel(mapping);
- string filename = (!string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString()) + ".json";
-
- string path = Path.Combine(folder, filename);
-
- _settings.Logger.Info("Saving Mapping file {0}", filename);
-
- _settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(model, _jsonSerializerSettings));
- }
-
- private static string SanitizeFileName(string name, char replaceChar = '_')
- {
- return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar));
- }
-
- private IEnumerable ToMappingModels()
- {
- return Mappings.Where(m => !m.IsAdminInterface).Select(_mappingConverter.ToMappingModel);
- }
-
- private ResponseMessage MappingsGet(RequestMessage requestMessage)
- {
- return ToJson(ToMappingModels());
- }
-
- private ResponseMessage MappingsPost(RequestMessage requestMessage)
- {
- try
- {
- var mappingModels = DeserializeRequestMessageToArray(requestMessage);
- if (mappingModels.Length == 1)
- {
- Guid? guid = ConvertMappingAndRegisterAsRespondProvider(mappingModels[0]);
- return ResponseMessageBuilder.Create("Mapping added", 201, guid);
- }
-
- foreach (var mappingModel in mappingModels)
- {
- ConvertMappingAndRegisterAsRespondProvider(mappingModel);
- }
-
- return ResponseMessageBuilder.Create("Mappings added", 201);
- }
- catch (ArgumentException a)
- {
- _settings.Logger.Error("HttpStatusCode set to 400 {0}", a);
- return ResponseMessageBuilder.Create(a.Message, 400);
- }
- catch (Exception e)
- {
- _settings.Logger.Error("HttpStatusCode set to 500 {0}", e);
- return ResponseMessageBuilder.Create(e.ToString(), 500);
- }
- }
-
- private Guid? ConvertMappingAndRegisterAsRespondProvider(MappingModel mappingModel, Guid? guid = null, string path = null)
- {
- Check.NotNull(mappingModel, nameof(mappingModel));
- Check.NotNull(mappingModel.Request, nameof(mappingModel.Request));
- Check.NotNull(mappingModel.Response, nameof(mappingModel.Response));
-
- var requestBuilder = InitRequestBuilder(mappingModel.Request, true);
- if (requestBuilder == null)
- {
- return null;
- }
-
- var responseBuilder = InitResponseBuilder(mappingModel.Response);
-
- var respondProvider = Given(requestBuilder, mappingModel.SaveToFile == true);
-
- if (guid != null)
- {
- respondProvider = respondProvider.WithGuid(guid.Value);
- }
- else if (mappingModel.Guid != null && mappingModel.Guid != Guid.Empty)
- {
- respondProvider = respondProvider.WithGuid(mappingModel.Guid.Value);
- }
-
- if (path != null)
- {
- respondProvider = respondProvider.WithPath(path);
- }
-
- if (!string.IsNullOrEmpty(mappingModel.Title))
- {
- respondProvider = respondProvider.WithTitle(mappingModel.Title);
- }
-
- if (mappingModel.Priority != null)
- {
- respondProvider = respondProvider.AtPriority(mappingModel.Priority.Value);
- }
-
- if (mappingModel.Scenario != null)
- {
- respondProvider = respondProvider.InScenario(mappingModel.Scenario);
- respondProvider = respondProvider.WhenStateIs(mappingModel.WhenStateIs);
- respondProvider = respondProvider.WillSetStateTo(mappingModel.SetStateTo);
- }
-
- respondProvider.RespondWith(responseBuilder);
-
- return respondProvider.Guid;
- }
-
- private ResponseMessage MappingsDelete(RequestMessage requestMessage)
- {
- if (!string.IsNullOrEmpty(requestMessage.Body))
- {
- var deletedGuids = MappingsDeleteMappingFromBody(requestMessage);
- if (deletedGuids != null)
- {
- return ResponseMessageBuilder.Create($"Mappings deleted. Affected GUIDs: [{string.Join(", ", deletedGuids.ToArray())}]");
- }
- else
- {
- // return bad request
- return ResponseMessageBuilder.Create("Poorly formed mapping JSON.", 400);
- }
- }
- else
- {
- ResetMappings();
-
- ResetScenarios();
-
- return ResponseMessageBuilder.Create("Mappings deleted");
- }
- }
-
- private IEnumerable MappingsDeleteMappingFromBody(RequestMessage requestMessage)
- {
- var deletedGuids = new List();
-
- try
- {
- var mappingModels = DeserializeRequestMessageToArray(requestMessage);
- foreach (var mappingModel in mappingModels)
- {
- if (mappingModel.Guid.HasValue)
- {
- if (DeleteMapping(mappingModel.Guid.Value))
- {
- deletedGuids.Add(mappingModel.Guid.Value);
- }
- else
- {
- _settings.Logger.Debug($"Did not find/delete mapping with GUID: {mappingModel.Guid.Value}.");
- }
- }
- }
- }
- catch (ArgumentException a)
- {
- _settings.Logger.Error("ArgumentException: {0}", a);
- return null;
- }
- catch (Exception e)
- {
- _settings.Logger.Error("Exception: {0}", e);
- return null;
- }
-
- return deletedGuids;
- }
-
- private ResponseMessage MappingsReset(RequestMessage requestMessage)
- {
- ResetMappings();
-
- ResetScenarios();
-
- string message = "Mappings reset";
- if (requestMessage.Query.ContainsKey(QueryParamReloadStaticMappings) &&
- bool.TryParse(requestMessage.Query[QueryParamReloadStaticMappings].ToString(), out bool reloadStaticMappings)
- && reloadStaticMappings)
- {
- ReadStaticMappings();
- message = $"{message} and static mappings reloaded";
- }
-
- return ResponseMessageBuilder.Create(message);
- }
- #endregion Mappings
-
- #region Request/{guid}
- private ResponseMessage RequestGet(RequestMessage requestMessage)
- {
- Guid guid = ParseGuidFromRequestMessage(requestMessage);
- var entry = LogEntries.FirstOrDefault(r => !r.RequestMessage.Path.StartsWith("/__admin/") && r.Guid == guid);
-
- if (entry == null)
- {
- _settings.Logger.Warn("HttpStatusCode set to 404 : Request not found");
- return ResponseMessageBuilder.Create("Request not found", 404);
- }
-
- var model = LogEntryMapper.Map(entry);
-
- return ToJson(model);
- }
-
- private ResponseMessage RequestDelete(RequestMessage requestMessage)
- {
- Guid guid = ParseGuidFromRequestMessage(requestMessage);
-
- if (DeleteLogEntry(guid))
- {
- return ResponseMessageBuilder.Create("Request removed");
- }
-
- return ResponseMessageBuilder.Create("Request not found", 404);
- }
- #endregion Request/{guid}
-
- #region Requests
- private ResponseMessage RequestsGet(RequestMessage requestMessage)
- {
- var result = LogEntries
- .Where(r => !r.RequestMessage.Path.StartsWith("/__admin/"))
- .Select(LogEntryMapper.Map);
-
- return ToJson(result);
- }
-
- private ResponseMessage RequestsDelete(RequestMessage requestMessage)
- {
- ResetLogEntries();
-
- return ResponseMessageBuilder.Create("Requests deleted");
- }
- #endregion Requests
-
- #region Requests/find
- private ResponseMessage RequestsFind(RequestMessage requestMessage)
- {
- var requestModel = DeserializeObject(requestMessage);
-
- var request = (Request)InitRequestBuilder(requestModel, false);
-
- var dict = new Dictionary();
- foreach (var logEntry in LogEntries.Where(le => !le.RequestMessage.Path.StartsWith("/__admin/")))
- {
- var requestMatchResult = new RequestMatchResult();
- if (request.GetMatchingScore(logEntry.RequestMessage, requestMatchResult) > MatchScores.AlmostPerfect)
- {
- dict.Add(logEntry, requestMatchResult);
- }
- }
-
- var result = dict.OrderBy(x => x.Value.AverageTotalScore).Select(x => x.Key).Select(LogEntryMapper.Map);
-
- return ToJson(result);
- }
- #endregion Requests/find
-
- #region Scenarios
- private ResponseMessage ScenariosGet(RequestMessage requestMessage)
- {
- var scenariosStates = Scenarios.Values.Select(s => new ScenarioStateModel
- {
- Name = s.Name,
- NextState = s.NextState,
- Started = s.Started,
- Finished = s.Finished
- });
-
- return ToJson(scenariosStates, true);
- }
-
- private ResponseMessage ScenariosReset(RequestMessage requestMessage)
- {
- ResetScenarios();
-
- return ResponseMessageBuilder.Create("Scenarios reset");
- }
- #endregion
-
- private IRequestBuilder InitRequestBuilder(RequestModel requestModel, bool pathOrUrlRequired)
- {
- IRequestBuilder requestBuilder = Request.Create();
-
- if (requestModel.ClientIP != null)
- {
- if (requestModel.ClientIP is string clientIP)
- {
- requestBuilder = requestBuilder.WithClientIP(clientIP);
- }
- else
- {
- var clientIPModel = JsonUtils.ParseJTokenToObject(requestModel.ClientIP);
- if (clientIPModel?.Matchers != null)
- {
- requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
- }
- }
- }
-
- bool pathOrUrlmatchersValid = false;
- if (requestModel.Path != null)
- {
- if (requestModel.Path is string path)
- {
- requestBuilder = requestBuilder.WithPath(path);
- pathOrUrlmatchersValid = true;
- }
- else
- {
- var pathModel = JsonUtils.ParseJTokenToObject(requestModel.Path);
- if (pathModel?.Matchers != null)
- {
- requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
- pathOrUrlmatchersValid = true;
- }
- }
- }
- else if (requestModel.Url != null)
- {
- if (requestModel.Url is string url)
- {
- requestBuilder = requestBuilder.WithUrl(url);
- pathOrUrlmatchersValid = true;
- }
- else
- {
- var urlModel = JsonUtils.ParseJTokenToObject(requestModel.Url);
- if (urlModel?.Matchers != null)
- {
- requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
- pathOrUrlmatchersValid = true;
- }
- }
- }
-
- if (pathOrUrlRequired && !pathOrUrlmatchersValid)
- {
- _settings.Logger.Error("Path or Url matcher is missing for this mapping, this mapping will not be added.");
- return null;
- }
-
- if (requestModel.Methods != null)
- {
- requestBuilder = requestBuilder.UsingMethod(requestModel.Methods);
- }
-
- if (requestModel.Headers != null)
- {
- foreach (var headerModel in requestModel.Headers.Where(h => h.Matchers != null))
- {
- requestBuilder = requestBuilder.WithHeader(
- headerModel.Name,
- headerModel.IgnoreCase == true,
- headerModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
- headerModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray()
- );
- }
- }
-
- if (requestModel.Cookies != null)
- {
- foreach (var cookieModel in requestModel.Cookies.Where(c => c.Matchers != null))
- {
- requestBuilder = requestBuilder.WithCookie(
- cookieModel.Name,
- cookieModel.IgnoreCase == true,
- cookieModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
- cookieModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
- }
- }
-
- if (requestModel.Params != null)
- {
- foreach (var paramModel in requestModel.Params.Where(c => c.Matchers != null))
- {
- bool ignoreCase = paramModel?.IgnoreCase ?? false;
- requestBuilder = requestBuilder.WithParam(paramModel.Name, ignoreCase, paramModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
- }
- }
-
- if (requestModel.Body?.Matcher != null)
- {
- requestBuilder = requestBuilder.WithBody(_matcherMapper.Map(requestModel.Body.Matcher));
- }
- else if (requestModel.Body?.Matchers != null)
- {
- requestBuilder = requestBuilder.WithBody(_matcherMapper.Map(requestModel.Body.Matchers));
- }
-
- return requestBuilder;
- }
-
- private IResponseBuilder InitResponseBuilder(ResponseModel responseModel)
- {
- IResponseBuilder responseBuilder = Response.Create();
-
- if (responseModel.Delay > 0)
- {
- responseBuilder = responseBuilder.WithDelay(responseModel.Delay.Value);
- }
-
- if (responseModel.UseTransformer == true)
- {
- responseBuilder = responseBuilder.WithTransformer(responseModel.UseTransformerForBodyAsFile == true);
- }
-
- if (!string.IsNullOrEmpty(responseModel.ProxyUrl))
- {
- var proxyAndRecordSettings = new ProxyAndRecordSettings
- {
- Url = responseModel.ProxyUrl,
- ClientX509Certificate2ThumbprintOrSubjectName = responseModel.X509Certificate2ThumbprintOrSubjectName,
- WebProxySettings = responseModel.WebProxy != null ? new WebProxySettings
- {
- Address = responseModel.WebProxy.Address,
- UserName = responseModel.WebProxy.UserName,
- Password = responseModel.WebProxy.Password
- } : null
- };
-
- return responseBuilder.WithProxy(proxyAndRecordSettings);
- }
-
- if (responseModel.StatusCode is string statusCodeAsString)
- {
- responseBuilder = responseBuilder.WithStatusCode(statusCodeAsString);
- }
- else if (responseModel.StatusCode != null)
- {
- // Convert to Int32 because Newtonsoft deserializes an 'object' with a number value to a long.
- responseBuilder = responseBuilder.WithStatusCode(Convert.ToInt32(responseModel.StatusCode));
- }
-
- if (responseModel.Headers != null)
- {
- foreach (var entry in responseModel.Headers)
- {
- responseBuilder = entry.Value is string value ?
- responseBuilder.WithHeader(entry.Key, value) :
- responseBuilder.WithHeader(entry.Key, JsonUtils.ParseJTokenToObject(entry.Value));
- }
- }
- else if (responseModel.HeadersRaw != null)
- {
- foreach (string headerLine in responseModel.HeadersRaw.Split(new[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
- {
- int indexColon = headerLine.IndexOf(":", StringComparison.Ordinal);
- string key = headerLine.Substring(0, indexColon).TrimStart(' ', '\t');
- string value = headerLine.Substring(indexColon + 1).TrimStart(' ', '\t');
- responseBuilder = responseBuilder.WithHeader(key, value);
- }
- }
-
- if (responseModel.BodyAsBytes != null)
- {
- responseBuilder = responseBuilder.WithBody(responseModel.BodyAsBytes, responseModel.BodyDestination, ToEncoding(responseModel.BodyEncoding));
- }
- else if (responseModel.Body != null)
- {
- responseBuilder = responseBuilder.WithBody(responseModel.Body, responseModel.BodyDestination, ToEncoding(responseModel.BodyEncoding));
- }
- else if (responseModel.BodyAsJson != null)
- {
- responseBuilder = responseBuilder.WithBodyAsJson(responseModel.BodyAsJson, ToEncoding(responseModel.BodyEncoding), responseModel.BodyAsJsonIndented == true);
- }
- else if (responseModel.BodyAsFile != null)
- {
- responseBuilder = responseBuilder.WithBodyFromFile(responseModel.BodyAsFile);
- }
-
- if (responseModel.Fault != null && Enum.TryParse(responseModel.Fault.Type, out FaultType faultType))
- {
- responseBuilder.WithFault(faultType, responseModel.Fault.Percentage);
- }
-
- return responseBuilder;
- }
-
- private ResponseMessage ToJson(T result, bool keepNullValues = false)
- {
- return new ResponseMessage
- {
- BodyData = new BodyData
- {
- DetectedBodyType = BodyType.String,
- BodyAsString = JsonConvert.SerializeObject(result, keepNullValues ? _settingsIncludeNullValues : _jsonSerializerSettings)
- },
- StatusCode = (int)HttpStatusCode.OK,
- Headers = new Dictionary> { { HttpKnownHeaderNames.ContentType, new WireMockList(ContentTypeJson) } }
- };
- }
-
- private Encoding ToEncoding(EncodingModel encodingModel)
- {
- return encodingModel != null ? Encoding.GetEncoding(encodingModel.CodePage) : null;
- }
-
- private T DeserializeObject(RequestMessage requestMessage)
- {
- if (requestMessage?.BodyData?.DetectedBodyType == BodyType.String)
- {
- return JsonUtils.DeserializeObject(requestMessage.BodyData.BodyAsString);
- }
-
- if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
- {
- return ((JObject)requestMessage.BodyData.BodyAsJson).ToObject();
- }
-
- return default(T);
- }
-
- private T[] DeserializeRequestMessageToArray(RequestMessage requestMessage)
- {
- if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
- {
- var bodyAsJson = requestMessage.BodyData.BodyAsJson;
-
- return DeserializeObjectToArray(bodyAsJson);
- }
-
- return default(T[]);
- }
-
- private T[] DeserializeObjectToArray(object value)
- {
- if (value is JArray jArray)
- {
- return jArray.ToObject();
- }
-
- var singleResult = ((JObject)value).ToObject();
- return new[] { singleResult };
- }
-
- private T[] DeserializeJsonToArray(string value)
- {
- return DeserializeObjectToArray(JsonUtils.DeserializeObject(value));
- }
- }
+ ///
+ [PublicAPI]
+ public bool ReadStaticMappingAndAddOrUpdate([NotNull] string path)
+ {
+ Check.NotNull(path, nameof(path));
+
+ string filenameWithoutExtension = Path.GetFileNameWithoutExtension(path);
+
+ if (FileHelper.TryReadMappingFileWithRetryAndDelay(_settings.FileSystemHandler, path, out string value))
+ {
+ var mappingModels = DeserializeJsonToArray(value);
+ foreach (var mappingModel in mappingModels)
+ {
+ if (mappingModels.Length == 1 && Guid.TryParse(filenameWithoutExtension, out Guid guidFromFilename))
+ {
+ ConvertMappingAndRegisterAsRespondProvider(mappingModel, guidFromFilename, path);
+ }
+ else
+ {
+ ConvertMappingAndRegisterAsRespondProvider(mappingModel, null, path);
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ #endregion
+
+ #region Proxy and Record
+ private HttpClient _httpClientForProxy;
+
+ private void InitProxyAndRecord(IWireMockServerSettings settings)
+ {
+ _httpClientForProxy = HttpClientHelper.CreateHttpClient(settings.ProxyAndRecordSettings);
+
+ var respondProvider = Given(Request.Create().WithPath("/*").UsingAnyMethod());
+ if (settings.StartAdminInterface == true)
+ {
+ respondProvider.AtPriority(ProxyPriority);
+ }
+
+ respondProvider.RespondWith(new ProxyAsyncResponseProvider(ProxyAndRecordAsync, settings));
+ }
+
+ private async Task ProxyAndRecordAsync(RequestMessage requestMessage, IWireMockServerSettings settings)
+ {
+ var requestUri = new Uri(requestMessage.Url);
+ var proxyUri = new Uri(settings.ProxyAndRecordSettings.Url);
+ var proxyUriWithRequestPathAndQuery = new Uri(proxyUri, requestUri.PathAndQuery);
+
+ var responseMessage = await HttpClientHelper.SendAsync(
+ _httpClientForProxy,
+ requestMessage,
+ proxyUriWithRequestPathAndQuery.AbsoluteUri,
+ !settings.DisableJsonBodyParsing.GetValueOrDefault(false),
+ !settings.DisableRequestBodyDecompressing.GetValueOrDefault(false)
+ );
+
+ if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
+ (settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile))
+ {
+ var mapping = ToMapping(requestMessage, responseMessage, settings.ProxyAndRecordSettings.BlackListedHeaders ?? new string[] { }, settings.ProxyAndRecordSettings.BlackListedCookies ?? new string[] { });
+
+ if (settings.ProxyAndRecordSettings.SaveMapping)
+ {
+ _options.Mappings.TryAdd(mapping.Guid, mapping);
+ }
+
+ if (settings.ProxyAndRecordSettings.SaveMappingToFile)
+ {
+ SaveMappingToFile(mapping);
+ }
+ }
+
+ return responseMessage;
+ }
+
+ private IMapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage, string[] blacklistedHeaders, string[] blacklistedCookies)
+ {
+ var request = Request.Create();
+ request.WithPath(requestMessage.Path);
+ request.UsingMethod(requestMessage.Method);
+
+ requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
+ requestMessage.Cookies.Loop((key, value) =>
+ {
+ if (!blacklistedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
+ {
+ request.WithCookie(key, value);
+ }
+ });
+
+ var allBlackListedHeaders = new List(blacklistedHeaders) { "Cookie" };
+ requestMessage.Headers.Loop((key, value) =>
+ {
+ if (!allBlackListedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
+ {
+ request.WithHeader(key, value.ToArray());
+ }
+ });
+
+ switch (requestMessage.BodyData?.DetectedBodyType)
+ {
+ case BodyType.Json:
+ request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson));
+ break;
+
+ case BodyType.String:
+ request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsString));
+ break;
+
+ case BodyType.Bytes:
+ request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes));
+ break;
+ }
+
+ var response = Response.Create(responseMessage);
+
+ return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null);
+ }
+ #endregion
+
+ #region Settings
+ private ResponseMessage SettingsGet(RequestMessage requestMessage)
+ {
+ var model = new SettingsModel
+ {
+ AllowPartialMapping = _options.AllowPartialMapping,
+ MaxRequestLogCount = _options.MaxRequestLogCount,
+ RequestLogExpirationDuration = _options.RequestLogExpirationDuration,
+ GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds,
+ AllowBodyForAllHttpMethods = _options.AllowBodyForAllHttpMethods
+ };
+
+ return ToJson(model);
+ }
+
+ private ResponseMessage SettingsUpdate(RequestMessage requestMessage)
+ {
+ var settings = DeserializeObject(requestMessage);
+ _options.MaxRequestLogCount = settings.MaxRequestLogCount;
+ _options.RequestLogExpirationDuration = settings.RequestLogExpirationDuration;
+
+ if (settings.AllowPartialMapping != null)
+ {
+ _options.AllowPartialMapping = settings.AllowPartialMapping.Value;
+ }
+
+ if (settings.GlobalProcessingDelay != null)
+ {
+ _options.RequestProcessingDelay = TimeSpan.FromMilliseconds(settings.GlobalProcessingDelay.Value);
+ }
+
+ if (settings.AllowBodyForAllHttpMethods != null)
+ {
+ _options.AllowBodyForAllHttpMethods = settings.AllowBodyForAllHttpMethods.Value;
+ }
+
+ return ResponseMessageBuilder.Create("Settings updated");
+ }
+ #endregion Settings
+
+ #region Mapping/{guid}
+ private ResponseMessage MappingGet(RequestMessage requestMessage)
+ {
+ Guid guid = ParseGuidFromRequestMessage(requestMessage);
+ var mapping = Mappings.FirstOrDefault(m => !m.IsAdminInterface && m.Guid == guid);
+
+ if (mapping == null)
+ {
+ _settings.Logger.Warn("HttpStatusCode set to 404 : Mapping not found");
+ return ResponseMessageBuilder.Create("Mapping not found", 404);
+ }
+
+ var model = _mappingConverter.ToMappingModel(mapping);
+
+ return ToJson(model);
+ }
+
+ private ResponseMessage MappingPut(RequestMessage requestMessage)
+ {
+ Guid guid = ParseGuidFromRequestMessage(requestMessage);
+
+ var mappingModel = DeserializeObject(requestMessage);
+ Guid? guidFromPut = ConvertMappingAndRegisterAsRespondProvider(mappingModel, guid);
+
+ return ResponseMessageBuilder.Create("Mapping added or updated", 200, guidFromPut);
+ }
+
+ private ResponseMessage MappingDelete(RequestMessage requestMessage)
+ {
+ Guid guid = ParseGuidFromRequestMessage(requestMessage);
+
+ if (DeleteMapping(guid))
+ {
+ return ResponseMessageBuilder.Create("Mapping removed", 200, guid);
+ }
+
+ return ResponseMessageBuilder.Create("Mapping not found", 404);
+ }
+
+ private Guid ParseGuidFromRequestMessage(RequestMessage requestMessage)
+ {
+ return Guid.Parse(requestMessage.Path.Substring(AdminMappings.Length + 1));
+ }
+ #endregion Mapping/{guid}
+
+ #region Mappings
+ private ResponseMessage MappingsSave(RequestMessage requestMessage)
+ {
+ SaveStaticMappings();
+
+ return ResponseMessageBuilder.Create("Mappings saved to disk");
+ }
+
+ private void SaveMappingToFile(IMapping mapping, string folder = null)
+ {
+ if (folder == null)
+ {
+ folder = _settings.FileSystemHandler.GetMappingFolder();
+ }
+
+ if (!_settings.FileSystemHandler.FolderExists(folder))
+ {
+ _settings.FileSystemHandler.CreateFolder(folder);
+ }
+
+ var model = _mappingConverter.ToMappingModel(mapping);
+ string filename = (!string.IsNullOrEmpty(mapping.Title) ? SanitizeFileName(mapping.Title) : mapping.Guid.ToString()) + ".json";
+
+ string path = Path.Combine(folder, filename);
+
+ _settings.Logger.Info("Saving Mapping file {0}", filename);
+
+ _settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(model, _jsonSerializerSettings));
+ }
+
+ private static string SanitizeFileName(string name, char replaceChar = '_')
+ {
+ return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar));
+ }
+
+ private IEnumerable ToMappingModels()
+ {
+ return Mappings.Where(m => !m.IsAdminInterface).Select(_mappingConverter.ToMappingModel);
+ }
+
+ private ResponseMessage MappingsGet(RequestMessage requestMessage)
+ {
+ return ToJson(ToMappingModels());
+ }
+
+ private ResponseMessage MappingsPost(RequestMessage requestMessage)
+ {
+ try
+ {
+ var mappingModels = DeserializeRequestMessageToArray(requestMessage);
+ if (mappingModels.Length == 1)
+ {
+ Guid? guid = ConvertMappingAndRegisterAsRespondProvider(mappingModels[0]);
+ return ResponseMessageBuilder.Create("Mapping added", 201, guid);
+ }
+
+ foreach (var mappingModel in mappingModels)
+ {
+ ConvertMappingAndRegisterAsRespondProvider(mappingModel);
+ }
+
+ return ResponseMessageBuilder.Create("Mappings added", 201);
+ }
+ catch (ArgumentException a)
+ {
+ _settings.Logger.Error("HttpStatusCode set to 400 {0}", a);
+ return ResponseMessageBuilder.Create(a.Message, 400);
+ }
+ catch (Exception e)
+ {
+ _settings.Logger.Error("HttpStatusCode set to 500 {0}", e);
+ return ResponseMessageBuilder.Create(e.ToString(), 500);
+ }
+ }
+
+ private Guid? ConvertMappingAndRegisterAsRespondProvider(MappingModel mappingModel, Guid? guid = null, string path = null)
+ {
+ Check.NotNull(mappingModel, nameof(mappingModel));
+ Check.NotNull(mappingModel.Request, nameof(mappingModel.Request));
+ Check.NotNull(mappingModel.Response, nameof(mappingModel.Response));
+
+ var requestBuilder = InitRequestBuilder(mappingModel.Request, true);
+ if (requestBuilder == null)
+ {
+ return null;
+ }
+
+ var responseBuilder = InitResponseBuilder(mappingModel.Response);
+
+ var respondProvider = Given(requestBuilder, mappingModel.SaveToFile == true);
+
+ if (guid != null)
+ {
+ respondProvider = respondProvider.WithGuid(guid.Value);
+ }
+ else if (mappingModel.Guid != null && mappingModel.Guid != Guid.Empty)
+ {
+ respondProvider = respondProvider.WithGuid(mappingModel.Guid.Value);
+ }
+
+ if (path != null)
+ {
+ respondProvider = respondProvider.WithPath(path);
+ }
+
+ if (!string.IsNullOrEmpty(mappingModel.Title))
+ {
+ respondProvider = respondProvider.WithTitle(mappingModel.Title);
+ }
+
+ if (mappingModel.Priority != null)
+ {
+ respondProvider = respondProvider.AtPriority(mappingModel.Priority.Value);
+ }
+
+ if (mappingModel.Scenario != null)
+ {
+ respondProvider = respondProvider.InScenario(mappingModel.Scenario);
+ respondProvider = respondProvider.WhenStateIs(mappingModel.WhenStateIs);
+ respondProvider = respondProvider.WillSetStateTo(mappingModel.SetStateTo);
+ }
+
+ respondProvider.RespondWith(responseBuilder);
+
+ return respondProvider.Guid;
+ }
+
+ private ResponseMessage MappingsDelete(RequestMessage requestMessage)
+ {
+ if (!string.IsNullOrEmpty(requestMessage.Body))
+ {
+ var deletedGuids = MappingsDeleteMappingFromBody(requestMessage);
+ if (deletedGuids != null)
+ {
+ return ResponseMessageBuilder.Create($"Mappings deleted. Affected GUIDs: [{string.Join(", ", deletedGuids.ToArray())}]");
+ }
+ else
+ {
+ // return bad request
+ return ResponseMessageBuilder.Create("Poorly formed mapping JSON.", 400);
+ }
+ }
+ else
+ {
+ ResetMappings();
+
+ ResetScenarios();
+
+ return ResponseMessageBuilder.Create("Mappings deleted");
+ }
+ }
+
+ private IEnumerable MappingsDeleteMappingFromBody(RequestMessage requestMessage)
+ {
+ var deletedGuids = new List();
+
+ try
+ {
+ var mappingModels = DeserializeRequestMessageToArray(requestMessage);
+ foreach (var mappingModel in mappingModels)
+ {
+ if (mappingModel.Guid.HasValue)
+ {
+ if (DeleteMapping(mappingModel.Guid.Value))
+ {
+ deletedGuids.Add(mappingModel.Guid.Value);
+ }
+ else
+ {
+ _settings.Logger.Debug($"Did not find/delete mapping with GUID: {mappingModel.Guid.Value}.");
+ }
+ }
+ }
+ }
+ catch (ArgumentException a)
+ {
+ _settings.Logger.Error("ArgumentException: {0}", a);
+ return null;
+ }
+ catch (Exception e)
+ {
+ _settings.Logger.Error("Exception: {0}", e);
+ return null;
+ }
+
+ return deletedGuids;
+ }
+
+ private ResponseMessage MappingsReset(RequestMessage requestMessage)
+ {
+ ResetMappings();
+
+ ResetScenarios();
+
+ string message = "Mappings reset";
+ if (requestMessage.Query.ContainsKey(QueryParamReloadStaticMappings) &&
+ bool.TryParse(requestMessage.Query[QueryParamReloadStaticMappings].ToString(), out bool reloadStaticMappings)
+ && reloadStaticMappings)
+ {
+ ReadStaticMappings();
+ message = $"{message} and static mappings reloaded";
+ }
+
+ return ResponseMessageBuilder.Create(message);
+ }
+ #endregion Mappings
+
+ #region Request/{guid}
+ private ResponseMessage RequestGet(RequestMessage requestMessage)
+ {
+ Guid guid = ParseGuidFromRequestMessage(requestMessage);
+ var entry = LogEntries.FirstOrDefault(r => !r.RequestMessage.Path.StartsWith("/__admin/") && r.Guid == guid);
+
+ if (entry == null)
+ {
+ _settings.Logger.Warn("HttpStatusCode set to 404 : Request not found");
+ return ResponseMessageBuilder.Create("Request not found", 404);
+ }
+
+ var model = LogEntryMapper.Map(entry);
+
+ return ToJson(model);
+ }
+
+ private ResponseMessage RequestDelete(RequestMessage requestMessage)
+ {
+ Guid guid = ParseGuidFromRequestMessage(requestMessage);
+
+ if (DeleteLogEntry(guid))
+ {
+ return ResponseMessageBuilder.Create("Request removed");
+ }
+
+ return ResponseMessageBuilder.Create("Request not found", 404);
+ }
+ #endregion Request/{guid}
+
+ #region Requests
+ private ResponseMessage RequestsGet(RequestMessage requestMessage)
+ {
+ var result = LogEntries
+ .Where(r => !r.RequestMessage.Path.StartsWith("/__admin/"))
+ .Select(LogEntryMapper.Map);
+
+ return ToJson(result);
+ }
+
+ private ResponseMessage RequestsDelete(RequestMessage requestMessage)
+ {
+ ResetLogEntries();
+
+ return ResponseMessageBuilder.Create("Requests deleted");
+ }
+ #endregion Requests
+
+ #region Requests/find
+ private ResponseMessage RequestsFind(RequestMessage requestMessage)
+ {
+ var requestModel = DeserializeObject(requestMessage);
+
+ var request = (Request)InitRequestBuilder(requestModel, false);
+
+ var dict = new Dictionary();
+ foreach (var logEntry in LogEntries.Where(le => !le.RequestMessage.Path.StartsWith("/__admin/")))
+ {
+ var requestMatchResult = new RequestMatchResult();
+ if (request.GetMatchingScore(logEntry.RequestMessage, requestMatchResult) > MatchScores.AlmostPerfect)
+ {
+ dict.Add(logEntry, requestMatchResult);
+ }
+ }
+
+ var result = dict.OrderBy(x => x.Value.AverageTotalScore).Select(x => x.Key).Select(LogEntryMapper.Map);
+
+ return ToJson(result);
+ }
+ #endregion Requests/find
+
+ #region Scenarios
+ private ResponseMessage ScenariosGet(RequestMessage requestMessage)
+ {
+ var scenariosStates = Scenarios.Values.Select(s => new ScenarioStateModel
+ {
+ Name = s.Name,
+ NextState = s.NextState,
+ Started = s.Started,
+ Finished = s.Finished
+ });
+
+ return ToJson(scenariosStates, true);
+ }
+
+ private ResponseMessage ScenariosReset(RequestMessage requestMessage)
+ {
+ ResetScenarios();
+
+ return ResponseMessageBuilder.Create("Scenarios reset");
+ }
+ #endregion
+
+ private IRequestBuilder InitRequestBuilder(RequestModel requestModel, bool pathOrUrlRequired)
+ {
+ IRequestBuilder requestBuilder = Request.Create();
+
+ if (requestModel.ClientIP != null)
+ {
+ if (requestModel.ClientIP is string clientIP)
+ {
+ requestBuilder = requestBuilder.WithClientIP(clientIP);
+ }
+ else
+ {
+ var clientIPModel = JsonUtils.ParseJTokenToObject(requestModel.ClientIP);
+ if (clientIPModel?.Matchers != null)
+ {
+ requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
+ }
+ }
+ }
+
+ bool pathOrUrlmatchersValid = false;
+ if (requestModel.Path != null)
+ {
+ if (requestModel.Path is string path)
+ {
+ requestBuilder = requestBuilder.WithPath(path);
+ pathOrUrlmatchersValid = true;
+ }
+ else
+ {
+ var pathModel = JsonUtils.ParseJTokenToObject(requestModel.Path);
+ if (pathModel?.Matchers != null)
+ {
+ requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
+ pathOrUrlmatchersValid = true;
+ }
+ }
+ }
+ else if (requestModel.Url != null)
+ {
+ if (requestModel.Url is string url)
+ {
+ requestBuilder = requestBuilder.WithUrl(url);
+ pathOrUrlmatchersValid = true;
+ }
+ else
+ {
+ var urlModel = JsonUtils.ParseJTokenToObject(requestModel.Url);
+ if (urlModel?.Matchers != null)
+ {
+ requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
+ pathOrUrlmatchersValid = true;
+ }
+ }
+ }
+
+ if (pathOrUrlRequired && !pathOrUrlmatchersValid)
+ {
+ _settings.Logger.Error("Path or Url matcher is missing for this mapping, this mapping will not be added.");
+ return null;
+ }
+
+ if (requestModel.Methods != null)
+ {
+ requestBuilder = requestBuilder.UsingMethod(requestModel.Methods);
+ }
+
+ if (requestModel.Headers != null)
+ {
+ foreach (var headerModel in requestModel.Headers.Where(h => h.Matchers != null))
+ {
+ requestBuilder = requestBuilder.WithHeader(
+ headerModel.Name,
+ headerModel.IgnoreCase == true,
+ headerModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
+ headerModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray()
+ );
+ }
+ }
+
+ if (requestModel.Cookies != null)
+ {
+ foreach (var cookieModel in requestModel.Cookies.Where(c => c.Matchers != null))
+ {
+ requestBuilder = requestBuilder.WithCookie(
+ cookieModel.Name,
+ cookieModel.IgnoreCase == true,
+ cookieModel.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch,
+ cookieModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
+ }
+ }
+
+ if (requestModel.Params != null)
+ {
+ foreach (var paramModel in requestModel.Params.Where(c => c.Matchers != null))
+ {
+ bool ignoreCase = paramModel?.IgnoreCase ?? false;
+ requestBuilder = requestBuilder.WithParam(paramModel.Name, ignoreCase, paramModel.Matchers.Select(_matcherMapper.Map).OfType().ToArray());
+ }
+ }
+
+ if (requestModel.Body?.Matcher != null)
+ {
+ requestBuilder = requestBuilder.WithBody(_matcherMapper.Map(requestModel.Body.Matcher));
+ }
+ else if (requestModel.Body?.Matchers != null)
+ {
+ requestBuilder = requestBuilder.WithBody(_matcherMapper.Map(requestModel.Body.Matchers));
+ }
+
+ return requestBuilder;
+ }
+
+ private IResponseBuilder InitResponseBuilder(ResponseModel responseModel)
+ {
+ IResponseBuilder responseBuilder = Response.Create();
+
+ if (responseModel.Delay > 0)
+ {
+ responseBuilder = responseBuilder.WithDelay(responseModel.Delay.Value);
+ }
+
+ if (responseModel.UseTransformer == true)
+ {
+ responseBuilder = responseBuilder.WithTransformer(responseModel.UseTransformerForBodyAsFile == true);
+ }
+
+ if (!string.IsNullOrEmpty(responseModel.ProxyUrl))
+ {
+ var proxyAndRecordSettings = new ProxyAndRecordSettings
+ {
+ Url = responseModel.ProxyUrl,
+ ClientX509Certificate2ThumbprintOrSubjectName = responseModel.X509Certificate2ThumbprintOrSubjectName,
+ WebProxySettings = responseModel.WebProxy != null ? new WebProxySettings
+ {
+ Address = responseModel.WebProxy.Address,
+ UserName = responseModel.WebProxy.UserName,
+ Password = responseModel.WebProxy.Password
+ } : null
+ };
+
+ return responseBuilder.WithProxy(proxyAndRecordSettings);
+ }
+
+ if (responseModel.StatusCode is string statusCodeAsString)
+ {
+ responseBuilder = responseBuilder.WithStatusCode(statusCodeAsString);
+ }
+ else if (responseModel.StatusCode != null)
+ {
+ // Convert to Int32 because Newtonsoft deserializes an 'object' with a number value to a long.
+ responseBuilder = responseBuilder.WithStatusCode(Convert.ToInt32(responseModel.StatusCode));
+ }
+
+ if (responseModel.Headers != null)
+ {
+ foreach (var entry in responseModel.Headers)
+ {
+ responseBuilder = entry.Value is string value ?
+ responseBuilder.WithHeader(entry.Key, value) :
+ responseBuilder.WithHeader(entry.Key, JsonUtils.ParseJTokenToObject(entry.Value));
+ }
+ }
+ else if (responseModel.HeadersRaw != null)
+ {
+ foreach (string headerLine in responseModel.HeadersRaw.Split(new[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ int indexColon = headerLine.IndexOf(":", StringComparison.Ordinal);
+ string key = headerLine.Substring(0, indexColon).TrimStart(' ', '\t');
+ string value = headerLine.Substring(indexColon + 1).TrimStart(' ', '\t');
+ responseBuilder = responseBuilder.WithHeader(key, value);
+ }
+ }
+
+ if (responseModel.BodyAsBytes != null)
+ {
+ responseBuilder = responseBuilder.WithBody(responseModel.BodyAsBytes, responseModel.BodyDestination, ToEncoding(responseModel.BodyEncoding));
+ }
+ else if (responseModel.Body != null)
+ {
+ responseBuilder = responseBuilder.WithBody(responseModel.Body, responseModel.BodyDestination, ToEncoding(responseModel.BodyEncoding));
+ }
+ else if (responseModel.BodyAsJson != null)
+ {
+ responseBuilder = responseBuilder.WithBodyAsJson(responseModel.BodyAsJson, ToEncoding(responseModel.BodyEncoding), responseModel.BodyAsJsonIndented == true);
+ }
+ else if (responseModel.BodyAsFile != null)
+ {
+ responseBuilder = responseBuilder.WithBodyFromFile(responseModel.BodyAsFile);
+ }
+
+ if (responseModel.Fault != null && Enum.TryParse(responseModel.Fault.Type, out FaultType faultType))
+ {
+ responseBuilder.WithFault(faultType, responseModel.Fault.Percentage);
+ }
+
+ return responseBuilder;
+ }
+
+ private ResponseMessage ToJson(T result, bool keepNullValues = false)
+ {
+ return new ResponseMessage
+ {
+ BodyData = new BodyData
+ {
+ DetectedBodyType = BodyType.String,
+ BodyAsString = JsonConvert.SerializeObject(result, keepNullValues ? _settingsIncludeNullValues : _jsonSerializerSettings)
+ },
+ StatusCode = (int)HttpStatusCode.OK,
+ Headers = new Dictionary> { { HttpKnownHeaderNames.ContentType, new WireMockList(ContentTypeJson) } }
+ };
+ }
+
+ private Encoding ToEncoding(EncodingModel encodingModel)
+ {
+ return encodingModel != null ? Encoding.GetEncoding(encodingModel.CodePage) : null;
+ }
+
+ private T DeserializeObject(RequestMessage requestMessage)
+ {
+ if (requestMessage?.BodyData?.DetectedBodyType == BodyType.String)
+ {
+ return JsonUtils.DeserializeObject(requestMessage.BodyData.BodyAsString);
+ }
+
+ if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
+ {
+ return ((JObject)requestMessage.BodyData.BodyAsJson).ToObject();
+ }
+
+ return default(T);
+ }
+
+ private T[] DeserializeRequestMessageToArray(RequestMessage requestMessage)
+ {
+ if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
+ {
+ var bodyAsJson = requestMessage.BodyData.BodyAsJson;
+
+ return DeserializeObjectToArray(bodyAsJson);
+ }
+
+ return default(T[]);
+ }
+
+ private T[] DeserializeObjectToArray(object value)
+ {
+ if (value is JArray jArray)
+ {
+ return jArray.ToObject();
+ }
+
+ var singleResult = ((JObject)value).ToObject();
+ return new[] { singleResult };
+ }
+
+ private T[] DeserializeJsonToArray(string value)
+ {
+ return DeserializeObjectToArray(JsonUtils.DeserializeObject(value));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Server/WireMockServer.LogEntries.cs b/src/WireMock.Net/Server/WireMockServer.LogEntries.cs
index 002fb46b..ee27b497 100644
--- a/src/WireMock.Net/Server/WireMockServer.LogEntries.cs
+++ b/src/WireMock.Net/Server/WireMockServer.LogEntries.cs
@@ -1,93 +1,91 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Collections.Specialized;
-using System.Linq;
-using JetBrains.Annotations;
-using WireMock.Logging;
-using WireMock.Matchers;
-using WireMock.Matchers.Request;
-
-namespace WireMock.Server
-{
- public partial class WireMockServer
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Linq;
+using JetBrains.Annotations;
+using WireMock.Logging;
+using WireMock.Matchers;
+using WireMock.Matchers.Request;
+
+namespace WireMock.Server
+{
+ public partial class WireMockServer
{
- ///
- [PublicAPI]
- public event NotifyCollectionChangedEventHandler LogEntriesChanged
- {
- add
- {
- _options.LogEntries.CollectionChanged += (sender, eventRecordArgs) =>
- {
- try
- {
- value(sender, eventRecordArgs);
- }
- catch (Exception exception)
- {
- _options.Logger.Error("Error calling the LogEntriesChanged event handler: {0}", exception.Message);
- }
- };
- }
-
- remove => _options.LogEntries.CollectionChanged -= value;
+ ///
+ [PublicAPI]
+ public event NotifyCollectionChangedEventHandler LogEntriesChanged
+ {
+ add
+ {
+ _options.LogEntries.CollectionChanged += (sender, eventRecordArgs) =>
+ {
+ try
+ {
+ value(sender, eventRecordArgs);
+ }
+ catch (Exception exception)
+ {
+ _options.Logger.Error("Error calling the LogEntriesChanged event handler: {0}", exception.Message);
+ }
+ };
+ }
+
+ remove => _options.LogEntries.CollectionChanged -= value;
}
- ///
- /// Gets the request logs.
- ///
- [PublicAPI]
- public IEnumerable LogEntries => new ReadOnlyCollection(_options.LogEntries.ToList());
+ ///
+ [PublicAPI]
+ public IEnumerable LogEntries => new ReadOnlyCollection(_options.LogEntries.ToList());
- ///
- /// The search log-entries based on matchers.
- ///
- /// The matchers.
- /// The .
- [PublicAPI]
- public IEnumerable FindLogEntries([NotNull] params IRequestMatcher[] matchers)
- {
- var results = new Dictionary();
-
- foreach (var log in _options.LogEntries.ToList())
- {
- var requestMatchResult = new RequestMatchResult();
- foreach (var matcher in matchers)
- {
- matcher.GetMatchingScore(log.RequestMessage, requestMatchResult);
- }
-
- if (requestMatchResult.AverageTotalScore > MatchScores.AlmostPerfect)
- {
- results.Add(log, requestMatchResult);
- }
- }
-
- return new ReadOnlyCollection(results.OrderBy(x => x.Value).Select(x => x.Key).ToList());
+ ///
+ /// The search log-entries based on matchers.
+ ///
+ /// The matchers.
+ /// The .
+ [PublicAPI]
+ public IEnumerable FindLogEntries([NotNull] params IRequestMatcher[] matchers)
+ {
+ var results = new Dictionary();
+
+ foreach (var log in _options.LogEntries.ToList())
+ {
+ var requestMatchResult = new RequestMatchResult();
+ foreach (var matcher in matchers)
+ {
+ matcher.GetMatchingScore(log.RequestMessage, requestMatchResult);
+ }
+
+ if (requestMatchResult.AverageTotalScore > MatchScores.AlmostPerfect)
+ {
+ results.Add(log, requestMatchResult);
+ }
+ }
+
+ return new ReadOnlyCollection(results.OrderBy(x => x.Value).Select(x => x.Key).ToList());
}
- ///
- [PublicAPI]
- public void ResetLogEntries()
- {
- _options.LogEntries.Clear();
+ ///
+ [PublicAPI]
+ public void ResetLogEntries()
+ {
+ _options.LogEntries.Clear();
}
- ///
- [PublicAPI]
- public bool DeleteLogEntry(Guid guid)
- {
- // Check a logentry exists with the same GUID, if so, remove it.
- var existing = _options.LogEntries.ToList().FirstOrDefault(m => m.Guid == guid);
- if (existing != null)
- {
- _options.LogEntries.Remove(existing);
- return true;
- }
-
- return false;
- }
- }
+ ///
+ [PublicAPI]
+ public bool DeleteLogEntry(Guid guid)
+ {
+ // Check a logentry exists with the same GUID, if so, remove it.
+ var existing = _options.LogEntries.ToList().FirstOrDefault(m => m.Guid == guid);
+ if (existing != null)
+ {
+ _options.LogEntries.Remove(existing);
+ return true;
+ }
+
+ return false;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Util/BodyData.cs b/src/WireMock.Net/Util/BodyData.cs
index 50c8d1d7..1e7d54e0 100644
--- a/src/WireMock.Net/Util/BodyData.cs
+++ b/src/WireMock.Net/Util/BodyData.cs
@@ -6,56 +6,36 @@ namespace WireMock.Util
///
/// BodyData
///
- public class BodyData
+ public class BodyData : IBodyData
{
- ///
- /// The body encoding.
- ///
+ ///
public Encoding Encoding { get; set; }
- ///
- /// The body as string, this is defined when BodyAsString or BodyAsJson are not null.
- ///
+ ///
public string BodyAsString { get; set; }
- ///
- /// The body (as JSON object).
- ///
+ ///
public object BodyAsJson { get; set; }
- ///
- /// The body (as bytearray).
- ///
+ ///
public byte[] BodyAsBytes { get; set; }
- ///
- /// Gets or sets a value indicating whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings.
- ///
+ ///
public bool? BodyAsJsonIndented { get; set; }
- ///
- /// Gets or sets the body as a file.
- ///
+ ///
public string BodyAsFile { get; set; }
- ///
- /// Is the body as file cached?
- ///
+ ///
public bool? BodyAsFileIsCached { get; set; }
- ///
- /// The detected body type (detection based on body content).
- ///
+ ///
public BodyType DetectedBodyType { get; set; }
- ///
- /// The detected body type (detection based on Content-Type).
- ///
+ ///
public BodyType DetectedBodyTypeFromContentType { get; set; }
- ///
- /// The detected compression.
- ///
+ ///
public string DetectedCompression { get; set; }
}
}
\ No newline at end of file