| File: Routing\ControllerRequestDelegateFactory.cs | Web Access |
| Project: src\aspnetcore\src\Mvc\Mvc.Core\src\Microsoft.AspNetCore.Mvc.Core.csproj (Microsoft.AspNetCore.Mvc.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Mvc.Routing; internal sealed class ControllerRequestDelegateFactory : IRequestDelegateFactory { private readonly ControllerActionInvokerCache _controllerActionInvokerCache; private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories; private readonly int _maxModelValidationErrors; private readonly int? _maxValidationDepth; private readonly int _maxModelBindingRecursionDepth; private readonly ILogger _logger; private readonly DiagnosticListener _diagnosticListener; private readonly IActionResultTypeMapper _mapper; #pragma warning disable ASPDEPR006 // Type or member is obsolete private readonly IActionContextAccessor _actionContextAccessor; #pragma warning restore ASPDEPR006 // Type or member is obsolete private readonly bool _enableActionInvokers; public ControllerRequestDelegateFactory( ControllerActionInvokerCache controllerActionInvokerCache, IOptions<MvcOptions> optionsAccessor, ILoggerFactory loggerFactory, DiagnosticListener diagnosticListener, IActionResultTypeMapper mapper) : this(controllerActionInvokerCache, optionsAccessor, loggerFactory, diagnosticListener, mapper, null) { } public ControllerRequestDelegateFactory( ControllerActionInvokerCache controllerActionInvokerCache, IOptions<MvcOptions> optionsAccessor, ILoggerFactory loggerFactory, DiagnosticListener diagnosticListener, IActionResultTypeMapper mapper, #pragma warning disable ASPDEPR006 // Type or member is obsolete IActionContextAccessor? actionContextAccessor) #pragma warning restore ASPDEPR006 // Type or member is obsolete { _controllerActionInvokerCache = controllerActionInvokerCache; _valueProviderFactories = optionsAccessor.Value.ValueProviderFactories.ToArray(); _maxModelValidationErrors = optionsAccessor.Value.MaxModelValidationErrors; _maxValidationDepth = optionsAccessor.Value.MaxValidationDepth; _maxModelBindingRecursionDepth = optionsAccessor.Value.MaxModelBindingRecursionDepth; _enableActionInvokers = optionsAccessor.Value.EnableActionInvokers; _logger = loggerFactory.CreateLogger<ControllerActionInvoker>(); _diagnosticListener = diagnosticListener; _mapper = mapper; #pragma warning disable ASPDEPR006 // Type or member is obsolete _actionContextAccessor = actionContextAccessor ?? ActionContextAccessor.Null; #pragma warning restore ASPDEPR006 // Type or member is obsolete } public RequestDelegate? CreateRequestDelegate(ActionDescriptor actionDescriptor, RouteValueDictionary? dataTokens) { // Fallback to action invoker extensibility so that invokers can override any default behaviors if (_enableActionInvokers || actionDescriptor is not ControllerActionDescriptor controller) { return null; } return context => { RouteData routeData; if (dataTokens is null or { Count: 0 }) { routeData = new RouteData(context.Request.RouteValues); } else { routeData = new RouteData(); routeData.PushState(router: null, context.Request.RouteValues, dataTokens); } var controllerContext = new ControllerContext(context, routeData, controller) { // PERF: These are rarely going to be changed, so let's go copy-on-write. ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories) }; controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors; controllerContext.ModelState.MaxValidationDepth = _maxValidationDepth; controllerContext.ModelState.MaxStateDepth = _maxModelBindingRecursionDepth; var (cacheEntry, filters) = _controllerActionInvokerCache.GetCachedResult(controllerContext); var invoker = new ControllerActionInvoker( _logger, _diagnosticListener, _actionContextAccessor, _mapper, controllerContext, cacheEntry, filters); return invoker.InvokeAsync(); }; } }