This repository has been archived by the owner on Dec 14, 2018. It is now read-only.
/
ApiBehaviorApplicationModelProvider.cs
134 lines (114 loc) · 4.93 KB
/
ApiBehaviorApplicationModelProvider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// 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 System.Reflection;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
internal class ApiBehaviorApplicationModelProvider : IApplicationModelProvider
{
public ApiBehaviorApplicationModelProvider(
IOptions<ApiBehaviorOptions> apiBehaviorOptions,
IModelMetadataProvider modelMetadataProvider,
IClientErrorFactory clientErrorFactory,
ILoggerFactory loggerFactory)
{
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 convention = new InferParameterBindingInfoConvention(modelMetadataProvider)
{
AllowInferringBindingSourceForCollectionTypesAsFromQuery = options.AllowInferringBindingSourceForCollectionTypesAsFromQuery,
};
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);
}
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();
}
}
}