From 36ddaf02ad43bc40cb09e9c23b012ed3ac92fdd9 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Sun, 18 Sep 2022 22:54:32 +0200 Subject: [PATCH] Removed DNS dependency, added ReflectionExtensions. --- .../AMWD.Common.AspNetCore.csproj | 10 +++- .../AMWD.Common.EntityFrameworkCore.csproj | 20 ++++--- AMWD.Common.Moq/AMWD.Common.Moq.csproj | 12 ++-- AMWD.Common/AMWD.Common.csproj | 11 ++-- .../Extensions/ReflectionExtensions.cs | 42 ++++++++++++++ AMWD.Common/Extensions/StringExtensions.cs | 57 +++++++++++++------ CHANGELOG.md | 10 +++- .../Extensions/StringExtensionsTests.cs | 14 ++--- UnitTests/UnitTests.csproj | 7 ++- 9 files changed, 135 insertions(+), 48 deletions(-) create mode 100644 AMWD.Common/Extensions/ReflectionExtensions.cs diff --git a/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj b/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj index 75cae53..cdb926c 100644 --- a/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj +++ b/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj @@ -6,7 +6,7 @@ AMWD.Common.AspNetCore AMWD.Common.AspNetCore - {semvertag:main}{!:~dirty} + {semvertag:main}{!:-dirty} true false @@ -33,17 +33,21 @@ MIT - + true + + + + + - diff --git a/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj b/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj index e6edb79..cac7921 100644 --- a/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj +++ b/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj @@ -6,7 +6,7 @@ AMWD.Common.EntityFrameworkCore AMWD.Common.EntityFrameworkCore - {semvertag:main}{!:~dirty} + {semvertag:main}{!:-dirty} true false @@ -33,29 +33,33 @@ MIT - + true + + + + + - - - + + + - - + + - all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/AMWD.Common.Moq/AMWD.Common.Moq.csproj b/AMWD.Common.Moq/AMWD.Common.Moq.csproj index 9adc2d2..32a5f93 100644 --- a/AMWD.Common.Moq/AMWD.Common.Moq.csproj +++ b/AMWD.Common.Moq/AMWD.Common.Moq.csproj @@ -6,7 +6,7 @@ AMWD.Common.Moq AMWD.Common.Moq - {semvertag:main}{!:~dirty} + {semvertag:main}{!:-dirty} true false @@ -33,17 +33,21 @@ MIT - + true + + + + + - - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/AMWD.Common/AMWD.Common.csproj b/AMWD.Common/AMWD.Common.csproj index f0df83b..9e48be6 100644 --- a/AMWD.Common/AMWD.Common.csproj +++ b/AMWD.Common/AMWD.Common.csproj @@ -6,7 +6,7 @@ AMWD.Common AMWD.Common - {semvertag:main}{!:~dirty} + {semvertag:main}{!:-dirty} true false @@ -33,19 +33,22 @@ MIT - + true + + + + + - - diff --git a/AMWD.Common/Extensions/ReflectionExtensions.cs b/AMWD.Common/Extensions/ReflectionExtensions.cs new file mode 100644 index 0000000..2496477 --- /dev/null +++ b/AMWD.Common/Extensions/ReflectionExtensions.cs @@ -0,0 +1,42 @@ +using System.Reflection; +using System.Threading.Tasks; + +namespace AMWD.Common.Extensions +{ + /// + /// Extension methods for . + /// + [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public static class ReflectionExtensions + { + /// + /// Calls a method from it's reflection asynchronously without result. + /// + /// The to call on an object. + /// The reflected instance to call the method on. + /// The parameters of the called method. + /// An awaitable . + public static async Task CallAsync(this MethodInfo methodInfo, object obj, params object[] parameters) + { + var task = (Task)methodInfo.Invoke(obj, parameters); + await task.ConfigureAwait(false); + } + + /// + /// Invokes a method from it's reflection asynchronously with a result. + /// + /// The result type, that is expected (and casted to). + /// The to invoke on an object. + /// The reflected instance to invoke the method on. + /// The parameters of the called method. + /// An awaitable with result. + public static async Task InvokeAsync(this MethodInfo methodInfo, object obj, params object[] parameters) + { + var task = (Task)methodInfo.Invoke(obj, parameters); + await task.ConfigureAwait(false); + + var resultPropertyInfo = task.GetType().GetProperty("Result"); + return (TResult)resultPropertyInfo.GetValue(task); + } + } +} diff --git a/AMWD.Common/Extensions/StringExtensions.cs b/AMWD.Common/Extensions/StringExtensions.cs index cec9ef6..551f0a0 100644 --- a/AMWD.Common/Extensions/StringExtensions.cs +++ b/AMWD.Common/Extensions/StringExtensions.cs @@ -1,13 +1,14 @@ -using System.Collections.Generic; +using System.Collections; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; using System.Net.Mail; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; -using DNS.Client; -using DNS.Protocol; +using AMWD.Common.Extensions; namespace System { @@ -150,47 +151,67 @@ namespace System /// You can enhance the check by requesting the MX record of the domain. /// /// The email address as string to validate. - /// A value indicating whether to resolve a MX record (Google DNS is used). + /// A value indicating whether to resolve a MX record (Google DNS is used). /// true when the email address is valid, other wise false. - public static bool IsValidEmailAddress(this string email, bool checkRecordExists = false) - => email.IsValidEmailAddress(checkRecordExists ? new[] { new IPEndPoint(IPAddress.Parse("8.8.8.8"), 53) } : null); + public static bool IsValidEmailAddress(this string email, bool checkForDnsRecord = false) + => email.IsValidEmailAddress(checkForDnsRecord ? new[] { new IPEndPoint(IPAddress.Parse("8.8.8.8"), 53) } : null); /// /// Checks whether the given is a valid . /// /// /// The check is enhanced by a request for MX records on the defined . + ///
+ /// The DNS resolution is only used when the DNS NuGet package is available. + /// See: https://www.nuget.org/packages/DNS/7.0.0 ///
- /// The email address as string to validate. + /// The email address as string to validate. /// A list of s of nameservers. /// true when the email address is valid, other wise false. - public static bool IsValidEmailAddress(this string email, IEnumerable nameservers) + public static bool IsValidEmailAddress(this string emailAddress, IEnumerable nameservers) { try { - var mailAddress = new MailAddress(email); - bool isValid = mailAddress.Address == email; + var mailAddress = new MailAddress(emailAddress); + bool isValid = mailAddress.Address == emailAddress; if (isValid && nameservers?.Any() == true) { + var dnsClientType = Type.GetType("DNS.Client.DnsClient, DNS"); + if (dnsClientType == null) + throw new DllNotFoundException("The DNS NuGet package is required: https://www.nuget.org/packages/DNS/7.0.0"); + + var recordTypeType = Type.GetType("DNS.Protocol.RecordType, DNS"); + var resolveMethodInfo = dnsClientType.GetMethod("Resolve", new[] { typeof(string), recordTypeType, typeof(CancellationToken) }); + bool exists = false; foreach (var nameserver in nameservers) { - var client = new DnsClient(nameserver); - var waitTask = Task.Run(async () => await client.Resolve(mailAddress.Host, RecordType.MX)); + object dnsClient = Activator.CreateInstance(dnsClientType, new object[] { nameserver }); + + var waitTask = Task.Run(async () => await resolveMethodInfo.InvokeAsync(dnsClient, new object[] { mailAddress.Host, 15, CancellationToken.None })); // 15 = MX Record waitTask.Wait(); - var response = waitTask.Result; + object response = waitTask.Result; waitTask.Dispose(); - if (response.ResponseCode != ResponseCode.NoError) + int responseCode = (int)response.GetType().GetProperty("ResponseCode").GetValue(response); + if (responseCode != 0) continue; - exists = response.AnswerRecords - .Where(r => r.Type == RecordType.MX) - .Any(); + object list = response.GetType().GetProperty("AnswerRecords").GetValue(response); + foreach (object item in (list as IEnumerable)) + { + int type = (int)item.GetType().GetProperty("Type").GetValue(item); + if (type == 15) + { + exists = true; + break; + } + } - break; + if (exists) + break; } isValid &= exists; diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e8f0b9..78ce8e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased](https://git.am-wd.de/AM.WD/common/compare/v1.9.0...main) - 0000-00-00 +## [Unreleased](https://git.am-wd.de/AM.WD/common/compare/v1.10.0...main) - 0000-00-00 +_nothing changed yet_ + +## [v1.10.0](https://git.am-wd.de/AM.WD/common/compare/v1.9.0...v1.10.0) - 2022-09-18 ### Fixed - Over-/Underflow behaviour for IPAddress de-/increment - Await behaviour for AsyncQueue (not required to marshal back to the original captured context) +### Removed + +- Removing dependency from DNS package + It's now used via reflection when possible (otherwise exeption) + ## [v1.9.0](https://git.am-wd.de/AM.WD/common/compare/v1.8.1...v1.9.0) - 2022-08-14 diff --git a/UnitTests/Common/Extensions/StringExtensionsTests.cs b/UnitTests/Common/Extensions/StringExtensionsTests.cs index 740a9c8..fa86b59 100644 --- a/UnitTests/Common/Extensions/StringExtensionsTests.cs +++ b/UnitTests/Common/Extensions/StringExtensionsTests.cs @@ -267,11 +267,11 @@ namespace UnitTests.Common.Extensions string nullStr = null; // act - bool validWithoutTag = validEmailWithoutTag.IsValidEmailAddress(checkRecordExists: false); - bool validWithTag = validEmailWithTag.IsValidEmailAddress(checkRecordExists: false); - bool invalidWithoutTag = !invalidEmailWithoutTag.IsValidEmailAddress(checkRecordExists: false); - bool invalidWithTag = !invalidEmailWithTag.IsValidEmailAddress(checkRecordExists: false); - bool nullTest = nullStr.IsValidEmailAddress(checkRecordExists: false); + bool validWithoutTag = validEmailWithoutTag.IsValidEmailAddress(checkForDnsRecord: false); + bool validWithTag = validEmailWithTag.IsValidEmailAddress(checkForDnsRecord: false); + bool invalidWithoutTag = !invalidEmailWithoutTag.IsValidEmailAddress(checkForDnsRecord: false); + bool invalidWithTag = !invalidEmailWithTag.IsValidEmailAddress(checkForDnsRecord: false); + bool nullTest = nullStr.IsValidEmailAddress(checkForDnsRecord: false); // assert Assert.IsTrue(validWithoutTag); @@ -289,8 +289,8 @@ namespace UnitTests.Common.Extensions string invalidEmail = "test@not.exists"; // act - bool valid = validEmail.IsValidEmailAddress(checkRecordExists: true); - bool invalid = !invalidEmail.IsValidEmailAddress(checkRecordExists: true); + bool valid = validEmail.IsValidEmailAddress(checkForDnsRecord: true); + bool invalid = !invalidEmail.IsValidEmailAddress(checkForDnsRecord: true); // assert Assert.IsTrue(valid); diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj index df96bfd..243482a 100644 --- a/UnitTests/UnitTests.csproj +++ b/UnitTests/UnitTests.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -11,8 +11,9 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + +