This repository has been archived by the owner on Dec 14, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
WebApiActionConventionsApplicationModelConvention.cs
117 lines (101 loc) · 3.94 KB
/
WebApiActionConventionsApplicationModelConvention.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
// 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;
using Microsoft.AspNetCore.Mvc.Internal;
namespace Microsoft.AspNetCore.Mvc.WebApiCompatShim
{
public class WebApiActionConventionsApplicationModelConvention : IControllerModelConvention
{
private static readonly string[] SupportedHttpMethodConventions = new string[]
{
"GET",
"PUT",
"POST",
"DELETE",
"PATCH",
"HEAD",
"OPTIONS",
};
public void Apply(ControllerModel controller)
{
if (controller == null)
{
throw new ArgumentNullException(nameof(controller));
}
if (IsConventionApplicable(controller))
{
var newActions = new List<ActionModel>();
foreach (var action in controller.Actions)
{
SetHttpMethodFromConvention(action);
// Action Name doesn't really come into play with attribute routed actions. However for a
// non-attribute-routed action we need to create a 'named' version and an 'unnamed' version.
if (!IsActionAttributeRouted(action))
{
var namedAction = action;
var unnamedAction = new ActionModel(namedAction);
unnamedAction.RouteValues.Add("action", null);
newActions.Add(unnamedAction);
}
}
foreach (var action in newActions)
{
controller.Actions.Add(action);
}
}
}
private bool IsConventionApplicable(ControllerModel controller)
{
return controller.Attributes.OfType<IUseWebApiActionConventions>().Any();
}
private bool IsActionAttributeRouted(ActionModel action)
{
foreach (var controllerSelectorModel in action.Controller.Selectors)
{
if (controllerSelectorModel.AttributeRouteModel?.Template != null)
{
return true;
}
}
foreach (var actionSelectorModel in action.Selectors)
{
if (actionSelectorModel.AttributeRouteModel?.Template != null)
{
return true;
}
}
return false;
}
private void SetHttpMethodFromConvention(ActionModel action)
{
foreach (var selector in action.Selectors)
{
if (selector.ActionConstraints.OfType<HttpMethodActionConstraint>().Count() > 0)
{
// If the HttpMethods are set from attributes, don't override it with the convention
return;
}
}
// The Method name is used to infer verb constraints. Changing the action name has no impact.
foreach (var verb in SupportedHttpMethodConventions)
{
if (action.ActionMethod.Name.StartsWith(verb, StringComparison.OrdinalIgnoreCase))
{
foreach (var selector in action.Selectors)
{
selector.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { verb }));
}
return;
}
}
// If no convention matches, then assume POST
foreach (var actionSelectorModel in action.Selectors)
{
actionSelectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { "POST" }));
}
}
}
}