diff --git a/examples/WireMock.Net.ConsoleApplication/App.config b/examples/WireMock.Net.ConsoleApplication/App.config
index 88fa4027..71a06ba3 100644
--- a/examples/WireMock.Net.ConsoleApplication/App.config
+++ b/examples/WireMock.Net.ConsoleApplication/App.config
@@ -1,6 +1,14 @@
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/WireMock.Net.ConsoleApplication/Program.cs b/examples/WireMock.Net.ConsoleApplication/Program.cs
index 42401af4..b4f808cc 100644
--- a/examples/WireMock.Net.ConsoleApplication/Program.cs
+++ b/examples/WireMock.Net.ConsoleApplication/Program.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using Newtonsoft.Json;
using WireMock.Matchers;
using WireMock.RequestBuilders;
@@ -20,62 +21,64 @@ namespace WireMock.Net.ConsoleApplication
server.AllowPartialMapping();
- //server
- // .Given(Request.Create().WithPath(p => p.Contains("x")).UsingGet())
- // .AtPriority(4)
- // .RespondWith(Response.Create()
- // .WithStatusCode(200)
- // .WithHeader("Content-Type", "application/json")
- // .WithBody(@"{ ""result"": ""Contains x with FUNC 200""}"));
-
- //server
- // .Given(Request.Create().WithPath("/data").UsingPost().WithBody(b => b.Contains("e")))
- // .RespondWith(Response.Create()
- // .WithStatusCode(201)
- // .WithHeader("Content-Type", "application/json")
- // .WithBody(@"{ ""result"": ""data posted with FUNC 201""}"));
-
- //server
- // .Given(Request.Create().WithPath("/data", "/ax").UsingPost().WithHeader("Content-Type", "application/json*"))
- // .RespondWith(Response.Create()
- // .WithStatusCode(201)
- // .WithHeader("Content-Type", "application/json")
- // .WithBody(@"{ ""result"": ""data posted with 201""}"));
-
- //server
- // .Given(Request.Create().WithPath("/json").UsingPost().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]")))
- // .RespondWith(Response.Create()
- // .WithStatusCode(201)
- // .WithHeader("Content-Type", "application/json")
- // .WithBody(@"{ ""result"": ""json posted with 201""}"));
-
- //server
- // .Given(Request.Create().WithPath("/json2").UsingPost().WithBody("x"))
- // .RespondWith(Response.Create()
- // .WithStatusCode(201)
- // .WithHeader("Content-Type", "application/json")
- // .WithBody(@"{ ""result"": ""json posted with x - 201""}"));
-
- //server
- // .Given(Request.Create().WithPath("/data").UsingDelete())
- // .RespondWith(Response.Create()
- // .WithStatusCode(200)
- // .WithHeader("Content-Type", "application/json")
- // .WithBody(@"{ ""result"": ""data deleted with 200""}"));
-
- //server
- // .Given(Request.Create().WithPath("/nobody").UsingGet())
- // .RespondWith(Response.Create().WithDelay(TimeSpan.FromSeconds(1))
- // .WithStatusCode(200));
+ server
+ .Given(Request.Create().WithPath(p => p.Contains("x")).UsingGet())
+ .AtPriority(4)
+ .RespondWith(Response.Create()
+ .WithStatusCode(200)
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(@"{ ""result"": ""Contains x with FUNC 200""}"));
server
- .Given(Request.Create().WithPath("/partial").UsingGet().WithHeader("p", "p"))
+ .Given(Request.Create().WithPath("/data").UsingPost().WithBody(b => b.Contains("e")))
+ .AtPriority(999)
+ .RespondWith(Response.Create()
+ .WithStatusCode(201)
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(@"{ ""result"": ""data posted with FUNC 201""}"));
+
+ server
+ .Given(Request.Create().WithPath("/data", "/ax").UsingPost().WithHeader("Content-Type", "application/json*"))
+ .RespondWith(Response.Create()
+ .WithStatusCode(201)
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(@"{ ""result"": ""data posted with 201""}"));
+
+ server
+ .Given(Request.Create().WithPath("/json").UsingPost().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]")))
+ .RespondWith(Response.Create()
+ .WithStatusCode(201)
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(@"{ ""result"": ""json posted with 201""}"));
+
+ server
+ .Given(Request.Create().WithPath("/json2").UsingPost().WithBody("x"))
+ .RespondWith(Response.Create()
+ .WithStatusCode(201)
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(@"{ ""result"": ""json posted with x - 201""}"));
+
+ server
+ .Given(Request.Create().WithPath("/data").UsingDelete())
+ .RespondWith(Response.Create()
+ .WithStatusCode(200)
+ .WithHeader("Content-Type", "application/json")
+ .WithBody(@"{ ""result"": ""data deleted with 200""}"));
+
+ server
+ .Given(Request.Create().WithPath("/nobody").UsingGet())
+ .RespondWith(Response.Create().WithDelay(TimeSpan.FromSeconds(1))
+ .WithStatusCode(200));
+
+ server
+ .Given(Request.Create().WithPath("/partial").UsingPost().WithBody(new SimMetricsMatcher("cat")))
.RespondWith(Response.Create().WithStatusCode(200).WithBody("partial = 200"));
// http://localhost:8080/any/any?start=1000&stop=1&stop=2
server
.Given(Request.Create().WithPath("/*").UsingGet())
.WithGuid(Guid.Parse("90356dba-b36c-469a-a17e-669cd84f1f05"))
+ .AtPriority(server.Mappings.Count() + 1)
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
diff --git a/examples/WireMock.Net.ConsoleApplication/WireMock.Net.ConsoleApplication.csproj b/examples/WireMock.Net.ConsoleApplication/WireMock.Net.ConsoleApplication.csproj
index ca45c1da..03c13115 100644
--- a/examples/WireMock.Net.ConsoleApplication/WireMock.Net.ConsoleApplication.csproj
+++ b/examples/WireMock.Net.ConsoleApplication/WireMock.Net.ConsoleApplication.csproj
@@ -37,6 +37,10 @@
..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
True
+
+ ..\..\packages\SimMetrics.Net.1.0.1.0\lib\net45\SimMetrics.Net.dll
+ True
+
diff --git a/examples/WireMock.Net.ConsoleApplication/packages.config b/examples/WireMock.Net.ConsoleApplication/packages.config
index 9d64bf36..c18085ec 100644
--- a/examples/WireMock.Net.ConsoleApplication/packages.config
+++ b/examples/WireMock.Net.ConsoleApplication/packages.config
@@ -1,4 +1,5 @@
+
\ No newline at end of file
diff --git a/src/WireMock.Net/Admin/Requests/LogEntryModel.cs b/src/WireMock.Net/Admin/Requests/LogEntryModel.cs
index e1a58808..76e7a6ea 100644
--- a/src/WireMock.Net/Admin/Requests/LogEntryModel.cs
+++ b/src/WireMock.Net/Admin/Requests/LogEntryModel.cs
@@ -31,6 +31,14 @@ namespace WireMock.Admin.Requests
///
public LogResponseModel Response { get; set; }
+ ///
+ /// Gets or sets the mapping unique identifier.
+ ///
+ ///
+ /// The mapping unique identifier.
+ ///
+ public Guid? MappingGuid { get; set; }
+
///
/// Gets or sets the request match result.
///
diff --git a/src/WireMock.Net/Logging/LogEntry.cs b/src/WireMock.Net/Logging/LogEntry.cs
index a2f0c8cd..35c9d01c 100644
--- a/src/WireMock.Net/Logging/LogEntry.cs
+++ b/src/WireMock.Net/Logging/LogEntry.cs
@@ -39,5 +39,13 @@ namespace WireMock.Logging
/// The request match result.
///
public RequestMatchResult RequestMatchResult { get; set; }
+
+ ///
+ /// Gets or sets the mapping unique identifier.
+ ///
+ ///
+ /// The mapping unique identifier.
+ ///
+ public Guid? MappingGuid { get; set; }
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Matchers/SimMetricsMatcher.cs b/src/WireMock.Net/Matchers/SimMetricsMatcher.cs
index 74f09d3a..c4c98ee0 100644
--- a/src/WireMock.Net/Matchers/SimMetricsMatcher.cs
+++ b/src/WireMock.Net/Matchers/SimMetricsMatcher.cs
@@ -108,7 +108,7 @@ namespace WireMock.Matchers
/// Name
public string GetName()
{
- return $"SimMetricsMatcher ({_simMetricType})";
+ return $"SimMetricsMatcher.{_simMetricType}";
}
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs
index a0e63fc3..28497ee3 100644
--- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs
+++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs
@@ -4,6 +4,7 @@ using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using SimMetrics.Net;
using WireMock.Admin.Mappings;
using WireMock.Admin.Requests;
using WireMock.Logging;
@@ -11,6 +12,7 @@ using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
+using WireMock.Util;
namespace WireMock.Server
{
@@ -203,11 +205,12 @@ namespace WireMock.Server
BodyOriginal = logEntry.ResponseMessage.BodyOriginal,
Headers = logEntry.ResponseMessage.Headers
},
- RequestMatchResult = new LogRequestMatchModel
+ MappingGuid = logEntry.MappingGuid,
+ RequestMatchResult = logEntry.RequestMatchResult != null ? new LogRequestMatchModel
{
MatchScore = logEntry.RequestMatchResult.MatchScore,
Total = logEntry.RequestMatchResult.Total
- }
+ } : null
};
}
@@ -222,26 +225,31 @@ namespace WireMock.Server
private IRequestBuilder InitRequestBuilder(MappingModel mappingModel)
{
IRequestBuilder requestBuilder = Request.Create();
- string path = mappingModel.Request.Path as string;
- if (path != null)
- requestBuilder = requestBuilder.WithPath(path);
- else
+
+ if (mappingModel.Request.Path != null)
{
- JToken pathToken = (JToken)mappingModel.Request.Path;
- PathModel pathModel = pathToken.ToObject();
- if (pathModel?.Matchers != null)
- requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(Map).ToArray());
+ string path = mappingModel.Request.Path as string;
+ if (path != null)
+ requestBuilder = requestBuilder.WithPath(path);
+ else
+ {
+ var pathModel = JsonUtils.ParseJTokenToObject(mappingModel.Request.Path);
+ if (pathModel?.Matchers != null)
+ requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(Map).ToArray());
+ }
}
- string url = mappingModel.Request.Url as string;
- if (url != null)
- requestBuilder = requestBuilder.WithUrl(url);
- else
+ if (mappingModel.Request.Url != null)
{
- JToken urlToken = (JToken)mappingModel.Request.Url;
- UrlModel urlModel = urlToken.ToObject();
- if (urlModel?.Matchers != null)
- requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(Map).ToArray());
+ string url = mappingModel.Request.Url as string;
+ if (url != null)
+ requestBuilder = requestBuilder.WithUrl(url);
+ else
+ {
+ var urlModel = JsonUtils.ParseJTokenToObject(mappingModel.Request.Url);
+ if (urlModel?.Matchers != null)
+ requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(Map).ToArray());
+ }
}
if (mappingModel.Request.Methods != null)
@@ -412,7 +420,11 @@ namespace WireMock.Server
if (matcher == null)
return null;
- switch (matcher.Name)
+ var parts = matcher.Name.Split('.');
+ string matcherName = parts[0];
+ string matcherType = parts.Length > 1 ? parts[1] : null;
+
+ switch (matcherName)
{
case "RegexMatcher":
return new RegexMatcher(matcher.Pattern);
@@ -423,8 +435,18 @@ namespace WireMock.Server
case "XPathMatcher":
return new XPathMatcher(matcher.Pattern);
- default:
+ case "WildcardMatcher":
return new WildcardMatcher(matcher.Pattern, matcher.IgnoreCase == true);
+
+ case "SimMetricsMatcher":
+ SimMetricType type = SimMetricType.Levenstein;
+ if (!string.IsNullOrEmpty(matcherType) && !Enum.TryParse(matcherType, out type))
+ throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported.");
+
+ return new SimMetricsMatcher(matcher.Pattern, type);
+
+ default:
+ throw new NotSupportedException($"Matcher '{matcherName}' is not supported.");
}
}
diff --git a/src/WireMock.Net/Server/FluentMockServer.cs b/src/WireMock.Net/Server/FluentMockServer.cs
index 8967fc30..56ea4bab 100644
--- a/src/WireMock.Net/Server/FluentMockServer.cs
+++ b/src/WireMock.Net/Server/FluentMockServer.cs
@@ -331,6 +331,7 @@ namespace WireMock.Server
var request = _requestMapper.Map(ctx.Request);
ResponseMessage response = null;
+ Mapping targetMapping = null;
RequestMatchResult requestMatchResult = null;
try
{
@@ -338,15 +339,19 @@ namespace WireMock.Server
.Select(m => new { Mapping = m, MatchResult = m.IsRequestHandled(request) })
.ToList();
- Mapping targetMapping;
if (_allowPartialMapping)
{
var orderedMappings = possibleMatchingMappings
- .OrderBy(m => m.Mapping.Priority)
- .ThenBy(m => m.MatchResult)
+ .Where(pm =>
+ (pm.Mapping.Provider is DynamicResponseProvider && pm.MatchResult.IsPerfectMatch) ||
+ !(pm.Mapping.Provider is DynamicResponseProvider)
+ )
+ .OrderBy(m => m.MatchResult)
+ .ThenBy(m => m.Mapping.Priority)
.ToList();
var bestPartialMatch = orderedMappings.FirstOrDefault();
+
targetMapping = bestPartialMatch?.Mapping;
requestMatchResult = bestPartialMatch?.MatchResult;
}
@@ -388,6 +393,7 @@ namespace WireMock.Server
Guid = Guid.NewGuid(),
RequestMessage = request,
ResponseMessage = response,
+ MappingGuid = targetMapping?.Guid,
RequestMatchResult = requestMatchResult
};
diff --git a/src/WireMock.Net/Util/JsonUtils.cs b/src/WireMock.Net/Util/JsonUtils.cs
new file mode 100644
index 00000000..3d80c89f
--- /dev/null
+++ b/src/WireMock.Net/Util/JsonUtils.cs
@@ -0,0 +1,19 @@
+using Newtonsoft.Json.Linq;
+
+namespace WireMock.Util
+{
+ internal static class JsonUtils
+ {
+ public static T ParseJTokenToObject(object value)
+ {
+ if (value == null)
+ return default(T);
+
+ JToken token = value as JToken;
+ if (token == null)
+ return default(T);
+
+ return token.ToObject();
+ }
+ }
+}
\ No newline at end of file