diff --git a/AMWD.Common.AspNetCore/BasicAuthentication/BasicAuthenticationMiddleware.cs b/AMWD.Common.AspNetCore/BasicAuthentication/BasicAuthenticationMiddleware.cs
index 14e9b37..b96c046 100644
--- a/AMWD.Common.AspNetCore/BasicAuthentication/BasicAuthenticationMiddleware.cs
+++ b/AMWD.Common.AspNetCore/BasicAuthentication/BasicAuthenticationMiddleware.cs
@@ -12,19 +12,16 @@ namespace AMWD.Common.AspNetCore.BasicAuthentication
public class BasicAuthenticationMiddleware
{
private readonly RequestDelegate next;
- private readonly string realm;
private readonly IBasicAuthenticationValidator validator;
///
/// Initializes a new instance of the class.
///
/// The following delegate in the process chain.
- /// The realm to display when requesting for credentials.
/// A basic authentication validator.
- public BasicAuthenticationMiddleware(RequestDelegate next, string realm, IBasicAuthenticationValidator validator)
+ public BasicAuthenticationMiddleware(RequestDelegate next, IBasicAuthenticationValidator validator)
{
this.next = next;
- this.realm = realm;
this.validator = validator;
}
@@ -53,10 +50,8 @@ namespace AMWD.Common.AspNetCore.BasicAuthentication
}
httpContext.Response.Headers["WWW-Authenticate"] = "Basic";
- if (!string.IsNullOrWhiteSpace(realm))
- {
- httpContext.Response.Headers["WWW-Authenticate"] += $" realm=\"{realm}\"";
- }
+ if (!string.IsNullOrWhiteSpace(validator.Realm))
+ httpContext.Response.Headers["WWW-Authenticate"] += $" realm=\"{validator.Realm}\"";
httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
}
diff --git a/AMWD.Common.AspNetCore/BasicAuthentication/IBasicAuthenticationValidator.cs b/AMWD.Common.AspNetCore/BasicAuthentication/IBasicAuthenticationValidator.cs
index 84972f7..d2d865b 100644
--- a/AMWD.Common.AspNetCore/BasicAuthentication/IBasicAuthenticationValidator.cs
+++ b/AMWD.Common.AspNetCore/BasicAuthentication/IBasicAuthenticationValidator.cs
@@ -9,6 +9,11 @@ namespace AMWD.Common.AspNetCore.BasicAuthentication
///
public interface IBasicAuthenticationValidator
{
+ ///
+ /// Gets or sets the realm to use when requesting authentication.
+ ///
+ string Realm { get; set; }
+
///
/// Validates a username and password for Basic Authentication.
///
diff --git a/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs b/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs
index 82a5c29..7dd8dab 100644
--- a/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs
+++ b/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs
@@ -66,19 +66,24 @@ namespace Microsoft.EntityFrameworkCore
return DatabaseProvider.SQLite;
if (provider.Contains("sqlclient", StringComparison.OrdinalIgnoreCase))
return DatabaseProvider.SQLServer;
+ if (provider.Contains("inmemory", StringComparison.OrdinalIgnoreCase))
+ return DatabaseProvider.InMemory;
throw new DatabaseProviderException($"The database provider '{provider}' is unknown");
}
private static async Task CreateMigrationsTable(this DbConnection connection, DatabaseMigrationOptions options, CancellationToken cancellationToken)
{
+ if (connection.GetProviderType() == DatabaseProvider.InMemory)
+ return true;
+
try
{
using var command = connection.CreateCommand();
-#pragma warning disable CS8524 // missing default case
+#pragma warning disable CS8509 // ignore missing cases
command.CommandText = connection.GetProviderType() switch
-#pragma warning restore CS8524 // missing default case
+#pragma warning restore CS8509 // ignore missing cases
{
DatabaseProvider.MySQL => $@"CREATE TABLE IF NOT EXISTS `{options.MigrationsTableName}` (
`id` INT NOT NULL AUTO_INCREMENT,
@@ -135,6 +140,9 @@ END;"
private static async Task Migrate(this DbConnection connection, DatabaseMigrationOptions options, CancellationToken cancellationToken)
{
+ if (connection.GetProviderType() == DatabaseProvider.InMemory)
+ return true;
+
try
{
List availableMigrationFiles;
@@ -279,7 +287,8 @@ END;"
Oracle = 2,
PostgreSQL = 3,
SQLite = 4,
- SQLServer = 5
+ SQLServer = 5,
+ InMemory = 6,
}
}
}
diff --git a/AMWD.Common.EntityFrameworkCore/Extensions/DbContextOptionsBuilderExtensions.cs b/AMWD.Common.EntityFrameworkCore/Extensions/DbContextOptionsBuilderExtensions.cs
index 51646f9..edf410f 100644
--- a/AMWD.Common.EntityFrameworkCore/Extensions/DbContextOptionsBuilderExtensions.cs
+++ b/AMWD.Common.EntityFrameworkCore/Extensions/DbContextOptionsBuilderExtensions.cs
@@ -79,6 +79,10 @@ namespace Microsoft.EntityFrameworkCore
case "mssql":
methodInfo = extensionType.GetMethod("UseSqlServer", new Type[] { typeof(DbContextOptionsBuilder), typeof(string), actionType });
break;
+ case "memory":
+ case "inmemory":
+ methodInfo = extensionType.GetMethod("UseInMemoryDatabase", new Type[] { typeof(DbContextOptionsBuilder), typeof(string), actionType });
+ break;
default:
throw new DatabaseProviderException($"Unknown database provider: {provider}");
}
@@ -122,6 +126,10 @@ namespace Microsoft.EntityFrameworkCore
case "mssql":
builderType = Type.GetType("Microsoft.EntityFrameworkCore.Infrastructure.SqlServerDbContextOptionsBuilder, Microsoft.EntityFrameworkCore.SqlServer");
break;
+ case "memory":
+ case "inmemory":
+ builderType = Type.GetType("Microsoft.EntityFrameworkCore.Infrastructure.InMemoryDbContextOptionsBuilder, Microsoft.EntityFrameworkCore.InMemory");
+ break;
default:
throw new ArgumentException($"Unknown database provider: {provider}");
}
@@ -155,6 +163,10 @@ namespace Microsoft.EntityFrameworkCore
case "mssql":
extensionType = Type.GetType("Microsoft.EntityFrameworkCore.SqlServerDbContextOptionsExtensions, Microsoft.EntityFrameworkCore.SqlServer");
break;
+ case "memory":
+ case "inmemory":
+ extensionType = Type.GetType("Microsoft.EntityFrameworkCore.InMemoryDbContextOptionsExtensions, Microsoft.EntityFrameworkCore.InMemory");
+ break;
default:
throw new ArgumentException($"Unknown database provider: {provider}");
}
@@ -219,6 +231,10 @@ namespace Microsoft.EntityFrameworkCore
}
cs.Add("Connect Timeout=15");
break;
+ case "memory":
+ case "inmemory":
+ cs.Add(configuration.GetValue("Name", provider));
+ break;
default:
throw new DatabaseProviderException($"Unknown database provider: {provider}");
}
diff --git a/AMWD.Common.Moq/AMWD.Common.Moq.csproj b/AMWD.Common.Moq/AMWD.Common.Moq.csproj
new file mode 100644
index 0000000..b0afde3
--- /dev/null
+++ b/AMWD.Common.Moq/AMWD.Common.Moq.csproj
@@ -0,0 +1,46 @@
+
+
+
+ netstandard2.0
+ 10.0
+
+ AMWD.Common.Moq
+ AMWD.Common.Moq
+ {semvertag:master:+chash}{!:-dirty}
+
+ true
+ false
+ true
+
+ true
+ true
+ snupkg
+
+ AMWD.Common.Moq
+ icon.png
+ https://wiki.am-wd.de/libs/common
+
+ git
+ https://git.am-wd.de/AM.WD/common.git
+
+ AM.WD Common Library for Moq
+ Library with classes and extensions used frequently on AM.WD projects.
+ AM.WD
+ Andreas Müller
+ © {copyright:2020-} AM.WD
+ MIT
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
diff --git a/AMWD.Common.Moq/HttpMessageHandlerMoq.cs b/AMWD.Common.Moq/HttpMessageHandlerMoq.cs
new file mode 100644
index 0000000..d5b18dd
--- /dev/null
+++ b/AMWD.Common.Moq/HttpMessageHandlerMoq.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading;
+using System.Threading.Tasks;
+using Moq;
+using Moq.Protected;
+
+namespace AMWD.Common.Moq
+{
+ ///
+ /// Wrapps the including the setup.
+ ///
+ public class HttpMessageHandlerMoq
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public HttpMessageHandlerMoq()
+ {
+ Response = new() { StatusCode = HttpStatusCode.OK };
+ Callbacks = new();
+
+ Mock = new();
+ Mock.Protected()
+ .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny())
+ .Callback(async (req, _) =>
+ {
+ var callback = new HttpMessageRequestCallback
+ {
+ Headers = req.Headers,
+ Method = req.Method,
+ Properties = req.Properties,
+ RequestUri = req.RequestUri,
+ Version = req.Version
+ };
+
+ if (req.Content != null)
+ {
+ callback.ContentBytes = await req.Content.ReadAsByteArrayAsync();
+ callback.ContentString = await req.Content.ReadAsStringAsync();
+ }
+
+ Callbacks.Add(callback);
+ })
+ .ReturnsAsync(Response);
+ }
+
+ ///
+ /// Gets the mocked .
+ ///
+ public Mock Mock { get; }
+
+ ///
+ /// Gets the placed request.
+ ///
+ public List Callbacks { get; private set; }
+
+ ///
+ /// Gets the HTTP response, that should be "sent".
+ ///
+ public HttpResponseMessage Response { get; private set; }
+
+ ///
+ /// Disposes and resets the and .
+ ///
+ public void Reset()
+ {
+ Response.Dispose();
+ Response = new() { StatusCode = HttpStatusCode.OK };
+
+ Callbacks.Clear();
+ }
+
+ ///
+ /// Verifies the number of calls to the HTTP request.
+ ///
+ ///
+ public void Verify(Times times)
+ => Mock.Protected().Verify("SendAsync", times, ItExpr.IsAny(), ItExpr.IsAny());
+
+ ///
+ /// Represents the placed HTTP request.
+ ///
+ public class HttpMessageRequestCallback
+ {
+ ///
+ /// Gets the contents of the HTTP message.
+ ///
+ public byte[] ContentBytes { get; internal set; }
+
+ ///
+ /// Gets the contents of the HTTP message.
+ ///
+ public string ContentString { get; internal set; }
+
+ ///
+ /// Gets the collection of HTTP request headers.
+ ///
+ public HttpRequestHeaders Headers { get; internal set; }
+
+ ///
+ /// Gets the HTTP method used by the HTTP request message.
+ ///
+ public HttpMethod Method { get; internal set; }
+
+ ///
+ /// Gets of properties for the HTTP request.
+ ///
+ public IDictionary Properties { get; internal set; }
+
+ ///
+ /// Gets the used for the HTTP request.
+ ///
+ public Uri RequestUri { get; internal set; }
+
+ ///
+ /// Gets the string representation.
+ ///
+ public string RequestUrl => RequestUri?.ToString();
+
+ ///
+ /// Gets the HTTP message version.
+ ///
+ public Version Version { get; internal set; }
+ }
+ }
+}
diff --git a/AMWD.Common/Extensions/StringExtensions.cs b/AMWD.Common/Extensions/StringExtensions.cs
index df766bd..2b4f971 100644
--- a/AMWD.Common/Extensions/StringExtensions.cs
+++ b/AMWD.Common/Extensions/StringExtensions.cs
@@ -5,6 +5,7 @@ using System.Net;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
+using System.Threading.Tasks;
using DNS.Client;
using DNS.Protocol;
@@ -170,18 +171,17 @@ namespace System
var mailAddress = new MailAddress(email);
bool isValid = mailAddress.Address == email;
- if (isValid && nameservers != null)
+ if (isValid && nameservers?.Any() == true)
{
bool exists = false;
foreach (var nameserver in nameservers)
{
- var clientRequest = new ClientRequest(nameserver) { RecursionDesired = true };
- clientRequest.Questions.Add(new Question(Domain.FromString(mailAddress.Host), RecordType.MX));
+ var client = new DnsClient(nameserver);
+ var waitTask = Task.Run(async () => await client.Resolve(mailAddress.Host, RecordType.MX));
+ waitTask.Wait();
- var response = clientRequest.Resolve()
- .ConfigureAwait(false)
- .GetAwaiter()
- .GetResult();
+ var response = waitTask.Result;
+ waitTask.Dispose();
if (response.ResponseCode != ResponseCode.NoError)
continue;
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c1203a..9980b3a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,10 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased](https://git.am-wd.de/AM.WD/common/compare/v1.3.0...master) - 0000-00-00
### Added
-
+- New NuGet package `AMWD.Common.Moq` with `HttpRequestHandlerMoq` class
+- Supporting `InMemory` Database as provider
### Changed
- Enhanced Stopwatch/Timer delta due to unsharp resolution using timers
+- `IBasicAuthenticationValidator` now requires also the realm (resolving a string on DI is bad style)
## [v1.3.0](https://git.am-wd.de/AM.WD/common/compare/v1.2.0...v1.3.0) - 2021-12-21
diff --git a/Common.sln b/Common.sln
index 3a5745a..3c4d722 100644
--- a/Common.sln
+++ b/Common.sln
@@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F2C7556A-99E
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E5DF156A-6C8B-4004-BA4C-A8DDE6FD3ECD}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AMWD.Common.Moq", "AMWD.Common.Moq\AMWD.Common.Moq.csproj", "{6EBA2792-0B66-4C90-89A1-4E1D26D16443}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -48,6 +50,10 @@ Global
{086E3C11-454A-4C8F-AEAA-215BAE9C443F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{086E3C11-454A-4C8F-AEAA-215BAE9C443F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{086E3C11-454A-4C8F-AEAA-215BAE9C443F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6EBA2792-0B66-4C90-89A1-4E1D26D16443}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6EBA2792-0B66-4C90-89A1-4E1D26D16443}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6EBA2792-0B66-4C90-89A1-4E1D26D16443}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6EBA2792-0B66-4C90-89A1-4E1D26D16443}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -57,6 +63,7 @@ Global
{725F40C9-8172-487F-B3D0-D7E38B4DB197} = {F2C7556A-99EB-43EB-8954-56A24AFE928F}
{7091CECF-C981-4FB9-9CC6-91C4E65A6356} = {F2C7556A-99EB-43EB-8954-56A24AFE928F}
{086E3C11-454A-4C8F-AEAA-215BAE9C443F} = {E5DF156A-6C8B-4004-BA4C-A8DDE6FD3ECD}
+ {6EBA2792-0B66-4C90-89A1-4E1D26D16443} = {F2C7556A-99EB-43EB-8954-56A24AFE928F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {961E8DF8-DDF5-4D10-A510-CE409E9962AC}
diff --git a/build.cmd b/build.cmd
index 38adee8..d2156f3 100644
--- a/build.cmd
+++ b/build.cmd
@@ -40,3 +40,14 @@ rmdir /S /Q bin
dotnet build -c %Configuration% --nologo --no-incremental
move bin\%Configuration%\*.nupkg ..\artifacts
move bin\%Configuration%\*.snupkg ..\artifacts
+
+
+
+cd "%~dp0"
+cd "AMWD.Common.Moq"
+powershell write-host -fore Blue Building AMWD.Common.Moq
+
+rmdir /S /Q bin
+dotnet build -c %Configuration% --nologo --no-incremental
+move bin\%Configuration%\*.nupkg ..\artifacts
+move bin\%Configuration%\*.snupkg ..\artifacts
\ No newline at end of file
diff --git a/build.sh b/build.sh
index bd0b7ee..cddfbde 100644
--- a/build.sh
+++ b/build.sh
@@ -28,3 +28,10 @@ dotnet build -c ${CONFIGURATION} --nologo --no-incremental
mv bin/${CONFIGURATION}/*.nupkg ../artifacts
mv bin/${CONFIGURATION}/*.snupkg ../artifacts
popd
+
+pushd AMWD.Common.Moq
+rm -rf bin
+dotnet build -c ${CONFIGURATION} --nologo --no-incremental
+mv bin/${CONFIGURATION}/*.nupkg ../artifacts
+mv bin/${CONFIGURATION}/*.snupkg ../artifacts
+popd