mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-28 11:47:50 +02:00
@@ -23,6 +23,7 @@
|
|||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=WWW/@EntryIndexedValue">WWW</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=WWW/@EntryIndexedValue">WWW</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XMS/@EntryIndexedValue">XMS</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XMS/@EntryIndexedValue">XMS</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XUA/@EntryIndexedValue">XUA</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XUA/@EntryIndexedValue">XUA</s:String>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dlls/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Flurl/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Flurl/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=funcs/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=funcs/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Grpc/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Grpc/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace WireMock.Plugin;
|
|
||||||
|
|
||||||
internal static class PluginLoader
|
|
||||||
{
|
|
||||||
private static readonly ConcurrentDictionary<Type, Type> Assemblies = new();
|
|
||||||
|
|
||||||
public static T Load<T>(params object[] args) where T : class
|
|
||||||
{
|
|
||||||
var foundType = Assemblies.GetOrAdd(typeof(T), (type) =>
|
|
||||||
{
|
|
||||||
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll");
|
|
||||||
|
|
||||||
Type? pluginType = null;
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var assembly = Assembly.Load(new AssemblyName
|
|
||||||
{
|
|
||||||
Name = Path.GetFileNameWithoutExtension(file)
|
|
||||||
});
|
|
||||||
|
|
||||||
pluginType = GetImplementationTypeByInterface<T>(assembly);
|
|
||||||
if (pluginType != null)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// no-op: just try next .dll
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pluginType != null)
|
|
||||||
{
|
|
||||||
return pluginType;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new DllNotFoundException($"No dll found which implements type '{type}'");
|
|
||||||
});
|
|
||||||
|
|
||||||
return (T)Activator.CreateInstance(foundType, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type? GetImplementationTypeByInterface<T>(Assembly assembly)
|
|
||||||
{
|
|
||||||
return assembly.GetTypes().FirstOrDefault(t => typeof(T).IsAssignableFrom(t) && !t.GetTypeInfo().IsInterface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ using WireMock.Admin.Mappings;
|
|||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Plugin;
|
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
@@ -53,7 +52,7 @@ internal class MatcherMapper
|
|||||||
case "CSharpCodeMatcher":
|
case "CSharpCodeMatcher":
|
||||||
if (_settings.AllowCSharpCodeMatcher == true)
|
if (_settings.AllowCSharpCodeMatcher == true)
|
||||||
{
|
{
|
||||||
return PluginLoader.Load<ICSharpCodeMatcher>(matchBehaviour, matchOperator, stringPatterns);
|
return TypeLoader.Load<ICSharpCodeMatcher>(matchBehaviour, matchOperator, stringPatterns);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotSupportedException("It's not allowed to use the 'CSharpCodeMatcher' because WireMockServerSettings.AllowCSharpCodeMatcher is not set to 'true'.");
|
throw new NotSupportedException("It's not allowed to use the 'CSharpCodeMatcher' because WireMockServerSettings.AllowCSharpCodeMatcher is not set to 'true'.");
|
||||||
|
|||||||
89
src/WireMock.Net/Util/TypeLoader.cs
Normal file
89
src/WireMock.Net/Util/TypeLoader.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Stef.Validation;
|
||||||
|
|
||||||
|
namespace WireMock.Util;
|
||||||
|
|
||||||
|
internal static class TypeLoader
|
||||||
|
{
|
||||||
|
private static readonly ConcurrentDictionary<string, Type> Assemblies = new();
|
||||||
|
|
||||||
|
public static TInterface Load<TInterface>(params object[] args) where TInterface : class
|
||||||
|
{
|
||||||
|
var key = typeof(TInterface).FullName!;
|
||||||
|
|
||||||
|
var pluginType = Assemblies.GetOrAdd(key, _ =>
|
||||||
|
{
|
||||||
|
if (TryFindTypeInDlls<TInterface>(null, out var foundType))
|
||||||
|
{
|
||||||
|
return foundType;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new DllNotFoundException($"No dll found which implements Interface '{key}'.");
|
||||||
|
});
|
||||||
|
|
||||||
|
return (TInterface)Activator.CreateInstance(pluginType, args)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TInterface LoadByFullName<TInterface>(string implementationTypeFullName, params object[] args) where TInterface : class
|
||||||
|
{
|
||||||
|
Guard.NotNullOrEmpty(implementationTypeFullName);
|
||||||
|
|
||||||
|
var @interface = typeof(TInterface).FullName;
|
||||||
|
var key = $"{@interface}_{implementationTypeFullName}";
|
||||||
|
|
||||||
|
var pluginType = Assemblies.GetOrAdd(key, _ =>
|
||||||
|
{
|
||||||
|
if (TryFindTypeInDlls<TInterface>(implementationTypeFullName, out var foundType))
|
||||||
|
{
|
||||||
|
return foundType;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new DllNotFoundException($"No dll found which implements Interface '{@interface}' and has FullName '{implementationTypeFullName}'.");
|
||||||
|
});
|
||||||
|
|
||||||
|
return (TInterface)Activator.CreateInstance(pluginType, args)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryFindTypeInDlls<TInterface>(string? implementationTypeFullName, [NotNullWhen(true)] out Type? pluginType) where TInterface : class
|
||||||
|
{
|
||||||
|
foreach (var file in Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var assembly = Assembly.Load(new AssemblyName
|
||||||
|
{
|
||||||
|
Name = Path.GetFileNameWithoutExtension(file)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (TryGetImplementationTypeByInterfaceAndOptionalFullName<TInterface>(assembly, implementationTypeFullName, out pluginType))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// no-op: just try next .dll
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginType = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetImplementationTypeByInterfaceAndOptionalFullName<T>(Assembly assembly, string? implementationTypeFullName, [NotNullWhen(true)] out Type? type)
|
||||||
|
{
|
||||||
|
type = assembly
|
||||||
|
.GetTypes()
|
||||||
|
.FirstOrDefault(t =>
|
||||||
|
typeof(T).IsAssignableFrom(t) && !t.GetTypeInfo().IsInterface &&
|
||||||
|
(implementationTypeFullName == null || string.Equals(t.FullName, implementationTypeFullName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
);
|
||||||
|
|
||||||
|
return type != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
using System;
|
|
||||||
using AnyOfTypes;
|
|
||||||
using FluentAssertions;
|
|
||||||
using WireMock.Matchers;
|
|
||||||
using WireMock.Models;
|
|
||||||
using WireMock.Plugin;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace WireMock.Net.Tests.Plugin;
|
|
||||||
|
|
||||||
public class PluginLoaderTests
|
|
||||||
{
|
|
||||||
public interface IDummy
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Load_Valid()
|
|
||||||
{
|
|
||||||
// Act
|
|
||||||
AnyOf<string, StringPattern> pattern = "x";
|
|
||||||
var result = PluginLoader.Load<ICSharpCodeMatcher>(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, pattern);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
result.Should().NotBeNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Load_Invalid_ThrowsException()
|
|
||||||
{
|
|
||||||
// Act
|
|
||||||
Action a = () => PluginLoader.Load<IDummy>();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
a.Should().Throw<DllNotFoundException>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
65
test/WireMock.Net.Tests/Util/TypeLoaderTests.cs
Normal file
65
test/WireMock.Net.Tests/Util/TypeLoaderTests.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using AnyOfTypes;
|
||||||
|
using FluentAssertions;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Models;
|
||||||
|
using WireMock.Util;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Util;
|
||||||
|
|
||||||
|
public class TypeLoaderTests
|
||||||
|
{
|
||||||
|
public interface IDummyInterfaceNoImplementation
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IDummyInterfaceWithImplementation
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DummyClass : IDummyInterfaceWithImplementation
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Load_ByInterface()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
AnyOf<string, StringPattern> pattern = "x";
|
||||||
|
var result = TypeLoader.Load<ICSharpCodeMatcher>(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, pattern);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Load_ByInterfaceAndFullName()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var result = TypeLoader.LoadByFullName<IDummyInterfaceWithImplementation>(typeof(DummyClass).FullName!);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().BeOfType<DummyClass>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Load_ByInterface_ButNoImplementationFoundForInterface_ThrowsException()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Action a = () => TypeLoader.Load<IDummyInterfaceNoImplementation>();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
a.Should().Throw<DllNotFoundException>().WithMessage("No dll found which implements Interface 'WireMock.Net.Tests.Util.TypeLoaderTests+IDummyInterfaceNoImplementation'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Load_ByInterfaceAndFullName_ButNoImplementationFoundForInterface_ThrowsException()
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
Action a = () => TypeLoader.LoadByFullName<IDummyInterfaceWithImplementation>("xyz");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
a.Should().Throw<DllNotFoundException>().WithMessage("No dll found which implements Interface 'WireMock.Net.Tests.Util.TypeLoaderTests+IDummyInterfaceWithImplementation' and has FullName 'xyz'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user