merge netstandard into main (#26)

* #23

* #23 "Newtonsoft.Json" Version="10.0.2"

* owin

* AspNetCore

* Fix appveyor build

* fix start/stop in untitests
This commit is contained in:
Stef Heyenrath
2017-04-26 21:28:12 +02:00
committed by GitHub
parent 0f8f9c508f
commit 453cef90e5
106 changed files with 17753 additions and 24342 deletions

View File

@@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyTitle>WireMock.Net.Logic</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net45;netstandard1.3</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.Logic</AssemblyName>
<DebugType>full</DebugType>
<ApplicationIcon>../WireMock.Net-Logo.ico</ApplicationIcon>
<Version>1.0.2.0</Version>
<RootNamespace>WireMock</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<DefineConstants>NETSTANDARD</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="10.4.0">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="SimMetrics.Net" Version="1.0.3" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.3" />
<PackageReference Include="Handlebars.Net" Version="1.8.0" />
<PackageReference Include="XPath2" Version="1.0.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="1.1.1" />
<!--<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="1.1.1" />-->
<PackageReference Include="Handlebars.NetStandard" Version="1.8.1" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="System.Threading.Tasks" Version="4.3.0" />
<PackageReference Include="System.Threading.Thread">
<Version>4.3.0</Version>
</PackageReference>
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,49 @@
namespace WireMock.Net
{
/// <summary>
/// WireMockSettings
/// </summary>
public class WireMockSettings
{
/// <summary>
/// Gets or sets the port.
/// </summary>
/// <value>
/// The port.
/// </value>
public int? Port { get; set; }
/// <summary>
/// Gets or sets the use SSL.
/// </summary>
/// <value>
/// The use SSL.
/// </value>
// ReSharper disable once InconsistentNaming
public bool? UseSSL { get; set; }
/// <summary>
/// Gets or sets the start admin interface.
/// </summary>
/// <value>
/// The start admin interface.
/// </value>
public bool? StartAdminInterface { get; set; }
/// <summary>
/// Gets or sets the read static mappings.
/// </summary>
/// <value>
/// The read static mappings.
/// </value>
public bool? ReadStaticMappings { get; set; }
/// <summary>
/// Gets or sets the urls.
/// </summary>
/// <value>
/// The urls.
/// </value>
public string[] Urls { get; set; }
}
}

View File

@@ -0,0 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>WireMock.Net Owin Middleware.</Description>
<Version>1.0.0.0</Version>
<AssemblyTitle>WireMock.Net</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net45;netstandard1.3</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.Middleware</AssemblyName>
<PackageId>WireMock.Net.Middleware</PackageId>
<PackageTags>tdd;mock;http;wiremock;test;server;unittest</PackageTags>
<PackageReleaseNotes>Initial version</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/StefH/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/StefH/WireMock.Net</PackageProjectUrl>
<PackageLicenseUrl>https://raw.githubusercontent.com/StefH/WireMock.Net/master/LICENSE</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/StefH/WireMock.Net</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<DebugType>full</DebugType>
<ApplicationIcon>../WireMock.Net-Logo.ico</ApplicationIcon>
<RootNamespace>WireMock</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<DefineConstants>NETSTANDARD</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="10.4.0">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<!--<PackageReference Include="SimMetrics.Net" Version="1.0.3" />-->
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.3" />
<PackageReference Include="Handlebars.Net" Version="1.8.0" />
<PackageReference Include="XPath2" Version="1.0.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="Microsoft.AspNetCore.Owin" Version="1.1.1" />
<!--<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="1.1.1" />-->
<PackageReference Include="Handlebars.NetStandard" Version="1.8.1" />
<PackageReference Include="System.Threading" Version="4.3.0" />
<PackageReference Include="System.Threading.Tasks" Version="4.3.0" />
<PackageReference Include="System.Threading.Thread">
<Version>4.3.0</Version>
</PackageReference>
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections;
using System.Threading.Tasks;
using WireMock.Logging;
using WireMock.Matchers.Request;
using System.Linq;
#if NETSTANDARD
using Microsoft.AspNetCore.Http;
#else
using Microsoft.Owin;
#endif
namespace WireMock.Owin
{
#if NETSTANDARD
internal class WireMockMiddleware
#else
internal class WireMockMiddleware : OwinMiddleware
#endif
{
private static readonly Task CompletedTask = Task.FromResult(false);
private readonly WireMockMiddlewareOptions _options;
private readonly OwinRequestMapper _requestMapper = new OwinRequestMapper();
private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper();
#if NETSTANDARD
public WireMockMiddleware(RequestDelegate next, WireMockMiddlewareOptions options)
{
_options = options;
}
#else
public WireMockMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next)
{
_options = options;
}
#endif
#if NETSTANDARD
public async Task Invoke(HttpContext ctx)
#else
public override async Task Invoke(IOwinContext ctx)
#endif
{
if (_options.RequestProcessingDelay > TimeSpan.Zero)
{
await Task.Delay(_options.RequestProcessingDelay.Value);
// Thread.Sleep(_options.RequestProcessingDelay.Value);
}
var request = await _requestMapper.MapAsync(ctx.Request);
ResponseMessage response = null;
Mapping targetMapping = null;
RequestMatchResult requestMatchResult = null;
try
{
var mappings = _options.Mappings
.Select(m => new
{
Mapping = m,
MatchResult = m.IsRequestHandled(request)
})
.ToList();
if (_options.AllowPartialMapping)
{
var partialMappings = mappings
.Where(pm => pm.Mapping.IsAdminInterface && pm.MatchResult.IsPerfectMatch || !pm.Mapping.IsAdminInterface)
.OrderBy(m => m.MatchResult)
.ThenBy(m => m.Mapping.Priority)
.ToList();
var bestPartialMatch = partialMappings.FirstOrDefault(pm => pm.MatchResult.AverageTotalScore > 0.0);
targetMapping = bestPartialMatch?.Mapping;
requestMatchResult = bestPartialMatch?.MatchResult;
}
else
{
var perfectMatch = mappings
.OrderBy(m => m.Mapping.Priority)
.FirstOrDefault(m => m.MatchResult.IsPerfectMatch);
targetMapping = perfectMatch?.Mapping;
requestMatchResult = perfectMatch?.MatchResult;
}
if (targetMapping == null)
{
response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" };
return;
}
if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null)
{
string authorization;
bool present = request.Headers.TryGetValue("Authorization", out authorization);
if (!present || _options.AuthorizationMatcher.IsMatch(authorization) < 1.0)
{
response = new ResponseMessage { StatusCode = 401 };
return;
}
}
response = await targetMapping.ResponseTo(request);
}
catch (Exception ex)
{
response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() };
}
finally
{
var log = new LogEntry
{
Guid = Guid.NewGuid(),
RequestMessage = request,
ResponseMessage = response,
MappingGuid = targetMapping?.Guid,
MappingTitle = targetMapping?.Title,
RequestMatchResult = requestMatchResult
};
LogRequest(log);
await _responseMapper.MapAsync(response, ctx.Response);
}
await CompletedTask;
}
/// <summary>
/// The log request.
/// </summary>
/// <param name="entry">The request.</param>
private void LogRequest(LogEntry entry)
{
lock (((ICollection)_options.LogEntries).SyncRoot)
{
_options.LogEntries.Add(entry);
}
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CommandLineParser.Arguments;
using CommandLineParser.Exceptions;
using WireMock.Server;
namespace WireMock.Net.StandAlone.NETCoreApp
{
class Program
{
private class Options
{
[ValueArgument(typeof(string), 'u', "Urls", Description = "URL(s) to listen on.", Optional = true, AllowMultiple = true)]
public List<string> Urls { get; set; }
[SwitchArgument('p', "AllowPartialMapping", true, Description = "Allow Partial Mapping (default set to true).", Optional = true)]
public bool AllowPartialMapping { get; set; }
[SwitchArgument('s', "StartAdminInterface", true, Description = "Start the AdminInterface (default set to true).", Optional = true)]
public bool StartAdminInterface { get; set; }
[SwitchArgument('r', "ReadStaticMappings", true, Description = "Read StaticMappings from ./__admin/mappings (default set to true).", Optional = true)]
public bool ReadStaticMappings { get; set; }
}
static void Main(string[] args)
{
var options = new Options();
var parser = new CommandLineParser.CommandLineParser();
parser.ExtractArgumentAttributes(options);
try
{
parser.ParseCommandLine(args);
if (!options.Urls.Any())
{
options.Urls.Add("http://localhost:9090/");
}
var server = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = options.Urls.ToArray(),
StartAdminInterface = options.StartAdminInterface,
ReadStaticMappings = options.ReadStaticMappings
});
if (options.AllowPartialMapping)
{
server.AllowPartialMapping();
}
Console.WriteLine("WireMock.Net server listening at {0}", string.Join(" and ", server.Urls));
}
catch (CommandLineException e)
{
Console.WriteLine(e.Message);
parser.ShowUsage();
}
Console.WriteLine("Press any key to stop the server");
Console.ReadKey();
}
}
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineArgumentsParser" Version="3.0.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net\WireMock.Net.csproj" />
</ItemGroup>
</Project>

