forked from aspnet/AspNetWebStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathModelBinderAttribute.cs
More file actions
154 lines (132 loc) · 5.9 KB
/
Copy pathModelBinderAttribute.cs
File metadata and controls
154 lines (132 loc) · 5.9 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// 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.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Web.Http.Controllers;
using System.Web.Http.Dependencies;
using System.Web.Http.ModelBinding.Binders;
using System.Web.Http.Properties;
using System.Web.Http.ValueProviders;
namespace System.Web.Http.ModelBinding
{
/// <summary>
/// Specify this parameter uses a model binder. This can optionally specify the specific model binder and
/// value providers that drive that model binder.
/// Derived attributes may provide convenience settings for the model binder or value provider.
/// </summary>
[SuppressMessage("Microsoft.Design", "CA1019:DefineAccessorsForAttributeArguments", Justification = "want constructor argument shortcut")]
[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "part of a class hierarchy")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
public class ModelBinderAttribute : ParameterBindingAttribute
{
public ModelBinderAttribute()
: this(null)
{
}
public ModelBinderAttribute(Type binderType)
{
BinderType = binderType;
}
/// <summary>
/// Sets the type of the model binder.
/// This type must be a subclass of <see cref="ModelBinderProvider"/> or <see cref="IModelBinder"/>
/// If null, uses the default from the configuration.
/// </summary>
public Type BinderType { get; set; }
/// <summary>
/// Gets or sets the name to consider as the parameter name during model binding
/// </summary>
public string Name { get; set; }
public bool SuppressPrefixCheck { get; set; }
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
HttpConfiguration config = parameter.Configuration;
IModelBinder binder = GetModelBinder(config, parameter.ParameterType);
IEnumerable<ValueProviderFactory> valueProviderFactories = GetValueProviderFactories(config);
return new ModelBinderParameterBinding(parameter, binder, valueProviderFactories);
}
// This will get called by a parameter binding, which will cache the results.
public ModelBinderProvider GetModelBinderProvider(HttpConfiguration configuration)
{
if (BinderType != null)
{
object value = GetOrInstantiate(configuration, BinderType);
if (value != null)
{
VerifyBinderType(value.GetType());
ModelBinderProvider result = (ModelBinderProvider)value;
return result;
}
}
// Create default over config
IEnumerable<ModelBinderProvider> providers = configuration.Services.GetModelBinderProviders();
if (providers.Count() == 1)
{
return providers.First();
}
return new CompositeModelBinderProvider(providers);
}
/// <summary>
/// Get the IModelBinder for this type.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="modelType">model type that the binder is expected to bind.</param>
/// <returns>
/// a non-null model binder.
/// </returns>
public IModelBinder GetModelBinder(HttpConfiguration configuration, Type modelType)
{
if (BinderType == null)
{
ModelBinderProvider provider = GetModelBinderProvider(configuration);
return provider.GetBinder(configuration, modelType);
}
// This may create a IModelBinder or a ModelBinderProvider
object value = GetOrInstantiate(configuration, BinderType);
Contract.Assert(value != null); // Activator would have thrown
IModelBinder binder = value as IModelBinder;
if (binder != null)
{
return binder;
}
else
{
ModelBinderProvider provider = value as ModelBinderProvider;
if (provider != null)
{
return provider.GetBinder(configuration, modelType);
}
}
Type required = typeof(IModelBinder);
throw Error.InvalidOperation(SRResources.ValueProviderFactory_Cannot_Create, required.Name, value.GetType().Name, required.Name);
}
/// <summary>
/// Value providers that will be fed to the model binder.
/// </summary>
public virtual IEnumerable<ValueProviderFactory> GetValueProviderFactories(HttpConfiguration configuration)
{
// By default, just get all registered value provider factories
return configuration.Services.GetValueProviderFactories();
}
private static void VerifyBinderType(Type attemptedType)
{
Type required = typeof(ModelBinderProvider);
if (!required.IsAssignableFrom(attemptedType))
{
throw Error.InvalidOperation(SRResources.ValueProviderFactory_Cannot_Create, required.Name, attemptedType.Name, required.Name);
}
}
private static object GetOrInstantiate(HttpConfiguration configuration, Type type)
{
IDependencyResolver dr = configuration.DependencyResolver;
object value = dr.GetService(type);
if (value != null)
{
return value;
}
return Activator.CreateInstance(type);
}
}
}