aspnetcore/src/Microsoft.AspNetCore.Mvc.Core/Internal/ApplicationModelConventions.cs

119 lines
4.7 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace Microsoft.AspNetCore.Mvc.Internal
{
/// <summary>
/// Applies conventions to a <see cref="ApplicationModel"/>.
/// </summary>
public static class ApplicationModelConventions
{
/// <summary>
/// Applies conventions to a <see cref="ApplicationModel"/>.
/// </summary>
/// <param name="applicationModel">The <see cref="ApplicationModel"/>.</param>
/// <param name="conventions">The set of conventions.</param>
public static void ApplyConventions(
ApplicationModel applicationModel,
IEnumerable<IApplicationModelConvention> conventions)
{
if (applicationModel == null)
{
throw new ArgumentNullException(nameof(applicationModel));
}
if (conventions == null)
{
throw new ArgumentNullException(nameof(conventions));
}
// Conventions are applied from the outside-in to allow for scenarios where an action overrides
// a controller, etc.
foreach (var convention in conventions)
{
convention.Apply(applicationModel);
}
var controllers = applicationModel.Controllers.ToArray();
// First apply the conventions from attributes in decreasing order of scope.
foreach (var controller in controllers)
{
// ToArray is needed here to prevent issues with modifying the attributes collection
// while iterating it.
var controllerConventions =
controller.Attributes
.OfType<IControllerModelConvention>()
.ToArray();
foreach (var controllerConvention in controllerConventions)
{
controllerConvention.Apply(controller);
}
var actions = controller.Actions.ToArray();
foreach (var action in actions)
{
// ToArray is needed here to prevent issues with modifying the attributes collection
// while iterating it.
var actionConventions =
action.Attributes
.OfType<IActionModelConvention>()
.ToArray();
foreach (var actionConvention in actionConventions)
{
actionConvention.Apply(action);
}
var parameters = action.Parameters.ToArray();
foreach (var parameter in parameters)
{
// ToArray is needed here to prevent issues with modifying the attributes collection
// while iterating it.
var parameterConventions =
parameter.Attributes
.OfType<IParameterModelConvention>()
.ToArray();
foreach (var parameterConvention in parameterConventions)
{
parameterConvention.Apply(parameter);
}
var parameterBaseConventions = GetConventions<IParameterModelBaseConvention>(conventions, parameter.Attributes);
foreach (var parameterConvention in parameterBaseConventions)
{
parameterConvention.Apply(parameter);
}
}
}
var properties = controller.ControllerProperties.ToArray();
foreach (var property in properties)
{
var parameterBaseConventions = GetConventions<IParameterModelBaseConvention>(conventions, property.Attributes);
foreach (var parameterConvention in parameterBaseConventions)
{
parameterConvention.Apply(property);
}
}
}
}
private static IEnumerable<TConvention> GetConventions<TConvention>(
IEnumerable<IApplicationModelConvention> conventions,
IReadOnlyList<object> attributes)
{
return Enumerable.Concat(
conventions.OfType<TConvention>(),
attributes.OfType<TConvention>());
}
}
}