View File

@@ -36,8 +36,11 @@
<ApplicationIcon>..\..\WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="CommandLineArgumentsParser, Version=3.0.7.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\CommandLineArgumentsParser.3.0.7\lib\net45\CommandLineArgumentsParser.dll</HintPath>
<Reference Include="CommandLineArgumentsParser, Version=3.0.9.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\CommandLineArgumentsParser.3.0.9\lib\net45\CommandLineArgumentsParser.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Host.HttpListener, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.3.1.0\lib\net45\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommandLineArgumentsParser" version="3.0.7" targetFramework="net452" />
<package id="CommandLineArgumentsParser" version="3.0.9" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="3.1.0" targetFramework="net452" />
</packages>

View File

@@ -1,63 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
namespace WireMock.Extensions
{
/// <summary>
/// Dictionary Extensions
/// </summary>
public static class DictionaryExtensions
{
/// <summary>
/// Converts IDictionary to an ExpandObject.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dictionary">The dictionary.</param>
/// <returns></returns>
public static dynamic ToExpandoObject<T>(this IDictionary<string, T> dictionary)
{
dynamic expando = new ExpandoObject();
var expandoDic = (IDictionary<string, object>)expando;
// go through the items in the dictionary and copy over the key value pairs)
foreach (var kvp in dictionary)
{
// if the value can also be turned into an ExpandoObject, then do it!
var value = kvp.Value as IDictionary<string, object>;
if (value != null)
{
var expandoValue = value.ToExpandoObject();
expandoDic.Add(kvp.Key, expandoValue);
}
else if (kvp.Value is ICollection)
{
// iterate through the collection and convert any strin-object dictionaries
// along the way into expando objects
var itemList = new List<object>();
foreach (var item in (ICollection)kvp.Value)
{
var objects = item as IDictionary<string, object>;
if (objects != null)
{
var expandoItem = objects.ToExpandoObject();
itemList.Add(expandoItem);
}
else
{
itemList.Add(item);
}
}
expandoDic.Add(kvp.Key, itemList);
}
else
{
expandoDic.Add(kvp.Key, kvp.Value);
}
}
return expando;
}
}
}

View File

@@ -0,0 +1,65 @@
//using System;
//using System.Collections.Generic;
//using System.IO;
//using System.Linq;
//using System.Net;
//using System.Text;
//#if NET45
//#else
//using System.Net.Http;
//#endif
//namespace WireMock.Http
//{
// /// <summary>
// /// The http listener request mapper.
// /// </summary>
// public class HttpListenerRequestMapperOld
// {
// /// <summary>
// /// The map.
// /// </summary>
// /// <param name="listenerRequest">The listener request.</param>
// /// <returns>The <see cref="RequestMessage"/>.</returns>
// public RequestMessage MapAsync(HttpListenerRequest listenerRequest)
// {
// Uri url = listenerRequest.Url;
// string verb = listenerRequest.HttpMethod;
// byte[] body = GetRequestBody(listenerRequest);
// Encoding bodyEncoding = body != null ? listenerRequest.ContentEncoding : null;
// string bodyAsString = bodyEncoding?.GetString(body);
// var listenerHeaders = listenerRequest.Headers;
// var headers = listenerHeaders.AllKeys.ToDictionary(k => k, k => listenerHeaders[k]);
// var cookies = new Dictionary<string, string>();
// foreach (Cookie cookie in listenerRequest.Cookies)
// cookies.Add(cookie.Name, cookie.Value);
// return new RequestMessage(url, verb, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now };
// }
// /// <summary>
// /// The get request body.
// /// </summary>
// /// <param name="request">The request.</param>
// /// <returns>The <see cref="string"/>.</returns>
// private byte[] GetRequestBody(HttpListenerRequest request)
// {
// if (!request.HasEntityBody)
// {
// return null;
// }
// using (var bodyStream = request.InputStream)
// {
// using (var memoryStream = new MemoryStream())
// {
// bodyStream.CopyTo(memoryStream);
// return memoryStream.ToArray();
// }
// }
// }
// }
//}

