diff --git a/MailgunAddressValidator/AsyncHelper.cs b/MailgunAddressValidator/AsyncHelper.cs
new file mode 100644
index 0000000..edcb06c
--- /dev/null
+++ b/MailgunAddressValidator/AsyncHelper.cs
@@ -0,0 +1,48 @@
+//
+// Copyright (c) Balázs Keresztury. All rights reserved.
+//
+// Source: https://cpratt.co/async-tips-tricks/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MailgunAddressValidator
+{
+ ///
+ /// Helper class to wrap an async delegate into a syncronous method.
+ ///
+ public static class AsyncHelper
+ {
+ private static readonly TaskFactory _taskFactory = new
+ TaskFactory(
+ CancellationToken.None,
+ TaskCreationOptions.None,
+ TaskContinuationOptions.None,
+ TaskScheduler.Default);
+
+ ///
+ /// Wraps a generic async delegate into a syncronous method.
+ ///
+ /// The type of the result.
+ /// The asyncronous delegate.
+ /// The result.
+ public static TResult RunSync(Func> func)
+ => _taskFactory
+ .StartNew(func)
+ .Unwrap()
+ .GetAwaiter()
+ .GetResult();
+
+ ///
+ /// Wraps an async delegate into a syncronous method.
+ ///
+ /// The asyncronous delegate.
+ public static void RunSync(Func func)
+ => _taskFactory
+ .StartNew(func)
+ .Unwrap()
+ .GetAwaiter()
+ .GetResult();
+ }
+}
\ No newline at end of file
diff --git a/MailgunAddressValidator/MailgunAddressValidator.csproj b/MailgunAddressValidator/MailgunAddressValidator.csproj
index 80d3626..88c3412 100644
--- a/MailgunAddressValidator/MailgunAddressValidator.csproj
+++ b/MailgunAddressValidator/MailgunAddressValidator.csproj
@@ -1,7 +1,7 @@
netstandard1.1;netstandard2.0
- 1.1.1
+ 1.1.2
Balázs Keresztury
This asynchronous library checks email addresses against Mailgun's e-mail validation service
@@ -14,8 +14,11 @@
true
-
- 1701;1702;SA0001
+ MailgunAddressValidator.xml
+ 1701;1702
+
+
+ MailgunAddressValidator.xml
@@ -24,6 +27,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
all
diff --git a/MailgunAddressValidator/MailgunAddressValidator.xml b/MailgunAddressValidator/MailgunAddressValidator.xml
new file mode 100644
index 0000000..b3b71c7
--- /dev/null
+++ b/MailgunAddressValidator/MailgunAddressValidator.xml
@@ -0,0 +1,105 @@
+
+
+
+ MailgunAddressValidator
+
+
+
+
+ Helper class to wrap an async delegate into a syncronous method.
+
+
+
+
+ Wraps a generic async delegate into a syncronous method.
+
+ The type of the result.
+ The asyncronous delegate.
+ The result.
+
+
+
+ Wraps an async delegate into a syncronous method.
+
+ The asyncronous delegate.
+
+
+
+ It is thrown when the client is unable to authorize with the Mailgun API.
+
+
+
+
+ Initializes a new instance of the class.
+
+
+
+
+ Contains the result of a validation.
+
+
+
+
+ Runs the email segments across a valid known provider rule list. If a violation occurs this value is false.
+
+
+
+
+ Email address being validated.
+
+
+
+
+ Parsed segments of the provided email address.
+
+
+
+
+ Null if nothing, however if a potential typo is made, the closest suggestion is provided.
+
+
+
+
+ Contains parsed segments of the provided email address.
+
+
+
+
+ Display name for the address.
+
+
+
+
+ The local part of the e-mail address.
+
+
+
+
+ The domain part of the e-mail address.
+
+
+
+
+ Contains static functions to validate an e-mail address using Mailgun's e-mail validation service.
+
+
+
+
+ Validates an e-mail address.
+
+ E-mail address to validate.
+ Mailgun e-mail validation API key.
+ Max. time to wait for the call to complete (in ms).
+ A ValidationResult object.
+
+
+
+ Validates an e-mail address.
+
+ E-mail address to validate.
+ Mailgun e-mail validation API key.
+ Max. time to wait for the call to complete (in ms).
+ A Task containg a ValidationResult object.
+
+
+
diff --git a/MailgunAddressValidator/Validator.cs b/MailgunAddressValidator/Validator.cs
index 715d669..b7fc930 100644
--- a/MailgunAddressValidator/Validator.cs
+++ b/MailgunAddressValidator/Validator.cs
@@ -18,7 +18,7 @@ namespace MailgunAddressValidator
public static class Validator
{
private const string MailgunBaseUrl = "https://api.mailgun.net";
- private const string ValidatorResource = "/v3/address/validate";
+ private const string MailgunValidatorResource = "/v3/address/validate";
private static readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings()
{
ContractResolver = new DefaultContractResolver()
@@ -28,7 +28,7 @@ public static class Validator
};
///
- /// Validates an e-mail address in a syncronous fashion.
+ /// Validates an e-mail address.
///
/// E-mail address to validate.
/// Mailgun e-mail validation API key.
@@ -38,25 +38,19 @@ public static ValidationResult Validate(string email, string apikey, int timeout
{
try
{
- var response = GetClient(apikey, timeout).GetAsync(GetUri(email)).Result;
+ var response = AsyncHelper.RunSync(() => GetConfiguredClient(apikey, timeout).GetAsync(GetUri(email)));
EvaluateResponse(response);
- return JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result, _jsonSerializerSettings);
+ string responseBody = AsyncHelper.RunSync(() => response.Content.ReadAsStringAsync());
+ return JsonConvert.DeserializeObject(responseBody, _jsonSerializerSettings);
}
- catch (AggregateException ex)
+ catch (TaskCanceledException)
{
- if (ex.InnerException is TaskCanceledException)
- {
- throw new TimeoutException("API call took longer than expected.");
- }
- else
- {
- throw;
- }
+ throw new TimeoutException("API call took longer than expected.");
}
}
///
- /// Validates an e-mail address in an asyncronous fashion.
+ /// Validates an e-mail address.
///
/// E-mail address to validate.
/// Mailgun e-mail validation API key.
@@ -66,20 +60,14 @@ public static async Task ValidateAsync(string email, string ap
{
try
{
- var response = await GetClient(apikey, timeout).GetAsync(GetUri(email));
+ var response = await GetConfiguredClient(apikey, timeout).GetAsync(GetUri(email)).ConfigureAwait(false);
EvaluateResponse(response);
- return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync(), _jsonSerializerSettings);
+ string responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+ return JsonConvert.DeserializeObject(responseBody, _jsonSerializerSettings);
}
- catch (AggregateException ex)
+ catch (TaskCanceledException)
{
- if (ex.InnerException is TaskCanceledException)
- {
- throw new TimeoutException("API call took longer than expected.");
- }
- else
- {
- throw;
- }
+ throw new TimeoutException("API call took longer than expected.");
}
}
@@ -95,7 +83,7 @@ private static void EvaluateResponse(HttpResponseMessage response)
}
}
- private static HttpClient GetClient(string apikey, int timeout)
+ private static HttpClient GetConfiguredClient(string apikey, int timeout)
{
var auth = new HttpClientHandler()
{
@@ -114,7 +102,7 @@ private static Uri GetUri(string email)
{
UriBuilder ub = new UriBuilder(MailgunBaseUrl)
{
- Path = ValidatorResource,
+ Path = MailgunValidatorResource,
Query = $"address={email}",
};
return ub.Uri;
diff --git a/MailgunAddressValidatorTests/MailgunAddressValidatorTests.cs b/MailgunAddressValidatorTests/MailgunAddressValidatorTests.cs
index 8f648a1..27a3d25 100644
--- a/MailgunAddressValidatorTests/MailgunAddressValidatorTests.cs
+++ b/MailgunAddressValidatorTests/MailgunAddressValidatorTests.cs
@@ -20,6 +20,18 @@ public class MailgunAddressValidatorTests
private readonly string _validAddress = "sales@mailgun.com";
private readonly string _invalidAddress = "test@nonexistentdomain.com";
+ ///
+ /// Tests if a valid email address returns valid response.
+ ///
+ /// A representing the asynchronous unit test.
+ [Parallelizable]
+ [Test]
+ public async Task ValidateValidAddressAsync()
+ {
+ ValidationResult result = await Validator.ValidateAsync(_validAddress, _apikey).ConfigureAwait(false);
+ Assert.That(result.IsValid, Is.True);
+ }
+
///
/// Tests if a valid email address returns valid response.
///
@@ -31,6 +43,18 @@ public void ValidateValidAddress()
Assert.That(result.IsValid, Is.True);
}
+ ///
+ /// Tests if an invalid e-mail address returns invalid response.
+ ///
+ /// A representing the asynchronous unit test.
+ [Parallelizable]
+ [Test]
+ public async Task ValidateInvalidAddressAsync()
+ {
+ ValidationResult result = await Validator.ValidateAsync(_invalidAddress, _apikey).ConfigureAwait(false);
+ Assert.That(result.IsValid, Is.False);
+ }
+
///
/// Tests if an invalid e-mail address returns invalid response.
///
@@ -42,6 +66,19 @@ public void ValidateInvalidAddress()
Assert.That(result.IsValid, Is.False);
}
+ ///
+ /// Tests if an e-mail containing a typo gets fixed.
+ ///
+ /// A representing the asynchronous unit test.
+ [Parallelizable]
+ [Test]
+ public async Task ValidateAddressWithTypoAsync()
+ {
+ ValidationResult result = await Validator.ValidateAsync("test@gmaill.com", _apikey).ConfigureAwait(false);
+ Assert.That(result.IsValid, Is.True);
+ Assert.That(result.DidYouMean, Is.EqualTo("test@gmail.com"));
+ }
+
///
/// Tests if an e-mail containing a typo gets fixed.
///
@@ -54,6 +91,16 @@ public void ValidateAddressWithTypo()
Assert.That(result.DidYouMean, Is.EqualTo("test@gmail.com"));
}
+ ///
+ /// Tests if a request with very short timeout actually fails.
+ ///
+ [Parallelizable]
+ [Test]
+ public void ThrowTimeoutExceptionAsync()
+ {
+ Assert.That(async () => await Validator.ValidateAsync(_validAddress, _apikey, 1).ConfigureAwait(false), Throws.TypeOf());
+ }
+
///
/// Tests if a request with very short timeout actually fails.
///
@@ -69,21 +116,19 @@ public void ThrowTimeoutException()
///
[Parallelizable]
[Test]
- public void ThrowUnauthorizedExceptionOnBadApiKey()
+ public void ThrowUnauthorizedExceptionOnBadApiKeyAsync()
{
- Assert.That(() => Validator.Validate(_validAddress, "blabla"), Throws.TypeOf());
+ Assert.That(async () => await Validator.ValidateAsync(_validAddress, "blabla").ConfigureAwait(false), Throws.TypeOf());
}
///
- /// Tests asyncronous validation.
+ /// Tests if an exception is thrown when the API key is invalid.
///
- /// A Task.
[Parallelizable]
[Test]
- public async Task ValidateValidAddressAsync()
+ public void ThrowUnauthorizedExceptionOnBadApiKey()
{
- ValidationResult result = await Validator.ValidateAsync(_validAddress, _apikey);
- Assert.That(result.IsValid, Is.True);
+ Assert.That(() => Validator.Validate(_validAddress, "blabla"), Throws.TypeOf());
}
}
}
diff --git a/MailgunAddressValidatorTests/MailgunAddressValidatorTests.csproj b/MailgunAddressValidatorTests/MailgunAddressValidatorTests.csproj
index cb699e9..fcfbf04 100644
--- a/MailgunAddressValidatorTests/MailgunAddressValidatorTests.csproj
+++ b/MailgunAddressValidatorTests/MailgunAddressValidatorTests.csproj
@@ -2,7 +2,16 @@
netcoreapp3.1
- MailgunAddressValidator
+ MailgunAddressValidatorTests
+ 1.1.2
+
+
+
+ MailgunAddressValidatorTests.xml
+
+
+
+ MailgunAddressValidatorTests.xml
@@ -14,6 +23,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/MailgunAddressValidatorTests/MailgunAddressValidatorTests.xml b/MailgunAddressValidatorTests/MailgunAddressValidatorTests.xml
new file mode 100644
index 0000000..7b9150e
--- /dev/null
+++ b/MailgunAddressValidatorTests/MailgunAddressValidatorTests.xml
@@ -0,0 +1,66 @@
+
+
+
+ MailgunAddressValidatorTests
+
+
+
+
+ Contains tests for the MailgunAddressValidator project.
+
+
+
+
+ Tests if a valid email address returns valid response.
+
+ A representing the asynchronous unit test.
+
+
+
+ Tests if a valid email address returns valid response.
+
+
+
+
+ Tests if an invalid e-mail address returns invalid response.
+
+ A representing the asynchronous unit test.
+
+
+
+ Tests if an invalid e-mail address returns invalid response.
+
+
+
+
+ Tests if an e-mail containing a typo gets fixed.
+
+ A representing the asynchronous unit test.
+
+
+
+ Tests if an e-mail containing a typo gets fixed.
+
+
+
+
+ Tests if a request with very short timeout actually fails.
+
+
+
+
+ Tests if a request with very short timeout actually fails.
+
+
+
+
+ Tests if an exception is thrown when the API key is invalid.
+
+
+
+
+ Tests if an exception is thrown when the API key is invalid.
+
+
+
+