| File: ApplicationModels\ApiBehaviorApplicationModelProvider.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.Linq; using System.Reflection; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Mvc.ApplicationModels; internal sealed class ApiBehaviorApplicationModelProvider : IApplicationModelProvider { public ApiBehaviorApplicationModelProvider( IOptions<ApiBehaviorOptions> apiBehaviorOptions, IModelMetadataProvider modelMetadataProvider, IServiceProvider serviceProvider) { var options = apiBehaviorOptions.Value; ActionModelConventions = new List<IActionModelConvention>() { new ApiVisibilityConvention(), }; if (!options.SuppressMapClientErrors) { ActionModelConventions.Add(new ClientErrorResultFilterConvention()); } if (!options.SuppressModelStateInvalidFilter) { ActionModelConventions.Add(new InvalidModelStateFilterConvention()); } if (!options.SuppressConsumesConstraintForFormFileParameters) { ActionModelConventions.Add(new ConsumesConstraintForFormFileParameterConvention()); } var defaultErrorType = options.SuppressMapClientErrors ? typeof(void) : typeof(ProblemDetails); var defaultErrorTypeAttribute = new ProducesErrorResponseTypeAttribute(defaultErrorType); ActionModelConventions.Add(new ApiConventionApplicationModelConvention(defaultErrorTypeAttribute)); if (!options.SuppressInferBindingSourcesForParameters) { var serviceProviderIsService = serviceProvider.GetService<IServiceProviderIsService>(); var convention = options.DisableImplicitFromServicesParameters || serviceProviderIsService is null ? new InferParameterBindingInfoConvention(modelMetadataProvider) : new InferParameterBindingInfoConvention(modelMetadataProvider, serviceProviderIsService); ActionModelConventions.Add(convention); } } /// <remarks> /// Order is set to execute after the <see cref="DefaultApplicationModelProvider"/> and allow any other user /// <see cref="IApplicationModelProvider"/> that configure routing to execute. /// </remarks> public int Order => -1000 + 100; public List<IActionModelConvention> ActionModelConventions { get; } public void OnProvidersExecuted(ApplicationModelProviderContext context) { } public void OnProvidersExecuting(ApplicationModelProviderContext context) { foreach (var controller in context.Result.Controllers) { if (!IsApiController(controller)) { continue; } foreach (var action in controller.Actions) { // Ensure ApiController is set up correctly EnsureActionIsAttributeRouted(action); foreach (var convention in ActionModelConventions) { convention.Apply(action); } } } } private static void EnsureActionIsAttributeRouted(ActionModel actionModel) { if (!IsAttributeRouted(actionModel.Controller.Selectors) && !IsAttributeRouted(actionModel.Selectors)) { // Require attribute routing with controllers annotated with ApiControllerAttribute var message = Resources.FormatApiController_AttributeRouteRequired( actionModel.DisplayName, nameof(ApiControllerAttribute)); throw new InvalidOperationException(message); } static bool IsAttributeRouted(IList<SelectorModel> selectorModel) { for (var i = 0; i < selectorModel.Count; i++) { if (selectorModel[i].AttributeRouteModel != null) { return true; } } return false; } } private static bool IsApiController(ControllerModel controller) { if (controller.Attributes.OfType<IApiBehaviorMetadata>().Any()) { return true; } var controllerAssembly = controller.ControllerType.Assembly; var assemblyAttributes = controllerAssembly.GetCustomAttributes(); return assemblyAttributes.OfType<IApiBehaviorMetadata>().Any(); } }