View File

@@ -0,0 +1,44 @@
//using System.Linq;
//using System.Net;
//using System.Text;
//#if NET45
//#else
//using System.Net.Http;
//#endif
//namespace WireMock.Http
//{
// /// <summary>
// /// The http listener response mapper.
// /// </summary>
// public class HttpListenerResponseMapperOld
// {
// private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
// /// <summary>
// /// The map.
// /// </summary>
// /// <param name="responseMessage">
// /// The response.
// /// </param>
// /// <param name="listenerResponse">The listenerResponse.</param>
// public void MapAsync(ResponseMessage responseMessage, HttpListenerResponse listenerResponse)
// {
// listenerResponse.StatusCode = responseMessage.StatusCode;
// responseMessage.Headers.ToList().ForEach(pair => listenerResponse.AddHeader(pair.Key, pair.Value));
// if (responseMessage.Body == null)
// return;
// var encoding = responseMessage.BodyEncoding ?? _utf8NoBom;
// byte[] buffer = encoding.GetBytes(responseMessage.Body);
// listenerResponse.ContentEncoding = encoding;
// listenerResponse.ContentLength64 = buffer.Length;
// listenerResponse.OutputStream.Write(buffer, 0, buffer.Length);
// listenerResponse.OutputStream.Flush();
// }
// }
//}

View File

@@ -1,113 +1,117 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Validation;
//using System;
//using System.Collections.Generic;
//#if NET45
//using System.Net;
//#else
//using System.Net.Http;
//#endif
//using System.Threading;
//using System.Threading.Tasks;
//using JetBrains.Annotations;
//using WireMock.Validation;
namespace WireMock.Http
{
/// <summary>
/// The tiny http server.
/// </summary>
public class TinyHttpServer
{
private readonly Action<HttpListenerContext, CancellationToken> _httpHandler;
//namespace WireMock.Http
//{
// /// <summary>
// /// The tiny http server.
// /// </summary>
// public class TinyHttpServerOld
// {
// private readonly Action<HttpListenerContext, CancellationToken> _httpHandler;
private readonly HttpListener _listener;
// private readonly HttpListener _listener;
private readonly CancellationTokenSource _cts;
// private readonly CancellationTokenSource _cts;
/// <summary>
/// Gets a value indicating whether this server is started.
/// </summary>
/// <value>
/// <c>true</c> if this server is started; otherwise, <c>false</c>.
/// </value>
public bool IsStarted { get; private set; }
// /// <summary>
// /// Gets a value indicating whether this server is started.
// /// </summary>
// /// <value>
// /// <c>true</c> if this server is started; otherwise, <c>false</c>.
// /// </value>
// public bool IsStarted { get; private set; }
/// <summary>
/// Gets the url.
/// </summary>
/// <value>
/// The urls.
/// </value>
[PublicAPI]
public List<Uri> Urls { get; } = new List<Uri>();
// /// <summary>
// /// Gets the url.
// /// </summary>
// /// <value>
// /// The urls.
// /// </value>
// [PublicAPI]
// public List<Uri> Urls { get; } = new List<Uri>();
/// <summary>
/// Gets the ports.
/// </summary>
/// <value>
/// The ports.
/// </value>
[PublicAPI]
public List<int> Ports { get; } = new List<int>();
// /// <summary>
// /// Gets the ports.
// /// </summary>
// /// <value>
// /// The ports.
// /// </value>
// [PublicAPI]
// public List<int> Ports { get; } = new List<int>();
/// <summary>
/// Initializes a new instance of the <see cref="TinyHttpServer"/> class.
/// </summary>
/// <param name="uriPrefixes">The uriPrefixes.</param>
/// <param name="httpHandler">The http handler.</param>
public TinyHttpServer([NotNull] Action<HttpListenerContext, CancellationToken> httpHandler, [NotNull] params string[] uriPrefixes)
{
Check.NotNull(httpHandler, nameof(httpHandler));
Check.NotEmpty(uriPrefixes, nameof(uriPrefixes));
// /// <summary>
// /// Initializes a new instance of the <see cref="TinyHttpServer"/> class.
// /// </summary>
// /// <param name="uriPrefixes">The uriPrefixes.</param>
// /// <param name="httpHandler">The http handler.</param>
// public TinyHttpServerOld([NotNull] Action<HttpListenerContext, CancellationToken> httpHandler, [NotNull] params string[] uriPrefixes)
// {
// Check.NotNull(httpHandler, nameof(httpHandler));
// Check.NotEmpty(uriPrefixes, nameof(uriPrefixes));
_cts = new CancellationTokenSource();
// _cts = new CancellationTokenSource();
_httpHandler = httpHandler;
// _httpHandler = httpHandler;
// Create a listener.
_listener = new HttpListener();
foreach (string uriPrefix in uriPrefixes)
{
var uri = new Uri(uriPrefix);
Urls.Add(uri);
Ports.Add(uri.Port);
// // Create a listener.
// _listener = new HttpListener();
// foreach (string uriPrefix in uriPrefixes)
// {
// var uri = new Uri(uriPrefix);
// Urls.Add(uri);
// Ports.Add(uri.Port);
_listener.Prefixes.Add(uriPrefix);
}
}
// _listener.Prefixes.Add(uriPrefix);
// }
// }
/// <summary>
/// Start the server.
/// </summary>
[PublicAPI]
public void Start()
{
_listener.Start();
// /// <summary>
// /// Start the server.
// /// </summary>
// [PublicAPI]
// public void Start()
// {
// _listener.Start();
IsStarted = true;
// IsStarted = true;
Task.Run(
async () =>
{
//using (_listener)
{
while (!_cts.Token.IsCancellationRequested)
{
HttpListenerContext context = await _listener.GetContextAsync();
_httpHandler(context, _cts.Token);
}
// Task.Run(
// async () =>
// {
// //using (_listener)
// {
// while (!_cts.Token.IsCancellationRequested)
// {
// HttpListenerContext context = await _listener.GetContextAsync();
// _httpHandler(context, _cts.Token);
// }
_listener.Stop();
IsStarted = false;
}
},
_cts.Token);
}
// _listener.Stop();
// IsStarted = false;
// }
// },
// _cts.Token);
// }
/// <summary>
/// Stop the server.
/// </summary>
[PublicAPI]
public void Stop()
{
_listener?.Stop();
// /// <summary>
// /// Stop the server.
// /// </summary>
// [PublicAPI]
// public void Stop()
// {
// _listener?.Stop();
_cts.Cancel();
}
}
}
// _cts.Cancel();
// }
// }
//}

