-
Notifications
You must be signed in to change notification settings - Fork 0
/
DefaultValidatorOptions.cs
279 lines (248 loc) · 14.2 KB
/
DefaultValidatorOptions.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#region License
// Copyright (c) Jeremy Skinner (http://www.jeremyskinner.co.uk)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// The latest version of this file can be found at http://www.codeplex.com/FluentValidation
#endregion
namespace FluentValidation {
using System;
using System.Linq;
using System.Linq.Expressions;
using Internal;
using Resources;
using Validators;
/// <summary>
/// Default options that can be used to configure a validator.
/// </summary>
public static class DefaultValidatorOptions {
/// <summary>
/// Specifies the cascade mode for failures.
/// If set to 'Stop' then execution of the rule will stop once the first validator in the chain fails.
/// If set to 'Continue' then all validators in the chain will execute regardless of failures.
/// </summary>
public static IRuleBuilderInitial<T, TProperty> Cascade<T, TProperty>(this IRuleBuilderInitial<T, TProperty> ruleBuilder, CascadeMode cascadeMode) {
return ruleBuilder.Configure(cfg => {
cfg.CascadeMode = cascadeMode;
});
}
/// <summary>
/// Specifies a custom action to be invoked when the validator fails.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="rule"></param>
/// <param name="onFailure"></param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> OnAnyFailure<T, TProperty>(this IRuleBuilderOptions<T,TProperty> rule, Action<T> onFailure) {
return rule.Configure(config => {
config.OnFailure = onFailure.CoerceToNonGeneric();
});
}
/// <summary>
/// Specifies a custom error message to use if validation fails.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="errorMessage">The error message to use</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> WithMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string errorMessage) {
return rule.WithMessage(errorMessage, null as object[]);
}
/// <summary>
/// Specifies a custom error message to use if validation fails.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="errorMessage">The error message to use</param>
/// <param name="formatArgs">Additional arguments to be specified when formatting the custom error message.</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> WithMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string errorMessage, params object[] formatArgs) {
var funcs = ConvertArrayOfObjectsToArrayOfDelegates<T>(formatArgs);
return rule.WithMessage(errorMessage, funcs);
}
/// <summary>
/// Specifies a custom error message to use if validation fails.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="errorMessage">The error message to use</param>
/// <param name="funcs">Additional property values to be included when formatting the custom error message.</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> WithMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string errorMessage, params Func<T, object>[] funcs) {
errorMessage.Guard("A message must be specified when calling WithMessage.");
return rule.Configure(config => {
config.CurrentValidator.ErrorMessageSource = new StaticStringSource(errorMessage);
funcs
.Select(func => new Func<object, object, object>((instance, value) => func((T)instance)))
.ForEach(config.CurrentValidator.CustomMessageFormatArguments.Add);
});
}
/// <summary>
/// Specifies a custom error message to use if validation fails.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="errorMessage">The error message to use</param>
/// <param name="funcs">Additional property values to use when formatting the custom error message.</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> WithMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string errorMessage, params Func<T, TProperty, object>[] funcs) {
errorMessage.Guard("A message must be specified when calling WithMessage.");
return rule.Configure(config => {
config.CurrentValidator.ErrorMessageSource = new StaticStringSource(errorMessage);
funcs
.Select(func => new Func<object, object, object>((instance, value) => func((T)instance, (TProperty)value)))
.ForEach(config.CurrentValidator.CustomMessageFormatArguments.Add);
});
}
/// <summary>
/// Specifies a custom error message resource to use when validation fails.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="resourceSelector">The resource to use as an expression, eg () => Messages.MyResource</param>
/// <returns></returns>
public static IRuleBuilderOptions<T,TProperty> WithLocalizedMessage<T,TProperty>(this IRuleBuilderOptions<T,TProperty> rule, Expression<Func<string>> resourceSelector) {
// We use the StaticResourceAccessorBuilder here because we don't want calls to WithLocalizedMessage to be overriden by the ResourceProviderType.
return rule.WithLocalizedMessage(resourceSelector, new StaticResourceAccessorBuilder());
}
/// <summary>
/// Specifies a custom error message resource to use when validation fails.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="resourceSelector">The resource to use as an expression, eg () => Messages.MyResource</param>
/// <param name="formatArgs">Custom message format args</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> WithLocalizedMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, Expression<Func<string>> resourceSelector, params object[] formatArgs) {
var funcs = ConvertArrayOfObjectsToArrayOfDelegates<T>(formatArgs);
return rule.WithLocalizedMessage(resourceSelector, funcs);
}
/// <summary>
/// Specifies a custom error message resource to use when validation fails.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="resourceSelector">The resource to use as an expression, eg () => Messages.MyResource</param>
/// <param name="formatArgs">Custom message format args</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> WithLocalizedMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, Expression<Func<string>> resourceSelector, params Func<T, object>[] formatArgs) {
// We use the StaticResourceAccessorBuilder here because we don't want calls to WithLocalizedMessage to be overriden by the ResourceProviderType.
return rule.WithLocalizedMessage(resourceSelector, new StaticResourceAccessorBuilder())
.Configure(cfg => {
formatArgs
.Select(func => new Func<object, object, object>((instance, value) => func((T)instance)))
.ForEach(cfg.CurrentValidator.CustomMessageFormatArguments.Add);
});
}
/// <summary>
/// Specifies a custom error message resource to use when validation fails.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="resourceSelector">The resource to use as an expression, eg () => Messages.MyResource</param>
/// <param name="resourceAccessorBuilder">The resource accessor builder to use. </param>
/// <returns></returns>
public static IRuleBuilderOptions<T,TProperty> WithLocalizedMessage<T,TProperty>(this IRuleBuilderOptions<T,TProperty> rule, Expression<Func<string>> resourceSelector, IResourceAccessorBuilder resourceAccessorBuilder) {
resourceSelector.Guard("An expression must be specified when calling WithLocalizedMessage, eg .WithLocalizedMessage(() => Messages.MyResource)");
return rule.Configure(config => {
config.CurrentValidator.ErrorMessageSource = LocalizedStringSource.CreateFromExpression(resourceSelector, resourceAccessorBuilder);
});
}
/// <summary>
/// Specifies a condition limiting when the validator should run.
/// The validator will only be executed if the result of the lambda returns true.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="predicate">A lambda expression that specifies a condition for when the validator should run</param>
/// <param name="applyConditionTo">Whether the condition should be applied to the current rule or all rules in the chain</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> When<T,TProperty>(this IRuleBuilderOptions<T, TProperty> rule, Func<T, bool> predicate, ApplyConditionTo applyConditionTo = ApplyConditionTo.AllValidators) {
predicate.Guard("A predicate must be specified when calling When.");
// Default behaviour for When/Unless as of v1.3 is to apply the condition to all previous validators in the chain.
return rule.Configure(config => {
config.ApplyCondition(predicate.CoerceToNonGeneric(), applyConditionTo);
});
}
/// <summary>
/// Specifies a condition limiting when the validator should not run.
/// The validator will only be executed if the result of the lambda returns false.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="predicate">A lambda expression that specifies a condition for when the validator should not run</param>
/// <param name="applyConditionTo">Whether the condition should be applied to the current rule or all rules in the chain</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> Unless<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, Func<T, bool> predicate, ApplyConditionTo applyConditionTo = ApplyConditionTo.AllValidators) {
predicate.Guard("A predicate must be specified when calling Unless");
return rule.When(x => !predicate(x), applyConditionTo);
}
/// <summary>
/// Specifies a custom property name to use within the error message.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="overridePropertyName">The property name to use</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> WithName<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string overridePropertyName) {
overridePropertyName.Guard("A property name must be specified when calling WithName.");
return rule.Configure(config => {
config.DisplayName = new StaticStringSource(overridePropertyName);
});
}
/// <summary>
/// Specifies a localized name for the error message.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="resourceSelector">The resource to use as an expression, eg () => Messages.MyResource</param>
/// <param name="resourceAccessorBuilder">Resource accessor builder to use</param>
public static IRuleBuilderOptions<T, TProperty> WithLocalizedName<T,TProperty>(this IRuleBuilderOptions<T,TProperty> rule, Expression<Func<string>> resourceSelector, IResourceAccessorBuilder resourceAccessorBuilder = null) {
resourceSelector.Guard("A resource selector must be specified.");
// default to the static resource accessor builder - explicit resources configured with WithLocalizedName should take precedence over ResourceProviderType.
resourceAccessorBuilder = resourceAccessorBuilder ?? new StaticResourceAccessorBuilder();
return rule.Configure(config => {
config.DisplayName = LocalizedStringSource.CreateFromExpression(resourceSelector, resourceAccessorBuilder);
});
}
/// <summary>
/// Overrides the name of the property associated with this rule.
/// NOTE: This is a considered to be an advanced feature. 99% of the time that you use this, you actually meant to use WithName.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="propertyName">The property name to use</param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> OverridePropertyName<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string propertyName) {
propertyName.Guard("A property name must be specified when calling WithNamePropertyName.");
return rule.Configure(config => config.PropertyName = propertyName);
}
/// <summary>
/// Overrides the name of the property associated with this rule.
/// NOTE: This is a considered to be an advanced feature. 99% of the time that you use this, you actually meant to use WithName.
/// </summary>
/// <param name="rule">The current rule</param>
/// <param name="propertyName">The property name to use</param>
/// <returns></returns>
[Obsolete("WithPropertyName has been deprecated. If you wish to set the name of the property within the error message, use 'WithName'. If you actually intended to change which property this rule was declared against, use 'OverridePropertyName' instead.")]
public static IRuleBuilderOptions<T, TProperty> WithPropertyName<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, string propertyName) {
return rule.OverridePropertyName(propertyName);
}
/// <summary>
/// Specifies custom state that should be stored alongside the validation message when validation fails for this rule.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="rule"></param>
/// <param name="stateProvider"></param>
/// <returns></returns>
public static IRuleBuilderOptions<T, TProperty> WithState<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, Func<T, object> stateProvider) {
stateProvider.Guard("A lambda expression must be passed to WithState");
return rule.Configure(config => config.CurrentValidator.CustomStateProvider = stateProvider.CoerceToNonGeneric());
}
static Func<T, object>[] ConvertArrayOfObjectsToArrayOfDelegates<T>(object[] objects) {
if(objects == null || objects.Length == 0) {
return new Func<T, object>[0];
}
return objects.Select(obj => new Func<T, object>(x => obj)).ToArray();
}
}
}