();
});
}
diff --git a/sample/sample.aspnetcore/Properties/launchSettings.json b/sample/sample.aspnetcore/Properties/launchSettings.json
index 4f49531..6ca3990 100644
--- a/sample/sample.aspnetcore/Properties/launchSettings.json
+++ b/sample/sample.aspnetcore/Properties/launchSettings.json
@@ -1,4 +1,4 @@
-{
+{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
@@ -8,13 +8,6 @@
}
},
"profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
"hcaptcha.aspnetcore": {
"commandName": "Project",
"launchBrowser": true,
diff --git a/sample/sample.aspnetcore/Startup.cs b/sample/sample.aspnetcore/Startup.cs
index ef4423a..6cef1d0 100644
--- a/sample/sample.aspnetcore/Startup.cs
+++ b/sample/sample.aspnetcore/Startup.cs
@@ -1,47 +1,62 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
using BenjaminAbt.HCaptcha.AspNetCore;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
namespace BenjaminAbt.HCaptcha.Samples.AspNetCore;
+///
+/// Configures services and the HTTP request pipeline for the application.
+///
public class Startup
{
+ ///
+ /// Gets the configuration settings for the application.
+ ///
+ public IConfiguration Configuration { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The configuration settings for the application.
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
- public IConfiguration Configuration { get; }
-
+ ///
+ /// Configures services for dependency injection in the application.
+ ///
+ /// The to which services are added.
public void ConfigureServices(IServiceCollection services)
{
- // HCaptcha
+ // Add hCaptcha services using the configuration from the "HCaptcha" section
services.AddHCaptcha(Configuration.GetSection("HCaptcha"));
- // Mvc
+ // Add MVC controllers with views and configure the hCaptcha model binder
services.AddControllersWithViews(mvcOptions =>
- // add model binder
+ // Add custom model binder for hCaptcha
mvcOptions.AddHCaptchaModelBinder());
}
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ ///
+ /// Configures the HTTP request pipeline for the application.
+ ///
+ /// The used to configure the middleware pipeline.
+ /// The containing information about the hosting environment.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
+ // Use the developer exception page in development
app.UseDeveloperExceptionPage();
}
+ // Enable routing in the middleware pipeline
app.UseRouting();
app.UseEndpoints(endpoints =>
{
- // Mvc
+ // Map MVC controllers to their respective endpoints
endpoints.MapControllers();
});
}
diff --git a/sample/sample.aspnetcore/Views/Home/Index.cshtml b/sample/sample.aspnetcore/Views/Home/Index.cshtml
index ebfcd7a..115ee56 100644
--- a/sample/sample.aspnetcore/Views/Home/Index.cshtml
+++ b/sample/sample.aspnetcore/Views/Home/Index.cshtml
@@ -8,7 +8,6 @@
}
-
hCaptcha Demo
-
@{
var response = Model?.Response;
if (response != null)
diff --git a/sample/sample.aspnetcore/sample.aspnetcore.csproj b/sample/sample.aspnetcore/sample.aspnetcore.csproj
index 6a177a0..ba76029 100644
--- a/sample/sample.aspnetcore/sample.aspnetcore.csproj
+++ b/sample/sample.aspnetcore/sample.aspnetcore.csproj
@@ -1,7 +1,6 @@

- net6.0
BenjaminAbt.HCaptcha.Samples.AspNetCore
BenjaminAbt.HCaptcha.Samples.AspNetCore
diff --git a/src/HCaptcha.AspNetCore/AuthorEntityBinderProvider.cs b/src/HCaptcha.AspNetCore/AuthorEntityBinderProvider.cs
index 1dbcfd6..e47cbd3 100644
--- a/src/HCaptcha.AspNetCore/AuthorEntityBinderProvider.cs
+++ b/src/HCaptcha.AspNetCore/AuthorEntityBinderProvider.cs
@@ -1,22 +1,38 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
-using System;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
namespace BenjaminAbt.HCaptcha.AspNetCore;
+///
+/// Provides a model binder for binding an to an action parameter.
+///
public class AuthorEntityBinderProvider : IModelBinderProvider
{
+ ///
+ /// Returns a model binder for the model type, if applicable.
+ ///
+ /// The context that provides information about the model being bound.
+ ///
+ /// An instance if the model type is , otherwise null.
+ ///
+ ///
+ /// Thrown when the is null.
+ ///
public IModelBinder? GetBinder(ModelBinderProviderContext context)
{
+ // Ensure the context is not null
ArgumentNullException.ThrowIfNull(context);
+ // Check if the model type is HCaptchaVerifyResponse
if (context.Metadata.ModelType == typeof(HCaptchaVerifyResponse))
{
+ // Return a binder for HCaptchaVerifyResponse
return new BinderTypeModelBinder(typeof(HCaptchaModelBinder));
}
+ // Return null if no binder is required for the model type
return null;
}
}
diff --git a/src/HCaptcha.AspNetCore/HCaptcha.AspNetCore.csproj b/src/HCaptcha.AspNetCore/HCaptcha.AspNetCore.csproj
index 6728da3..36ccd07 100644
--- a/src/HCaptcha.AspNetCore/HCaptcha.AspNetCore.csproj
+++ b/src/HCaptcha.AspNetCore/HCaptcha.AspNetCore.csproj
@@ -2,17 +2,11 @@
HCaptcha for ASP.NET Core
- net6.0
BenjaminAbt.HCaptcha.AspNetCore
BenjaminAbt.HCaptcha.AspNetCore
- true
embedded
-
-
-
- true
- snupkg
true
+ true
@@ -34,7 +28,7 @@
-
+
diff --git a/src/HCaptcha.AspNetCore/HCaptchaExtensions.cs b/src/HCaptcha.AspNetCore/HCaptchaExtensions.cs
index 99ad7e8..50cbab9 100644
--- a/src/HCaptcha.AspNetCore/HCaptchaExtensions.cs
+++ b/src/HCaptcha.AspNetCore/HCaptchaExtensions.cs
@@ -1,32 +1,42 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
-using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Refit;
namespace BenjaminAbt.HCaptcha.AspNetCore;
+///
+/// Provides extension methods for registering hCaptcha services in the dependency injection container.
+///
public static class HCaptchaExtensions
{
///
- /// Adds the HCaptcha configuration as .
- /// Adds as Refit Client with given base address in .
+ /// Adds hCaptcha services to the using the provided configuration section.
///
+ /// The to which the hCaptcha services will be added.
+ /// The containing the hCaptcha configuration settings.
+ /// The with hCaptcha services added.
+ ///
+ /// Thrown when or is null.
+ ///
public static IServiceCollection AddHCaptcha(this IServiceCollection services, IConfigurationSection section)
{
+ // Bind configuration to HCaptchaOptions
HCaptchaOptions captchaOptions = new();
section.Bind(captchaOptions);
+ // Configure options to be injected wherever needed
services.Configure(section);
+ // Register the Refit client for IHCaptchaApi with the base URL from configuration
services.AddRefitClient()
.ConfigureHttpClient(c =>
- {
- c.BaseAddress = new Uri(captchaOptions.ApiBaseUrl);
- }
- );
+ {
+ c.BaseAddress = new Uri(captchaOptions.ApiBaseUrl);
+ });
+ // Register the hCaptcha provider
services.AddScoped();
return services;
diff --git a/src/HCaptcha.AspNetCore/HCaptchaModelBinder.cs b/src/HCaptcha.AspNetCore/HCaptchaModelBinder.cs
index 76b84c2..5005e0a 100644
--- a/src/HCaptcha.AspNetCore/HCaptchaModelBinder.cs
+++ b/src/HCaptcha.AspNetCore/HCaptchaModelBinder.cs
@@ -1,45 +1,67 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
-using System;
-using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Primitives;
namespace BenjaminAbt.HCaptcha.AspNetCore;
+///
+/// A model binder that binds an hCaptcha verification result to an action parameter.
+///
public class HCaptchaModelBinder : IModelBinder
{
private readonly IHCaptchaProvider _captchaProvider;
private readonly HCaptchaOptions _captchaOptions;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The hCaptcha provider used to verify the captcha token.
+ /// The configuration options for hCaptcha.
public HCaptchaModelBinder(IHCaptchaProvider captchaProvider, IOptions captchaOptionsAccessor)
{
_captchaProvider = captchaProvider;
_captchaOptions = captchaOptionsAccessor.Value;
}
+ ///
+ /// Binds the model by verifying the hCaptcha token from the HTTP request.
+ ///
+ /// The that contains the HTTP request data to bind.
+ /// A representing the asynchronous operation.
+ ///
+ /// Thrown when is null.
+ ///
+ ///
+ /// Thrown if the HTTP request method is not "POST", as hCaptcha validation is only allowed on POST requests.
+ ///
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
+ // Ensure bindingContext is not null
ArgumentNullException.ThrowIfNull(bindingContext);
- // validate context
- var httpContext = bindingContext.HttpContext;
+ // Validate that the request method is POST
+ HttpContext httpContext = bindingContext.HttpContext;
if (httpContext.Request.Method != "POST")
{
throw new InvalidOperationException($"{nameof(HCaptchaModelBinder)} can only be used with HTTP Post.");
}
- // read token
- var token = httpContext.Request.Form[_captchaOptions.HttpPostResponseKeyName];
+ // Retrieve the token from the form data
+ StringValues token = httpContext.Request.Form[_captchaOptions.HttpPostResponseKeyName];
- // verify
+ // Verify the token with the hCaptcha provider
try
{
- var result = await _captchaProvider.Verify(token, httpContext.Connection?.RemoteIpAddress?.ToString());
+ HCaptchaVerifyResponse? result = await _captchaProvider
+ .Verify(token, httpContext.Connection?.RemoteIpAddress?.ToString()).ConfigureAwait(false);
bindingContext.Result = ModelBindingResult.Success(result);
}
catch (HCaptchaApiException apiException)
{
+ // If verification fails, add a model error and mark the binding result as failed
bindingContext.ModelState.TryAddModelError(bindingContext.FieldName, apiException.Message);
bindingContext.Result = ModelBindingResult.Failed();
}
diff --git a/src/HCaptcha.AspNetCore/HCaptchaModelBinderExtensions.cs b/src/HCaptcha.AspNetCore/HCaptchaModelBinderExtensions.cs
index 6be4611..229cf15 100644
--- a/src/HCaptcha.AspNetCore/HCaptchaModelBinderExtensions.cs
+++ b/src/HCaptcha.AspNetCore/HCaptchaModelBinderExtensions.cs
@@ -1,18 +1,30 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
-using System;
using Microsoft.AspNetCore.Mvc;
namespace BenjaminAbt.HCaptcha.AspNetCore;
+///
+/// Extension methods for configuring the hCaptcha model binder in MVC options.
+///
public static class HCaptchaModelBinderExtensions
{
+ ///
+ /// Adds the hCaptcha model binder to the with optional configuration.
+ ///
+ /// The to which the model binder will be added.
+ /// An optional configuration action for setting up the model binder options.
+ /// The updated with the hCaptcha model binder added.
public static MvcOptions AddHCaptchaModelBinder(this MvcOptions mvcOptions,
Action? captchaModelBinderOptions = null)
{
+ // Create a default set of model binder options
HCaptchaModelBinderOptions cmbo = new();
+
+ // Apply custom configuration if provided
captchaModelBinderOptions?.Invoke(cmbo);
+ // Insert the custom AuthorEntityBinderProvider at the specified position
mvcOptions.ModelBinderProviders.Insert(cmbo.BinderPosition, new AuthorEntityBinderProvider());
return mvcOptions;
diff --git a/src/HCaptcha.AspNetCore/HCaptchaModelBinderOptions.cs b/src/HCaptcha.AspNetCore/HCaptchaModelBinderOptions.cs
index a1655ed..575a933 100644
--- a/src/HCaptcha.AspNetCore/HCaptchaModelBinderOptions.cs
+++ b/src/HCaptcha.AspNetCore/HCaptchaModelBinderOptions.cs
@@ -1,8 +1,20 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
+
+using Microsoft.AspNetCore.Mvc;
namespace BenjaminAbt.HCaptcha.AspNetCore;
+///
+/// Options for configuring the position of the hCaptcha model binder in the model binder provider list.
+///
public class HCaptchaModelBinderOptions
{
+ ///
+ /// Gets or sets the position of the hCaptcha model binder in the model binder provider list.
+ ///
+ ///
+ /// The binder is inserted at the specified position in the list.
+ /// A value of 0 means it will be inserted at the beginning of the list.
+ ///
public int BinderPosition { get; set; } = 0;
}
diff --git a/src/HCaptcha/HCaptcha.csproj b/src/HCaptcha/HCaptcha.csproj
index d4190ee..c863e3d 100644
--- a/src/HCaptcha/HCaptcha.csproj
+++ b/src/HCaptcha/HCaptcha.csproj
@@ -4,15 +4,9 @@
HCaptcha for .NET
BenjaminAbt.HCaptcha
BenjaminAbt.HCaptcha
- net6.0
- true
embedded
-
-
-
- true
- snupkg
true
+ true
@@ -30,9 +24,9 @@
-
-
-
+
+
+
diff --git a/src/HCaptcha/HCaptchaApiException.cs b/src/HCaptcha/HCaptchaApiException.cs
index b83deb6..9cc8ec0 100644
--- a/src/HCaptcha/HCaptchaApiException.cs
+++ b/src/HCaptcha/HCaptchaApiException.cs
@@ -1,28 +1,23 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
-using System;
using System.Net;
using Refit;
namespace BenjaminAbt.HCaptcha;
///
-/// hCapcha API Exception
+/// Represents an exception that occurs when an hCaptcha API request fails.
///
-/// Inner exception is a of type which is a part of Refit.
-public class HCaptchaApiException : Exception
+///
+/// Initializes a new instance of the class.
+///
+/// The HTTP status code returned by the hCaptcha API.
+/// The inner exception that contains details about the API error.
+public class HCaptchaApiException(HttpStatusCode statusCode, ApiException apiException)
+ : Exception("hCaptcha API request failed. See inner exception for details.", apiException)
{
///
- /// Status Code
+ /// Gets the HTTP status code associated with the failed hCaptcha API request.
///
- public HttpStatusCode StatusCode { get; } // Refit as Inner Exception
-
- ///
- /// Creates an instance of with wrapped
- ///
- public HCaptchaApiException(HttpStatusCode statusCode, ApiException apiException)
- : base("hCaptcha API request failed. See inner exception for details.", apiException)
- {
- StatusCode = statusCode;
- }
+ public HttpStatusCode StatusCode { get; } = statusCode;
}
diff --git a/src/HCaptcha/HCaptchaOptions.cs b/src/HCaptcha/HCaptchaOptions.cs
index 6a9528f..9c2035c 100644
--- a/src/HCaptcha/HCaptchaOptions.cs
+++ b/src/HCaptcha/HCaptchaOptions.cs
@@ -1,4 +1,4 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
namespace BenjaminAbt.HCaptcha;
diff --git a/src/HCaptcha/HCaptchaProvider.cs b/src/HCaptcha/HCaptchaProvider.cs
index ae85a79..7120c6d 100644
--- a/src/HCaptcha/HCaptchaProvider.cs
+++ b/src/HCaptcha/HCaptchaProvider.cs
@@ -1,7 +1,5 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
-using System.Threading;
-using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Refit;
diff --git a/src/HCaptcha/HCaptchaResponseExtensions.cs b/src/HCaptcha/HCaptchaResponseExtensions.cs
index a5d83bb..fcaf449 100644
--- a/src/HCaptcha/HCaptchaResponseExtensions.cs
+++ b/src/HCaptcha/HCaptchaResponseExtensions.cs
@@ -1,6 +1,4 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
-
-using System.Collections.Generic;
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
namespace BenjaminAbt.HCaptcha;
diff --git a/src/HCaptcha/HCaptchaVerifyErrorCode.cs b/src/HCaptcha/HCaptchaVerifyErrorCode.cs
index a3a1028..5ff3506 100644
--- a/src/HCaptcha/HCaptchaVerifyErrorCode.cs
+++ b/src/HCaptcha/HCaptchaVerifyErrorCode.cs
@@ -1,4 +1,4 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
namespace BenjaminAbt.HCaptcha;
diff --git a/src/HCaptcha/HCaptchaVerifyResponse.cs b/src/HCaptcha/HCaptchaVerifyResponse.cs
index fd96f69..60dbe00 100644
--- a/src/HCaptcha/HCaptchaVerifyResponse.cs
+++ b/src/HCaptcha/HCaptchaVerifyResponse.cs
@@ -1,6 +1,5 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
-using System;
using System.Text.Json.Serialization;
namespace BenjaminAbt.HCaptcha;
diff --git a/src/HCaptcha/IHCaptchaApi.cs b/src/HCaptcha/IHCaptchaApi.cs
index d1da735..e33a5d7 100644
--- a/src/HCaptcha/IHCaptchaApi.cs
+++ b/src/HCaptcha/IHCaptchaApi.cs
@@ -1,7 +1,5 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
-using System.Threading;
-using System.Threading.Tasks;
using Refit;
namespace BenjaminAbt.HCaptcha;
diff --git a/src/HCaptcha/IHCaptchaProvider.cs b/src/HCaptcha/IHCaptchaProvider.cs
index 216d83b..a07b3c2 100644
--- a/src/HCaptcha/IHCaptchaProvider.cs
+++ b/src/HCaptcha/IHCaptchaProvider.cs
@@ -1,7 +1,4 @@
-// Copyright © Benjamin Abt 2020-2021, all rights reserved
-
-using System.Threading;
-using System.Threading.Tasks;
+// Copyright © Benjamin Abt 2020-2024, all rights reserved
namespace BenjaminAbt.HCaptcha;
diff --git a/version.json b/version.json
index 1a05557..1dc6bc7 100644
--- a/version.json
+++ b/version.json
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
- "version": "0.9",
+ "version": "1.0",
"assemblyVersion": {
"precision": "revision" // optional. Use when you want a more precise assembly version than the default major.minor.
},