View File

@@ -1,60 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace WireMock
{
/// <summary>
/// The http listener request mapper.
/// </summary>
public class HttpListenerRequestMapper
{
/// <summary>
/// The map.
/// </summary>
/// <param name="listenerRequest">The listener request.</param>
/// <returns>The <see cref="RequestMessage"/>.</returns>
public RequestMessage Map(HttpListenerRequest listenerRequest)
{
Uri url = listenerRequest.Url;
string verb = listenerRequest.HttpMethod;
byte[] body = GetRequestBody(listenerRequest);
Encoding bodyEncoding = body != null ? listenerRequest.ContentEncoding : null;
string bodyAsString = bodyEncoding?.GetString(body);
var listenerHeaders = listenerRequest.Headers;
var headers = listenerHeaders.AllKeys.ToDictionary(k => k, k => listenerHeaders[k]);
var cookies = new Dictionary<string, string>();
foreach (Cookie cookie in listenerRequest.Cookies)
cookies.Add(cookie.Name, cookie.Value);
return new RequestMessage(url, verb, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now };
}
/// <summary>
/// The get request body.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>The <see cref="string"/>.</returns>
private byte[] GetRequestBody(HttpListenerRequest request)
{
if (!request.HasEntityBody)
{
return null;
}
using (var bodyStream = request.InputStream)
{
using (var memoryStream = new MemoryStream())
{
bodyStream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
}
}
}

View File

@@ -1,39 +0,0 @@
using System.Linq;
using System.Net;
using System.Text;
namespace WireMock
{
/// <summary>
/// The http listener response mapper.
/// </summary>
public class HttpListenerResponseMapper
{
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
/// <summary>
/// The map.
/// </summary>
/// <param name="responseMessage">
/// The response.
/// </param>
/// <param name="listenerResponse">The listenerResponse.</param>
public void Map(ResponseMessage responseMessage, HttpListenerResponse listenerResponse)
{
listenerResponse.StatusCode = responseMessage.StatusCode;
responseMessage.Headers.ToList().ForEach(pair => listenerResponse.AddHeader(pair.Key, pair.Value));
if (responseMessage.Body == null)
return;
var encoding = responseMessage.BodyEncoding ?? _utf8NoBom;
byte[] buffer = encoding.GetBytes(responseMessage.Body);
listenerResponse.ContentEncoding = encoding;
listenerResponse.ContentLength64 = buffer.Length;
listenerResponse.OutputStream.Write(buffer, 0, buffer.Length);
listenerResponse.OutputStream.Flush();
}
}
}

View File

@@ -3,7 +3,9 @@ using System.Linq;
using System.Xml;
using JetBrains.Annotations;
using WireMock.Validation;
#if NET45
using Wmhelp.XPath2;
#endif
namespace WireMock.Matchers
{
@@ -39,8 +41,11 @@ namespace WireMock.Matchers
try
{
var nav = new XmlDocument { InnerXml = input }.CreateNavigator();
#if NET45
return MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.XPath2Evaluate($"boolean({p})"))));
#else
return MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.Evaluate($"boolean({p})"))));
#endif
}
catch (Exception)
{

View File

@@ -0,0 +1,100 @@
#if !NET45
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using WireMock.Validation;
namespace WireMock.Owin
{
internal class AspNetCoreSelfHost : IOwinSelfHost
{
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private readonly WireMockMiddlewareOptions _options;
private readonly string[] _uriPrefixes;
public bool IsStarted { get; private set; }
public List<Uri> Urls { get; } = new List<Uri>();
public List<int> Ports { get; } = new List<int>();
public AspNetCoreSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
{
Check.NotNull(options, nameof(options));
Check.NotEmpty(uriPrefixes, nameof(uriPrefixes));
foreach (string uriPrefix in uriPrefixes)
{
var uri = new Uri(uriPrefix);
Urls.Add(uri);
Ports.Add(uri.Port);
}
_options = options;
_uriPrefixes = uriPrefixes;
}
public Task StartAsync()
{
return Task.Run(() =>
{
var host = new WebHostBuilder()
.ConfigureLogging(factory => factory.AddConsole(LogLevel.None))
.Configure(appBuilder =>
{
// appBuilder.UseExceptionHandler(builder => )
appBuilder.UseMiddleware<WireMockMiddleware>(_options);
})
.UseKestrel()
.UseUrls(_uriPrefixes)
.Build();
host.Run(_cts.Token);
IsStarted = true;
}, _cts.Token);
}
public Task StopAsync()
{
_cts.Cancel();
IsStarted = false;
return Task.FromResult(true);
}
}
internal class Startup
{
public Startup(IHostingEnvironment env)
{
//var builder = new ConfigurationBuilder()
// .SetBasePath(env.ContentRootPath)
// .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
// .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
// .AddEnvironmentVariables();
//Configuration = builder.Build();
}
// public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseMiddleware<WireMockMiddleware>();
}
}
}
#endif

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace WireMock.Owin
{
interface IOwinSelfHost
{
/// <summary>
/// Gets a value indicating whether this server is started.
/// </summary>
/// <value>
/// <c>true</c> if this server is started; otherwise, <c>false</c>.
/// </value>
bool IsStarted { get; }
/// <summary>
/// Gets the url.
/// </summary>
/// <value>
/// The urls.
/// </value>
List<Uri> Urls { get; }
/// <summary>
/// Gets the ports.
/// </summary>
/// <value>
/// The ports.
/// </value>
List<int> Ports { get; }
Task StartAsync();
Task StopAsync();
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if NET45
using Microsoft.Owin;
#else
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Features;
#endif
namespace WireMock.Owin
{
/// <summary>
/// OwinRequestMapper
/// </summary>
public class OwinRequestMapper
{
/// <summary>
/// MapAsync IOwinRequest to RequestMessage
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<RequestMessage> MapAsync(
#if NET45
IOwinRequest request
#else
HttpRequest request
#endif
)
{
#if NET45
Uri url = request.Uri;
#else
Uri url = new Uri(request.GetEncodedUrl());
#endif
string verb = request.Method;
string bodyAsString = null;
byte[] body = null;
Encoding bodyEncoding = null;
if (request.Body != null)
{
using (var streamReader = new StreamReader(request.Body))
{
bodyAsString = await streamReader.ReadToEndAsync();
bodyEncoding = streamReader.CurrentEncoding;
}
body = bodyEncoding.GetBytes(bodyAsString);
}
var listenerHeaders = request.Headers;
var headers = new Dictionary<string, string>();
foreach (var header in listenerHeaders)
headers.Add(header.Key, header.Value.FirstOrDefault());
var cookies = new Dictionary<string, string>();
foreach (var cookie in request.Cookies)
cookies.Add(cookie.Key, cookie.Value);
return new RequestMessage(url, verb, body, bodyAsString, bodyEncoding, headers, cookies) { DateTime = DateTime.Now };
}
}
}

View File

@@ -0,0 +1,47 @@
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if NET45
using Microsoft.Owin;
#else
using Microsoft.AspNetCore.Http;
#endif
namespace WireMock.Owin
{
/// <summary>
/// OwinResponseMapper
/// </summary>
public class OwinResponseMapper
{
private readonly Encoding _utf8NoBom = new UTF8Encoding(false);
/// <summary>
/// MapAsync ResponseMessage to OwinResponse
/// </summary>
/// <param name="responseMessage"></param>
/// <param name="response"></param>
public async Task MapAsync(ResponseMessage responseMessage
#if NET45
, IOwinResponse response
#else
, HttpResponse response
#endif
)
{
response.StatusCode = responseMessage.StatusCode;
responseMessage.Headers.ToList().ForEach(pair => response.Headers.Append(pair.Key, pair.Value));
if (responseMessage.Body == null)
return;
Encoding encoding = responseMessage.BodyEncoding ?? _utf8NoBom;
using (var writer = new StreamWriter(response.Body, encoding))
{
await writer.WriteAsync(responseMessage.Body);
}
}
}
}

View File

@@ -0,0 +1,116 @@
#if NET45
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Validation;
using Owin;
using Microsoft.Owin.Hosting;
namespace WireMock.Owin
{
internal class OwinSelfHost : IOwinSelfHost
{
private readonly WireMockMiddlewareOptions _options;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private System.Threading.Thread _internalThread;
public OwinSelfHost([NotNull] WireMockMiddlewareOptions options, [NotNull] params string[] uriPrefixes)
{
Check.NotNull(options, nameof(options));
Check.NotEmpty(uriPrefixes, nameof(uriPrefixes));
foreach (string uriPrefix in uriPrefixes)
{
var uri = new Uri(uriPrefix);
Urls.Add(uri);
Ports.Add(uri.Port);
}
_options = options;
}
public bool IsStarted { get; private set; }
public List<Uri> Urls { get; } = new List<Uri>();
public List<int> Ports { get; } = new List<int>();
[PublicAPI]
public Task StartAsync()
{
return Task.Run(() =>
{
StartServers();
}, _cts.Token);
//if (_internalThread != null)
// throw new InvalidOperationException("Cannot start a multiple threads.");
//_internalThread = new Thread(ThreadWorkInternal);
//_internalThread.Start();
}
[PublicAPI]
public Task StopAsync()
{
_cts.Cancel();
var tcs = new TaskCompletionSource<bool>();
var timer = new System.Timers.Timer(999);
timer.Elapsed += (sender, e) =>
{
if (_internalThread == null)
{
timer.Stop();
tcs.SetResult(true);
}
};
timer.Start();
return tcs.Task;
}
private void ThreadWorkInternal()
{
try
{
StartServers();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
_internalThread = null;
}
}
private void StartServers()
{
Action<IAppBuilder> startup = app =>
{
app.Use<WireMockMiddleware>(_options);
};
var servers = new List<IDisposable>();
foreach (var url in Urls)
{
servers.Add(WebApp.Start(url.ToString(), startup));
}
IsStarted = true;
while (!_cts.IsCancellationRequested)
Thread.Sleep(1000);
IsStarted = false;
foreach (var server in servers)
server.Dispose();
}
}
}
#endif

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections;
using System.Threading.Tasks;
using WireMock.Logging;
using WireMock.Matchers.Request;
using System.Linq;
#if NET45
using Microsoft.Owin;
#else
using Microsoft.AspNetCore.Http;
#endif
namespace WireMock.Owin
{
#if NET45
internal class WireMockMiddleware : OwinMiddleware
#else
internal class WireMockMiddleware
#endif
{
private static readonly Task CompletedTask = Task.FromResult(false);
private readonly WireMockMiddlewareOptions _options;
private readonly OwinRequestMapper _requestMapper = new OwinRequestMapper();
private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper();
#if NET45
public WireMockMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next)
{
_options = options;
}
#else
public WireMockMiddleware(RequestDelegate next, WireMockMiddlewareOptions options)
{
_options = options;
}
#endif
#if NET45
public override async Task Invoke(IOwinContext ctx)
#else
public async Task Invoke(HttpContext ctx)
#endif
{
if (_options.RequestProcessingDelay > TimeSpan.Zero)
{
await Task.Delay(_options.RequestProcessingDelay.Value);
// Thread.Sleep(_options.RequestProcessingDelay.Value);
}
var request = await _requestMapper.MapAsync(ctx.Request);
ResponseMessage response = null;
Mapping targetMapping = null;
RequestMatchResult requestMatchResult = null;
try
{
var mappings = _options.Mappings
.Select(m => new
{
Mapping = m,
MatchResult = m.IsRequestHandled(request)
})
.ToList();
if (_options.AllowPartialMapping)
{
var partialMappings = mappings
.Where(pm => pm.Mapping.IsAdminInterface && pm.MatchResult.IsPerfectMatch || !pm.Mapping.IsAdminInterface)
.OrderBy(m => m.MatchResult)
.ThenBy(m => m.Mapping.Priority)
.ToList();
var bestPartialMatch = partialMappings.FirstOrDefault(pm => pm.MatchResult.AverageTotalScore > 0.0);
targetMapping = bestPartialMatch?.Mapping;
requestMatchResult = bestPartialMatch?.MatchResult;
}
else
{
var perfectMatch = mappings
.OrderBy(m => m.Mapping.Priority)
.FirstOrDefault(m => m.MatchResult.IsPerfectMatch);
targetMapping = perfectMatch?.Mapping;
requestMatchResult = perfectMatch?.MatchResult;
}
if (targetMapping == null)
{
response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" };
return;
}
if (targetMapping.IsAdminInterface && _options.AuthorizationMatcher != null)
{
string authorization;
bool present = request.Headers.TryGetValue("Authorization", out authorization);
if (!present || _options.AuthorizationMatcher.IsMatch(authorization) < 1.0)
{
response = new ResponseMessage { StatusCode = 401 };
return;
}
}
response = await targetMapping.ResponseTo(request);
}
catch (Exception ex)
{
response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() };
}
finally
{
var log = new LogEntry
{
Guid = Guid.NewGuid(),
RequestMessage = request,
ResponseMessage = response,
MappingGuid = targetMapping?.Guid,
MappingTitle = targetMapping?.Title,
RequestMatchResult = requestMatchResult
};
LogRequest(log);
await _responseMapper.MapAsync(response, ctx.Response);
}
await CompletedTask;
}
/// <summary>
/// The log request.
/// </summary>
/// <param name="entry">The request.</param>
private void LogRequest(LogEntry entry)
{
lock (((ICollection)_options.LogEntries).SyncRoot)
{
_options.LogEntries.Add(entry);
}
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using WireMock.Logging;
using WireMock.Matchers;
namespace WireMock.Owin
{
internal class WireMockMiddlewareOptions
{
public TimeSpan? RequestProcessingDelay { get; set; }
public IMatcher AuthorizationMatcher { get; set; }
public bool AllowPartialMapping { get; set; }
public IList<Mapping> Mappings { get; set; }
public IList<LogEntry> LogEntries { get; set; }
public WireMockMiddlewareOptions()
{
Mappings = new List<Mapping>();
LogEntries = new List<LogEntry>();
}
}
}

View File

@@ -16,7 +16,7 @@ namespace WireMock
/// <summary>
/// Gets the url.
/// </summary>
public string Url { get; private set; }
public string Url { get; }
/// <summary>
/// Gets the DateTime.

View File

@@ -122,8 +122,8 @@ namespace WireMock.Server
{
var model = new SettingsModel
{
AllowPartialMapping = _allowPartialMapping,
GlobalProcessingDelay = _requestProcessingDelay?.Milliseconds
AllowPartialMapping = _options.AllowPartialMapping,
GlobalProcessingDelay = _options.RequestProcessingDelay?.Milliseconds
};
return ToJson(model);
@@ -134,10 +134,10 @@ namespace WireMock.Server
var settings = JsonConvert.DeserializeObject<SettingsModel>(requestMessage.Body);
if (settings.AllowPartialMapping != null)
_allowPartialMapping = settings.AllowPartialMapping.Value;
_options.AllowPartialMapping = settings.AllowPartialMapping.Value;
if (settings.GlobalProcessingDelay != null)
_requestProcessingDelay = TimeSpan.FromMilliseconds(settings.GlobalProcessingDelay.Value);
_options.RequestProcessingDelay = TimeSpan.FromMilliseconds(settings.GlobalProcessingDelay.Value);
return new ResponseMessage { Body = "Settings updated" };
}

View File

@@ -3,8 +3,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using WireMock.Http;
@@ -13,7 +13,7 @@ using WireMock.Matchers;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using WireMock.Validation;
using System.Threading;
using WireMock.Owin;
namespace WireMock.Server
{
@@ -22,23 +22,11 @@ namespace WireMock.Server
/// </summary>
public partial class FluentMockServer : IDisposable
{
private readonly TinyHttpServer _httpServer;
private IList<Mapping> _mappings = new List<Mapping>();
private readonly IList<LogEntry> _logEntries = new List<LogEntry>();
private readonly HttpListenerRequestMapper _requestMapper = new HttpListenerRequestMapper();
private readonly HttpListenerResponseMapper _responseMapper = new HttpListenerResponseMapper();
private readonly IOwinSelfHost _httpServer;
private readonly object _syncRoot = new object();
private TimeSpan? _requestProcessingDelay;
private bool _allowPartialMapping;
private IMatcher _authorizationMatcher;
private readonly WireMockMiddlewareOptions _options = new WireMockMiddlewareOptions();
/// <summary>
/// Gets the ports.
@@ -63,9 +51,9 @@ namespace WireMock.Server
{
get
{
lock (((ICollection)_logEntries).SyncRoot)
lock (((ICollection)_options.LogEntries).SyncRoot)
{
return new ReadOnlyCollection<LogEntry>(_logEntries);
return new ReadOnlyCollection<LogEntry>(_options.LogEntries);
}
}
}
@@ -78,11 +66,11 @@ namespace WireMock.Server
[PublicAPI]
public IEnumerable<LogEntry> FindLogEntries([NotNull] params IRequestMatcher[] matchers)
{
lock (((ICollection)_logEntries).SyncRoot)
lock (((ICollection)_options.LogEntries).SyncRoot)
{
var results = new Dictionary<LogEntry, RequestMatchResult>();
foreach (var log in _logEntries)
foreach (var log in _options.LogEntries)
{
var requestMatchResult = new RequestMatchResult();
foreach (var matcher in matchers)
@@ -106,9 +94,9 @@ namespace WireMock.Server
{
get
{
lock (((ICollection)_mappings).SyncRoot)
lock (((ICollection)_options.Mappings).SyncRoot)
{
return new ReadOnlyCollection<Mapping>(_mappings);
return new ReadOnlyCollection<Mapping>(_options.Mappings);
}
}
}
@@ -222,10 +210,14 @@ namespace WireMock.Server
Urls = new[] { (settings.UseSSL == true ? "https" : "http") + "://localhost:" + port + "/" };
}
_httpServer = new TinyHttpServer(HandleRequestAsync, Urls);
#if NET45
_httpServer = new OwinSelfHost(_options, Urls);
#else
_httpServer = new AspNetCoreSelfHost(_options, Urls);
#endif
Ports = _httpServer.Ports;
_httpServer.Start();
_httpServer.StartAsync();
if (settings.StartAdminInterface == true)
{
@@ -256,7 +248,7 @@ namespace WireMock.Server
[PublicAPI]
public void Stop()
{
_httpServer?.Stop();
_httpServer?.StopAsync();
}
/// <summary>
@@ -266,7 +258,7 @@ namespace WireMock.Server
{
if (_httpServer != null && _httpServer.IsStarted)
{
_httpServer.Stop();
_httpServer.StopAsync();
}
}
@@ -287,9 +279,9 @@ namespace WireMock.Server
[PublicAPI]
public void ResetLogEntries()
{
lock (((ICollection)_logEntries).SyncRoot)
lock (((ICollection)_options.LogEntries).SyncRoot)
{
_logEntries.Clear();
_options.LogEntries.Clear();
}
}
@@ -300,13 +292,13 @@ namespace WireMock.Server
[PublicAPI]
public bool DeleteLogEntry(Guid guid)
{
lock (((ICollection)_logEntries).SyncRoot)
lock (((ICollection)_options.LogEntries).SyncRoot)
{
// Check a logentry exists with the same GUID, if so, remove it.
var existing = _logEntries.FirstOrDefault(m => m.Guid == guid);
var existing = _options.LogEntries.FirstOrDefault(m => m.Guid == guid);
if (existing != null)
{
_logEntries.Remove(existing);
_options.LogEntries.Remove(existing);
return true;
}
@@ -320,9 +312,9 @@ namespace WireMock.Server
[PublicAPI]
public void ResetMappings()
{
lock (((ICollection)_mappings).SyncRoot)
lock (((ICollection)_options.Mappings).SyncRoot)
{
_mappings = _mappings.Where(m => m.Provider is DynamicResponseProvider).ToList();
_options.Mappings = _options.Mappings.Where(m => m.Provider is DynamicResponseProvider).ToList();
}
}
@@ -333,13 +325,13 @@ namespace WireMock.Server
[PublicAPI]
public bool DeleteMapping(Guid guid)
{
lock (((ICollection)_mappings).SyncRoot)
lock (((ICollection)_options.Mappings).SyncRoot)
{
// Check a mapping exists with the same GUID, if so, remove it.
var existingMapping = _mappings.FirstOrDefault(m => m.Guid == guid);
var existingMapping = _options.Mappings.FirstOrDefault(m => m.Guid == guid);
if (existingMapping != null)
{
_mappings.Remove(existingMapping);
_options.Mappings.Remove(existingMapping);
return true;
}
@@ -358,7 +350,7 @@ namespace WireMock.Server
{
lock (_syncRoot)
{
_requestProcessingDelay = delay;
_options.RequestProcessingDelay = delay;
}
}
@@ -370,7 +362,7 @@ namespace WireMock.Server
{
lock (_syncRoot)
{
_allowPartialMapping = true;
_options.AllowPartialMapping = true;
}
}
@@ -386,7 +378,7 @@ namespace WireMock.Server
Check.NotNull(password, nameof(password));
string authorization = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
_authorizationMatcher = new RegexMatcher("^(?i)BASIC " + authorization + "$");
_options.AuthorizationMatcher = new RegexMatcher("^(?i)BASIC " + authorization + "$");
}
/// <summary>
@@ -408,119 +400,99 @@ namespace WireMock.Server
/// </param>
private void RegisterMapping(Mapping mapping)
{
lock (((ICollection)_mappings).SyncRoot)
lock (((ICollection)_options.Mappings).SyncRoot)
{
// Check a mapping exists with the same GUID, if so, remove it first.
DeleteMapping(mapping.Guid);
_mappings.Add(mapping);
_options.Mappings.Add(mapping);
}
}
/// <summary>
/// The log request.
/// </summary>
/// <param name="entry">The request.</param>
private void LogRequest(LogEntry entry)
{
lock (((ICollection)_logEntries).SyncRoot)
{
_logEntries.Add(entry);
}
}
//private async void HandleRequestOld(IOwinContext ctx)
//{
// if (_requestProcessingDelay > TimeSpan.Zero)
// {
// lock (_syncRoot)
// {
// Task.Delay(_requestProcessingDelay.Value).Wait();
// }
// }
/// <summary>
/// The handle request.
/// </summary>
/// <param name="ctx">The HttpListenerContext.</param>
/// <param name="cancel">The CancellationToken.</param>
private async void HandleRequestAsync(HttpListenerContext ctx, CancellationToken cancel)
{
if (cancel.IsCancellationRequested)
return;
// var request = _requestMapper.MapAsync(ctx.Request);
if (_requestProcessingDelay > TimeSpan.Zero)
{
lock (_syncRoot)
{
Task.Delay(_requestProcessingDelay.Value, cancel).Wait(cancel);
}
}
// ResponseMessage response = null;
// Mapping targetMapping = null;
// RequestMatchResult requestMatchResult = null;
// try
// {
// var mappings = _mappings
// .Select(m => new { Mapping = m, MatchResult = m.IsRequestHandled(request) })
// .ToList();
var request = _requestMapper.Map(ctx.Request);
// if (_allowPartialMapping)
// {
// var partialMappings = mappings
// .Where(pm => pm.Mapping.IsAdminInterface && pm.MatchResult.IsPerfectMatch || !pm.Mapping.IsAdminInterface)
// .OrderBy(m => m.MatchResult)
// .ThenBy(m => m.Mapping.Priority)
// .ToList();
ResponseMessage response = null;
Mapping targetMapping = null;
RequestMatchResult requestMatchResult = null;
try
{
var mappings = _mappings
.Select(m => new { Mapping = m, MatchResult = m.IsRequestHandled(request) })
.ToList();
// var bestPartialMatch = partialMappings.FirstOrDefault(pm => pm.MatchResult.AverageTotalScore > 0.0);
if (_allowPartialMapping)
{
var partialMappings = mappings
.Where(pm => pm.Mapping.IsAdminInterface && pm.MatchResult.IsPerfectMatch || !pm.Mapping.IsAdminInterface)
.OrderBy(m => m.MatchResult)
.ThenBy(m => m.Mapping.Priority)
.ToList();
// targetMapping = bestPartialMatch?.Mapping;
// requestMatchResult = bestPartialMatch?.MatchResult;
// }
// else
// {
// var perfectMatch = mappings
// .OrderBy(m => m.Mapping.Priority)
// .FirstOrDefault(m => m.MatchResult.IsPerfectMatch);
var bestPartialMatch = partialMappings.FirstOrDefault(pm => pm.MatchResult.AverageTotalScore > 0.0);
// targetMapping = perfectMatch?.Mapping;
// requestMatchResult = perfectMatch?.MatchResult;
// }
targetMapping = bestPartialMatch?.Mapping;
requestMatchResult = bestPartialMatch?.MatchResult;
}
else
{
var perfectMatch = mappings
.OrderBy(m => m.Mapping.Priority)
.FirstOrDefault(m => m.MatchResult.IsPerfectMatch);
// if (targetMapping == null)
// {
// response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" };
// return;
// }
targetMapping = perfectMatch?.Mapping;
requestMatchResult = perfectMatch?.MatchResult;
}
// if (targetMapping.IsAdminInterface && _authorizationMatcher != null)
// {
// string authorization;
// bool present = request.Headers.TryGetValue("Authorization", out authorization);
// if (!present || _authorizationMatcher.IsMatch(authorization) < 1.0)
// {
// response = new ResponseMessage { StatusCode = 401 };
// return;
// }
// }
if (targetMapping == null)
{
response = new ResponseMessage { StatusCode = 404, Body = "No matching mapping found" };
return;
}
// response = await targetMapping.ResponseTo(request);
// }
// catch (Exception ex)
// {
// response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() };
// }
// finally
// {
// var log = new LogEntry
// {
// Guid = Guid.NewGuid(),
// RequestMessage = request,
// ResponseMessage = response,
// MappingGuid = targetMapping?.Guid,
// MappingTitle = targetMapping?.Title,
// RequestMatchResult = requestMatchResult
// };
if (targetMapping.IsAdminInterface && _authorizationMatcher != null)
{
string authorization;
bool present = request.Headers.TryGetValue("Authorization", out authorization);
if (!present || _authorizationMatcher.IsMatch(authorization) < 1.0)
{
response = new ResponseMessage { StatusCode = 401 };
return;
}
}
// LogRequest(log);
response = await targetMapping.ResponseTo(request);
}
catch (Exception ex)
{
response = new ResponseMessage { StatusCode = 500, Body = ex.ToString() };
}
finally
{
var log = new LogEntry
{
Guid = Guid.NewGuid(),
RequestMessage = request,
ResponseMessage = response,
MappingGuid = targetMapping?.Guid,
MappingTitle = targetMapping?.Title,
RequestMatchResult = requestMatchResult
};
LogRequest(log);
_responseMapper.Map(response, ctx.Response);
ctx.Response.Close();
}
}
// _responseMapper.MapAsync(response, ctx.Response);
// ctx.Response.Close();
// }
//}
}
}

View File

@@ -19,6 +19,7 @@
/// <value>
/// The use SSL.
/// </value>
// ReSharper disable once InconsistentNaming
public bool? UseSSL { get; set; }
/// <summary>
@@ -44,5 +45,10 @@
/// The urls.
/// </value>
public string[] Urls { get; set; }
/// <summary>
/// StartTimeout
/// </summary>
public int StartTimeout { get; set; } = 10000;
}
}

View File

@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
@@ -12,7 +11,7 @@ using JetBrains.Annotations;
// Copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Shared/Check.cs
namespace WireMock.Validation
{
[ExcludeFromCodeCoverage]
// [ExcludeFromCodeCoverage]
[DebuggerStepThrough]
internal static class Check
{

View File

@@ -1,12 +1,11 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using JetBrains.Annotations;
// copied from https://github.com/aspnet/EntityFramework/blob/dev/src/Microsoft.EntityFrameworkCore/Properties/CoreStrings.resx
namespace WireMock.Validation
{
[ExcludeFromCodeCoverage]
// [ExcludeFromCodeCoverage]
internal static class CoreStrings
{
/// <summary>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -3,14 +3,14 @@
<PropertyGroup>
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
<AssemblyTitle>WireMock.Net</AssemblyTitle>
<VersionPrefix>1.0.1.5</VersionPrefix>
<Version>1.0.2.0</Version>
<Authors>Alexandre Victoor;Stef Heyenrath</Authors>
<TargetFramework>net45</TargetFramework>
<TargetFrameworks>net45;netstandard1.3</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net</AssemblyName>
<PackageId>WireMock.Net</PackageId>
<PackageTags>tdd;mock;http;wiremock;test;server;unittest</PackageTags>
<PackageReleaseNotes>Fix StartAndStop from listener.</PackageReleaseNotes>
<PackageReleaseNotes>Support for NETStandard by replacing HttpListener by Owin</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/StefH/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/StefH/WireMock.Net</PackageProjectUrl>
<PackageLicenseUrl>https://raw.githubusercontent.com/StefH/WireMock.Net/master/LICENSE</PackageLicenseUrl>
@@ -18,23 +18,40 @@
<RepositoryUrl>https://github.com/StefH/WireMock.Net</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<DebugType>full</DebugType>
<ApplicationIcon>WireMock.Net-Logo.ico</ApplicationIcon>
<Version>1.0.2.0</Version>
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
<RootNamespace>WireMock</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<DefineConstants>NETSTANDARD</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="10.4.0">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="Handlebars.Net" Version="1.8.0" />
<PackageReference Include="Newtonsoft.Json" Version="6.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="SimMetrics.Net" Version="1.0.3" />
<PackageReference Include="XPath2" Version="1.0.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.AspNet.WebApi.OwinSelfHost" Version="5.2.3" />
<PackageReference Include="Handlebars.Net" Version="1.8.0" />
<PackageReference Include="XPath2" Version="1.0.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="System.Threading.Tasks" Version="4.3.0" />
<PackageReference Include="Handlebars.Net" Version="1.8.0" />
<PackageReference Include="XPath2" Version="1.0.3.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
<PackageReference Include="Handlebars.NetStandard" Version="1.8.1" />
<PackageReference Include="System.Xml.XmlDocument" Version="4.3.0" />
<PackageReference Include="System.Xml.XPath.XmlDocument" Version="4.3.0" />
</ItemGroup>
</Project>

View File

@@ -1,15 +0,0 @@
,
"netstandard1.3": {
"buildOptions": { "define": [ "NETSTANDARD" ] },
"imports": [
"dotnet5.4"
],
"dependencies": {
"System.Collections.Concurrent": "4.3.0",
"System.Diagnostics.Tools": "4.3.0",
"System.Linq": "4.3.0",
"System.Net.Http": "4.3.0",
"System.Net.Sockets": "4.3.0",
"System.Threading.Tasks": "4.3.0"
}
}