diff --git a/LICENSE b/LICENSE
index 3e59e20..7e4a3d3 100644
--- a/LICENSE
+++ b/LICENSE
@@ -20,3 +20,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+This software includes code from the open source Microsoft ASP.NET web stack,
+licensed under the Apache 2.0 license. You may obtain a copy of the license at
+http://www.apache.org/licenses/LICENSE-2.0
\ No newline at end of file
diff --git a/src/Autofac.Integration.WebApi/ActionFilterWrapper.cs b/src/Autofac.Integration.WebApi/ActionFilterWrapper.cs
deleted file mode 100644
index 6faa8dd..0000000
--- a/src/Autofac.Integration.WebApi/ActionFilterWrapper.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-// This software is part of the Autofac IoC container
-// Copyright (c) 2012 Autofac Contributors
-// https://autofac.org
-//
-// Permission is hereby granted, free of charge, to any person
-// obtaining a copy of this software and associated documentation
-// files (the "Software"), to deal in the Software without
-// restriction, including without limitation the rights to use,
-// copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the
-// Software is furnished to do so, subject to the following
-// conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-// OTHER DEALINGS IN THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Web.Http.Controllers;
-using System.Web.Http.Filters;
-using Autofac.Features.Metadata;
-
-namespace Autofac.Integration.WebApi
-{
- ///
- /// Resolves a filter for the specified metadata for each controller request.
- ///
- [SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "Derived attribute adds filter override support")]
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
- internal class ActionFilterWrapper : ActionFilterAttribute, IAutofacActionFilter
- {
- private readonly HashSet _allFilters;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The collection of filter metadata blocks that this wrapper should run.
- public ActionFilterWrapper(HashSet filterMetadata)
- {
- if (filterMetadata == null)
- {
- throw new ArgumentNullException(nameof(filterMetadata));
- }
-
- _allFilters = filterMetadata;
- }
-
- ///
- /// Occurs after the action method is invoked.
- ///
- /// The context for the action.
- /// A cancellation token for signaling task ending.
- ///
- /// Thrown if is .
- ///
- public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
- {
- if (actionExecutedContext == null)
- {
- throw new ArgumentNullException(nameof(actionExecutedContext));
- }
-
- var dependencyScope = actionExecutedContext.Request.GetDependencyScope();
- var lifetimeScope = dependencyScope.GetRequestLifetimeScope();
-
- var filters = lifetimeScope.Resolve>>>();
-
- // Issue #16: OnActionExecuted needs to happen in the opposite order of OnActionExecuting.
- foreach (var filter in filters.Where(this.FilterMatchesMetadata).Reverse())
- {
- await filter.Value.Value.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
- }
- }
-
- ///
- /// Occurs before the action method is invoked.
- ///
- /// The context for the action.
- /// A cancellation token for signaling task ending.
- ///
- /// Thrown if is .
- ///
- public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
- {
- if (actionContext == null)
- {
- throw new ArgumentNullException(nameof(actionContext));
- }
-
- var dependencyScope = actionContext.Request.GetDependencyScope();
- var lifetimeScope = dependencyScope.GetRequestLifetimeScope();
-
- var filters = lifetimeScope.Resolve>>>();
-
- // Need to know the set of filters that we've executed so far, so
- // we can go back through them.
- var executedFilters = new List();
-
- // Issue #16: OnActionExecuted needs to happen in the opposite order of OnActionExecuting.
- foreach (var filter in filters.Where(this.FilterMatchesMetadata))
- {
- await filter.Value.Value.OnActionExecutingAsync(actionContext, cancellationToken);
-
- // Issue #30: If an actionfilter sets a response, it should prevent the others from running
- // their own OnActionExecuting methods, and call OnActionExecuted on already-run
- // filters.
- // The OnActionExecutedAsync method of the wrapper will never fire if there
- // is a response set, so we must call the OnActionExecutedAsync of prior filters
- // ourselves.
- if (actionContext.Response != null)
- {
- await ExecuteManualOnActionExecutedAsync(executedFilters.AsEnumerable().Reverse(), actionContext, cancellationToken);
- break;
- }
-
- executedFilters.Add(filter.Value.Value);
- }
- }
-
- ///
- /// Method to manually invoke OnActionExecutedAsync outside of the filter wrapper's own
- /// OnActionExecuted async method.
- ///
- private async Task ExecuteManualOnActionExecutedAsync(
- IEnumerable filters,
- HttpActionContext actionContext,
- CancellationToken cancellationToken)
- {
- HttpActionExecutedContext localExecutedContext = null;
-
- foreach (var alreadyRanFilter in filters)
- {
- if (localExecutedContext == null)
- {
- localExecutedContext = new HttpActionExecutedContext
- {
- ActionContext = actionContext,
- Response = actionContext.Response
- };
- }
-
- await alreadyRanFilter.OnActionExecutedAsync(localExecutedContext, cancellationToken);
- }
- }
-
- private bool FilterMatchesMetadata(Meta> filter)
- {
- var metadata = filter.Metadata.TryGetValue(AutofacWebApiFilterProvider.FilterMetadataKey, out var metadataAsObject)
- ? metadataAsObject as FilterMetadata
- : null;
-
- return _allFilters.Contains(metadata);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Autofac.Integration.WebApi/Autofac.Integration.WebApi.csproj b/src/Autofac.Integration.WebApi/Autofac.Integration.WebApi.csproj
index d12d4a3..f3b875f 100644
--- a/src/Autofac.Integration.WebApi/Autofac.Integration.WebApi.csproj
+++ b/src/Autofac.Integration.WebApi/Autofac.Integration.WebApi.csproj
@@ -51,9 +51,10 @@
CodeAnalysisDictionary.xml
-
+
+
+
-
@@ -68,6 +69,7 @@
+
diff --git a/src/Autofac.Integration.WebApi/AutofacActionFilterAdapter.cs b/src/Autofac.Integration.WebApi/AutofacActionFilterAdapter.cs
new file mode 100644
index 0000000..ad3385e
--- /dev/null
+++ b/src/Autofac.Integration.WebApi/AutofacActionFilterAdapter.cs
@@ -0,0 +1,140 @@
+// This software is part of the Autofac IoC container
+// Copyright (c) 2012 Autofac Contributors
+// https://autofac.org
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// Portions of this file come from the Microsoft ASP.NET web stack, licensed
+// under the Apache 2.0 license. You may obtain a copy of the license at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Net.Http;
+using System.Runtime.ExceptionServices;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Web.Http.Controllers;
+using System.Web.Http.Filters;
+
+namespace Autofac.Integration.WebApi
+{
+ ///
+ /// This is an adapter responsible for wrapping the old style
+ /// and converting it to a .
+ ///
+ ///
+ /// The adapter from old -> new is registered in .
+ ///
+ internal class AutofacActionFilterAdapter : IAutofacContinuationActionFilter
+ {
+ private readonly IAutofacActionFilter _legacyFilter;
+
+ public AutofacActionFilterAdapter(IAutofacActionFilter legacyFilter)
+ {
+ _legacyFilter = legacyFilter;
+ }
+
+ public async Task ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func> continuation)
+ {
+ await _legacyFilter.OnActionExecutingAsync(actionContext, cancellationToken);
+
+ if (actionContext.Response != null)
+ {
+ return actionContext.Response;
+ }
+
+ return await CallOnActionExecutedAsync(actionContext, cancellationToken, continuation);
+ }
+
+ ///
+ /// The content of this method is taken from the ActionFilterAttribute code in the ASP.NET source, since
+ /// that is basically the reference implementation for invoking an async filter's OnActionExecuted correctly.
+ ///
+ [SuppressMessage("Microsoft.CodeQuality", "CA1068", Justification = "Matching parameter order in original implementtion.")]
+ private async Task CallOnActionExecutedAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func> continuation)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ HttpResponseMessage response = null;
+ ExceptionDispatchInfo exceptionInfo = null;
+
+ try
+ {
+ response = await continuation();
+ }
+ catch (Exception e)
+ {
+ exceptionInfo = ExceptionDispatchInfo.Capture(e);
+ }
+
+ Exception exception;
+
+ if (exceptionInfo == null)
+ {
+ exception = null;
+ }
+ else
+ {
+ exception = exceptionInfo.SourceException;
+ }
+
+ HttpActionExecutedContext executedContext = new HttpActionExecutedContext(actionContext, exception)
+ {
+ Response = response
+ };
+
+ try
+ {
+ await _legacyFilter.OnActionExecutedAsync(executedContext, cancellationToken);
+ }
+ catch
+ {
+ // Catch is running because OnActionExecuted threw an exception, so we just want to re-throw.
+ // We also need to reset the response to forget about it since a filter threw an exception.
+ actionContext.Response = null;
+ throw;
+ }
+
+ if (executedContext.Response != null)
+ {
+ return executedContext.Response;
+ }
+
+ Exception newException = executedContext.Exception;
+
+ if (newException != null)
+ {
+ if (newException == exception)
+ {
+ exceptionInfo.Throw();
+ }
+ else
+ {
+ throw newException;
+ }
+ }
+
+ throw new InvalidOperationException();
+ }
+ }
+}
diff --git a/src/Autofac.Integration.WebApi/AutofacWebApiFilterProvider.cs b/src/Autofac.Integration.WebApi/AutofacWebApiFilterProvider.cs
index cbc8b67..1889c68 100644
--- a/src/Autofac.Integration.WebApi/AutofacWebApiFilterProvider.cs
+++ b/src/Autofac.Integration.WebApi/AutofacWebApiFilterProvider.cs
@@ -150,8 +150,8 @@ private static void ResolveAllScopedFilterOverrides(
ILifetimeScope lifeTimeScope,
HttpActionDescriptor descriptor)
{
- ResolveScopedFilter(
- filterContext, scope, lifeTimeScope, descriptor, hs => new ActionFilterOverrideWrapper(hs), AutofacFilterCategory.ActionFilterOverride);
+ ResolveScopedFilter(
+ filterContext, scope, lifeTimeScope, descriptor, hs => new ContinuationActionFilterOverrideWrapper(hs), AutofacFilterCategory.ActionFilterOverride);
ResolveScopedFilter(
filterContext, scope, lifeTimeScope, descriptor, hs => new AuthenticationFilterOverrideWrapper(hs), AutofacFilterCategory.AuthenticationFilterOverride);
ResolveScopedFilter(
@@ -162,8 +162,8 @@ private static void ResolveAllScopedFilterOverrides(
private static void ResolveAllScopedFilters(FilterContext filterContext, FilterScope scope, ILifetimeScope lifeTimeScope, HttpActionDescriptor descriptor)
{
- ResolveScopedFilter(
- filterContext, scope, lifeTimeScope, descriptor, hs => new ActionFilterWrapper(hs), AutofacFilterCategory.ActionFilter);
+ ResolveScopedFilter(
+ filterContext, scope, lifeTimeScope, descriptor, hs => new ContinuationActionFilterWrapper(hs), AutofacFilterCategory.ActionFilter);
ResolveScopedFilter(
filterContext, scope, lifeTimeScope, descriptor, hs => new AuthenticationFilterWrapper(hs), AutofacFilterCategory.AuthenticationFilter);
ResolveScopedFilter(
diff --git a/src/Autofac.Integration.WebApi/ActionFilterOverrideWrapper.cs b/src/Autofac.Integration.WebApi/ContinuationActionFilterOverrideWrapper.cs
similarity index 80%
rename from src/Autofac.Integration.WebApi/ActionFilterOverrideWrapper.cs
rename to src/Autofac.Integration.WebApi/ContinuationActionFilterOverrideWrapper.cs
index 304c25b..99ba89d 100644
--- a/src/Autofac.Integration.WebApi/ActionFilterOverrideWrapper.cs
+++ b/src/Autofac.Integration.WebApi/ContinuationActionFilterOverrideWrapper.cs
@@ -1,5 +1,5 @@
// This software is part of the Autofac IoC container
-// Copyright (c) 2013 Autofac Contributors
+// Copyright (c) 2012 Autofac Contributors
// https://autofac.org
//
// Permission is hereby granted, free of charge, to any person
@@ -32,14 +32,13 @@ namespace Autofac.Integration.WebApi
///
/// Resolves a filter override for the specified metadata for each controller request.
///
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
- internal sealed class ActionFilterOverrideWrapper : ActionFilterWrapper, IOverrideFilter
+ internal sealed class ContinuationActionFilterOverrideWrapper : ContinuationActionFilterWrapper, IOverrideFilter
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The filter metadata.
- public ActionFilterOverrideWrapper(HashSet filterMetadata)
+ public ContinuationActionFilterOverrideWrapper(HashSet filterMetadata)
: base(filterMetadata)
{
}
@@ -52,4 +51,4 @@ public Type FiltersToOverride
get { return typeof(IActionFilter); }
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Autofac.Integration.WebApi/ContinuationActionFilterWrapper.cs b/src/Autofac.Integration.WebApi/ContinuationActionFilterWrapper.cs
new file mode 100644
index 0000000..5fc34c9
--- /dev/null
+++ b/src/Autofac.Integration.WebApi/ContinuationActionFilterWrapper.cs
@@ -0,0 +1,98 @@
+// This software is part of the Autofac IoC container
+// Copyright (c) 2012 Autofac Contributors
+// https://autofac.org
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Web.Http.Controllers;
+using System.Web.Http.Filters;
+using Autofac.Features.Metadata;
+
+namespace Autofac.Integration.WebApi
+{
+ ///
+ /// Resolves a filter for the specified metadata for each controller request.
+ ///
+ internal class ContinuationActionFilterWrapper : IActionFilter, IAutofacContinuationActionFilter
+ {
+ private readonly HashSet _allFilters;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The collection of filter metadata blocks that this wrapper should run.
+ public ContinuationActionFilterWrapper(HashSet filterMetadata)
+ {
+ if (filterMetadata == null)
+ {
+ throw new ArgumentNullException(nameof(filterMetadata));
+ }
+
+ _allFilters = filterMetadata;
+ }
+
+ public bool AllowMultiple { get; } = true;
+
+ public Task ExecuteActionFilterAsync(
+ HttpActionContext actionContext,
+ CancellationToken cancellationToken,
+ Func> continuation)
+ {
+ var dependencyScope = actionContext.Request.GetDependencyScope();
+ var lifetimeScope = dependencyScope.GetRequestLifetimeScope();
+
+ var filters = lifetimeScope.Resolve>>>();
+
+ Func> result = continuation;
+
+ Func> ChainContinuation(Func> next, IAutofacContinuationActionFilter innerFilter)
+ {
+ return () => innerFilter.ExecuteActionFilterAsync(actionContext, cancellationToken, next);
+ }
+
+ // We go backwards for the beginning of the set of filters, where
+ // the last one invokes the provided continuation, the previous one invokes the last one, and so on,
+ // until there's a callback that invokes the first filter.
+ foreach (var filterStage in filters.Reverse().Where(FilterMatchesMetadata))
+ {
+ result = ChainContinuation(result, filterStage.Value.Value);
+ }
+
+ return result();
+ }
+
+ private bool FilterMatchesMetadata(Meta> filter)
+ {
+ var metadata = filter.Metadata.TryGetValue(AutofacWebApiFilterProvider.FilterMetadataKey, out var metadataAsObject)
+ ? metadataAsObject as FilterMetadata
+ : null;
+
+ return _allFilters.Contains(metadata);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Autofac.Integration.WebApi/IAutofacContinuationActionFilter.cs b/src/Autofac.Integration.WebApi/IAutofacContinuationActionFilter.cs
new file mode 100644
index 0000000..ab94264
--- /dev/null
+++ b/src/Autofac.Integration.WebApi/IAutofacContinuationActionFilter.cs
@@ -0,0 +1,54 @@
+// This software is part of the Autofac IoC container
+// Copyright (c) 2012 Autofac Contributors
+// https://autofac.org
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Web.Http.Controllers;
+
+namespace Autofac.Integration.WebApi
+{
+ ///
+ /// An action filter that will be created for each controller request, and
+ /// executes using continuations, so the async context is preserved.
+ ///
+ public interface IAutofacContinuationActionFilter
+ {
+ ///
+ /// The method called when the filter executes. The filter should call 'next' to
+ /// continue processing the request.
+ ///
+ /// The context of the current action.
+ /// A cancellation token for the request.
+ /// The function to call that invokes the next filter in the chain.
+ [SuppressMessage("Microsoft.CodeQuality", "CA1068", Justification = "Matching parameter order in IActionFilter.")]
+ Task ExecuteActionFilterAsync(
+ HttpActionContext actionContext,
+ CancellationToken cancellationToken,
+ Func> next);
+ }
+}
\ No newline at end of file
diff --git a/src/Autofac.Integration.WebApi/RegistrationExtensions.cs b/src/Autofac.Integration.WebApi/RegistrationExtensions.cs
index 2b74cbf..cff1099 100644
--- a/src/Autofac.Integration.WebApi/RegistrationExtensions.cs
+++ b/src/Autofac.Integration.WebApi/RegistrationExtensions.cs
@@ -36,6 +36,7 @@
using System.Web.Http.ModelBinding;
using Autofac.Builder;
using Autofac.Core;
+using Autofac.Features.Metadata;
using Autofac.Features.Scanning;
namespace Autofac.Integration.WebApi
@@ -242,10 +243,14 @@ public static void RegisterWebApiFilterProvider(this ContainerBuilder builder, H
builder.Register(c => new AutofacWebApiFilterProvider(c.Resolve()))
.As()
.SingleInstance(); // It would be nice to scope this per request.
+
+ // Register the adapter to turn the old IAutofacActionFilters into the new continuation style.
+ builder.RegisterAdapter(
+ legacy => new AutofacActionFilterAdapter(legacy));
}
///
- /// Sets the provided registration to act as an for the specified controller action.
+ /// Sets the provided registration to act as an or for the specified controller action.
///
/// The type of the controller.
/// The registration.
@@ -257,11 +262,11 @@ public static IRegistrationBuilder