Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics;
using System.Web.Mvc;
namespace System.Web.WebPages
{
internal class CompareValidator : RequestFieldValidatorBase
{
private readonly string _otherField;
private readonly ModelClientValidationEqualToRule _clientValidationRule;
public CompareValidator(string otherField, string errorMessage)
: base(errorMessage)
{
Debug.Assert(!String.IsNullOrEmpty(otherField));
_otherField = otherField;
_clientValidationRule = new ModelClientValidationEqualToRule(errorMessage, otherField);
}
public override ModelClientValidationRule ClientValidationRule
{
get { return _clientValidationRule; }
}
protected override bool IsValid(HttpContextBase httpContext, string value)
{
string otherValue = GetRequestValue(httpContext.Request, _otherField);
return String.Equals(value, otherValue, StringComparison.CurrentCulture);
}
}
}

View File

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
namespace System.Web.WebPages
{
internal class DataTypeValidator : RequestFieldValidatorBase
{
private readonly SupportedValidationDataType _dataType;
public DataTypeValidator(SupportedValidationDataType type, string errorMessage = null)
: base(errorMessage)
{
_dataType = type;
}
public enum SupportedValidationDataType
{
DateTime,
Decimal,
Url,
Integer,
Float
}
protected override bool IsValid(HttpContextBase httpContext, string value)
{
if (String.IsNullOrEmpty(value))
{
return true;
}
switch (_dataType)
{
case SupportedValidationDataType.DateTime:
return value.IsDateTime();
case SupportedValidationDataType.Float:
return value.IsFloat();
case SupportedValidationDataType.Decimal:
return value.IsDecimal();
case SupportedValidationDataType.Integer:
return value.IsInt();
case SupportedValidationDataType.Url:
return Uri.IsWellFormedUriString(value, UriKind.Absolute);
}
return true;
}
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace System.Web.WebPages
{
public interface IValidator
{
ModelClientValidationRule ClientValidationRule { get; }
ValidationResult Validate(ValidationContext validationContext);
}
}

View File

@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Web.Helpers;
using System.Web.Mvc;
using Microsoft.Internal.Web.Utils;
namespace System.Web.WebPages
{
public abstract class RequestFieldValidatorBase : IValidator
{
private readonly string _errorMessage;
private readonly bool _useUnvalidatedValues;
protected RequestFieldValidatorBase(string errorMessage)
: this(errorMessage, useUnvalidatedValues: false)
{
}
protected RequestFieldValidatorBase(string errorMessage, bool useUnvalidatedValues)
{
if (String.IsNullOrEmpty(errorMessage))
{
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "errorMessage");
}
_errorMessage = errorMessage;
_useUnvalidatedValues = useUnvalidatedValues;
}
public virtual ModelClientValidationRule ClientValidationRule
{
get { return null; }
}
/// <summary>
/// Meant for unit tests that causes RequestFieldValidatorBase to basically ignore the unvalidated field requirement.
/// </summary>
internal static bool IgnoreUseUnvalidatedValues { get; set; }
protected abstract bool IsValid(HttpContextBase httpContext, string value);
public virtual ValidationResult Validate(ValidationContext validationContext)
{
var httpContext = GetHttpContext(validationContext);
var field = validationContext.MemberName;
var fieldValue = GetRequestValue(httpContext.Request, field);
if (IsValid(httpContext, fieldValue))
{
return ValidationResult.Success;
}
return new ValidationResult(_errorMessage, memberNames: new[] { field });
}
protected static HttpContextBase GetHttpContext(ValidationContext validationContext)
{
Debug.Assert(validationContext.ObjectInstance is HttpContextBase, "For our validation context, ObjectInstance must be an HttpContextBase instance.");
return (HttpContextBase)validationContext.ObjectInstance;
}
protected string GetRequestValue(HttpRequestBase request, string field)
{
if (IgnoreUseUnvalidatedValues)
{
// Make sure we do not set this when we are hosted since this is only meant for unit test scenarios.
Debug.Assert(HttpContext.Current == null, "This flag should not be set when we are hosted.");
return request.Form[field];
}
return _useUnvalidatedValues ? request.Unvalidated(field) : request.Form[field];
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace System.Web.WebPages
{
internal class ValidationAttributeAdapter : RequestFieldValidatorBase
{
private readonly ValidationAttribute _attribute;
private readonly ModelClientValidationRule _clientValidationRule;
public ValidationAttributeAdapter(ValidationAttribute attribute, string errorMessage, ModelClientValidationRule clientValidationRule)
:
this(attribute, errorMessage, clientValidationRule, useUnvalidatedValues: false)
{
}
public ValidationAttributeAdapter(ValidationAttribute attribute, string errorMessage, ModelClientValidationRule clientValidationRule, bool useUnvalidatedValues)
: base(errorMessage, useUnvalidatedValues)
{
_attribute = attribute;
_clientValidationRule = clientValidationRule;
}
public ValidationAttribute Attribute
{
get { return _attribute; }
}
public override ModelClientValidationRule ClientValidationRule
{
get { return _clientValidationRule; }
}
protected override bool IsValid(HttpContextBase httpContext, string value)
{
return _attribute.IsValid(value);
}
}
}

View File

@ -0,0 +1,295 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.WebPages.Html;
using System.Web.WebPages.Scope;
using Microsoft.Internal.Web.Utils;
namespace System.Web.WebPages
{
public sealed class ValidationHelper
{
private static readonly object _invalidCssClassKey = new object();
private static readonly object _validCssClassKey = new object();
private static IDictionary<object, object> _scopeOverride;
private readonly Dictionary<string, List<IValidator>> _validators = new Dictionary<string, List<IValidator>>(StringComparer.OrdinalIgnoreCase);
private readonly HttpContextBase _httpContext;
private readonly ModelStateDictionary _modelStateDictionary;
internal ValidationHelper(HttpContextBase httpContext, ModelStateDictionary modelStateDictionary)
{
Debug.Assert(httpContext != null);
Debug.Assert(modelStateDictionary != null);
_httpContext = httpContext;
_modelStateDictionary = modelStateDictionary;
}
public static string ValidCssClass
{
get
{
object value;
if (!Scope.TryGetValue(_validCssClassKey, out value))
{
return null;
}
return value as string;
}
set { Scope[_validCssClassKey] = value; }
}
public static string InvalidCssClass
{
get
{
object value;
if (!Scope.TryGetValue(_invalidCssClassKey, out value))
{
return HtmlHelper.DefaultValidationInputErrorCssClass;
}
return value as string;
}
set { Scope[_invalidCssClassKey] = value; }
}
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This makes it easier for a user to read this value without knowing of this type.")]
public string FormField
{
get { return ModelStateDictionary.FormFieldKey; }
}
internal static IDictionary<object, object> Scope
{
get { return _scopeOverride ?? ScopeStorage.CurrentScope; }
}
public void RequireField(string field)
{
RequireField(field, errorMessage: null);
}
public void RequireField(string field, string errorMessage)
{
if (String.IsNullOrEmpty(field))
{
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "field");
}
Add(field, Validator.Required(errorMessage: errorMessage));
}
public void RequireFields(params string[] fields)
{
if (fields == null)
{
throw new ArgumentNullException("fields");
}
foreach (var field in fields)
{
RequireField(field);
}
}
public void Add(string field, params IValidator[] validators)
{
if (String.IsNullOrEmpty(field))
{
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "field");
}
if ((validators == null) || validators.Any(v => v == null))
{
throw new ArgumentNullException("validators");
}
AddFieldValidators(field, validators);
}
public void Add(IEnumerable<string> fields, params IValidator[] validators)
{
if (fields == null)
{
throw new ArgumentNullException("fields");
}
if (validators == null)
{
throw new ArgumentNullException("validators");
}
foreach (var field in fields)
{
Add(field, validators);
}
}
public void AddFormError(string errorMessage)
{
_modelStateDictionary.AddFormError(errorMessage);
}
public bool IsValid(params string[] fields)
{
// Don't need to validate fields as we treat empty fields as all in Validate.
return !Validate(fields).Any();
}
public IEnumerable<ValidationResult> Validate(params string[] fields)
{
IEnumerable<string> keys = fields;
if (fields == null || !fields.Any())
{
// If no fields are present, validate all of them.
keys = _validators.Keys.Concat(new[] { FormField });
}
return ValidateFieldsAndUpdateModelState(keys);
}
public IEnumerable<string> GetErrors(params string[] fields)
{
// Don't need to validate fields as we treat empty fields as all in Validate.
return Validate(fields).Select(r => r.ErrorMessage);
}
public HtmlString For(string field)
{
if (String.IsNullOrEmpty(field))
{
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "field");
}
var clientRules = GetClientValidationRules(field);
return GenerateHtmlFromClientValidationRules(clientRules);
}
public HtmlString ClassFor(string field)
{
if (_httpContext != null && String.Equals("POST", _httpContext.Request.HttpMethod, StringComparison.OrdinalIgnoreCase))
{
string cssClass = IsValid(field) ? ValidationHelper.ValidCssClass : ValidationHelper.InvalidCssClass;
return cssClass == null ? null : new HtmlString(cssClass);
}
return null;
}
internal static IDisposable OverrideScope()
{
_scopeOverride = new Dictionary<object, object>();
return new DisposableAction(() => _scopeOverride = null);
}
internal IDictionary<string, object> GetUnobtrusiveValidationAttributes(string field)
{
var clientRules = GetClientValidationRules(field);
var attributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(clientRules, attributes);
return attributes;
}
private IEnumerable<ValidationResult> ValidateFieldsAndUpdateModelState(IEnumerable<string> fields)
{
var validationContext = new ValidationContext(_httpContext, serviceProvider: null, items: null);
var validationResults = new List<ValidationResult>();
foreach (var field in fields)
{
IEnumerable<ValidationResult> fieldResults = ValidateField(field, validationContext);
IEnumerable<string> errors = fieldResults.Select(c => c.ErrorMessage);
ModelState modelState = _modelStateDictionary[field];
if (modelState != null && modelState.Errors.Any())
{
errors = errors.Except(modelState.Errors, StringComparer.OrdinalIgnoreCase);
// If there were other validation errors that were added via ModelState, add them to the collection.
fieldResults = fieldResults.Concat(modelState.Errors.Select(e => new ValidationResult(e, new[] { field })));
}
foreach (var errorMessage in errors)
{
// Only add errors that haven't been encountered before. This is to prevent from the same error message being duplicated
// if a call is made multiple times
_modelStateDictionary.AddError(field, errorMessage);
}
validationResults.AddRange(fieldResults);
}
return validationResults;
}
private void AddFieldValidators(string field, params IValidator[] validators)
{
List<IValidator> fieldValidators = null;
if (!_validators.TryGetValue(field, out fieldValidators))
{
fieldValidators = new List<IValidator>();
_validators[field] = fieldValidators;
}
foreach (var validator in validators)
{
fieldValidators.Add(validator);
}
}
private IEnumerable<ValidationResult> ValidateField(string field, ValidationContext context)
{
List<IValidator> fieldValidators;
if (!_validators.TryGetValue(field, out fieldValidators))
{
return Enumerable.Empty<ValidationResult>();
}
context.MemberName = field;
return fieldValidators.Select(f => f.Validate(context))
.Where(result => result != ValidationResult.Success);
}
private IEnumerable<ModelClientValidationRule> GetClientValidationRules(string field)
{
List<IValidator> fieldValidators = null;
if (!_validators.TryGetValue(field, out fieldValidators))
{
return Enumerable.Empty<ModelClientValidationRule>();
}
return from item in fieldValidators
let clientRule = item.ClientValidationRule
where clientRule != null
select clientRule;
}
internal static HtmlString GenerateHtmlFromClientValidationRules(IEnumerable<ModelClientValidationRule> clientRules)
{
if (!clientRules.Any())
{
return null;
}
var attributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(clientRules, attributes);
var stringBuilder = new StringBuilder();
foreach (var attribute in attributes)
{
string key = attribute.Key;
// Values are already html encoded.
string value = Convert.ToString(attribute.Value, CultureInfo.InvariantCulture);
stringBuilder.Append(key)
.Append("=\"")
.Append(value)
.Append('"')
.Append(' ');
}
// Trim trailing whitespace
if (stringBuilder.Length > 0)
{
stringBuilder.Length--;
}
return new HtmlString(stringBuilder.ToString());
}
}
}

View File

@ -0,0 +1,127 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Web.Mvc;
using System.Web.WebPages.Resources;
using Microsoft.Internal.Web.Utils;
namespace System.Web.WebPages
{
public abstract class Validator
{
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator Required(string errorMessage = null)
{
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_Required);
var clientAttributes = new ModelClientValidationRequiredRule(errorMessage);
// We don't care if the value is unsafe when verifying that it is required.
return new ValidationAttributeAdapter(new RequiredAttribute(), errorMessage, clientAttributes, useUnvalidatedValues: true);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator Range(int minValue, int maxValue, string errorMessage = null)
{
errorMessage = String.Format(CultureInfo.CurrentCulture, DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_IntegerRange), minValue, maxValue);
var clientAttributes = new ModelClientValidationRangeRule(errorMessage, minValue, maxValue);
return new ValidationAttributeAdapter(new RangeAttribute(minValue, maxValue), errorMessage, clientAttributes);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator Range(double minValue, double maxValue, string errorMessage = null)
{
errorMessage = String.Format(CultureInfo.CurrentCulture, DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_FloatRange), minValue, maxValue);
var clientAttributes = new ModelClientValidationRangeRule(errorMessage, minValue, maxValue);
return new ValidationAttributeAdapter(new RangeAttribute(minValue, maxValue), errorMessage, clientAttributes);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator StringLength(int maxLength, int minLength = 0, string errorMessage = null)
{
if (minLength == 0)
{
errorMessage = String.Format(CultureInfo.CurrentCulture, DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_StringLength), maxLength);
}
else
{
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_StringLengthRange);
errorMessage = String.Format(CultureInfo.CurrentCulture, errorMessage, minLength, maxLength);
}
var clientAttributes = new ModelClientValidationStringLengthRule(errorMessage, minLength, maxLength);
// We don't care if the value is unsafe when checking the length of the request field passed to us.
return new ValidationAttributeAdapter(new StringLengthAttribute(maxLength) { MinimumLength = minLength }, errorMessage, clientAttributes,
useUnvalidatedValues: true);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator Regex(string pattern, string errorMessage = null)
{
if (String.IsNullOrEmpty(pattern))
{
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "pattern");
}
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_Regex);
var clientAttributes = new ModelClientValidationRegexRule(errorMessage, pattern);
return new ValidationAttributeAdapter(new RegularExpressionAttribute(pattern), errorMessage, clientAttributes);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator EqualsTo(string otherFieldName, string errorMessage = null)
{
if (String.IsNullOrEmpty(otherFieldName))
{
throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "otherFieldName");
}
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_EqualsTo);
return new CompareValidator(otherFieldName, errorMessage);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator DateTime(string errorMessage = null)
{
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_DataType);
return new DataTypeValidator(DataTypeValidator.SupportedValidationDataType.DateTime, errorMessage);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator Decimal(string errorMessage = null)
{
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_DataType);
return new DataTypeValidator(DataTypeValidator.SupportedValidationDataType.Decimal, errorMessage);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator Integer(string errorMessage = null)
{
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_DataType);
return new DataTypeValidator(DataTypeValidator.SupportedValidationDataType.Integer, errorMessage);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator Url(string errorMessage = null)
{
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_DataType);
return new DataTypeValidator(DataTypeValidator.SupportedValidationDataType.Url, errorMessage);
}
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "We are ok using default parameters for helpers")]
public static IValidator Float(string errorMessage = null)
{
errorMessage = DefaultIfEmpty(errorMessage, WebPageResources.ValidationDefault_DataType);
return new DataTypeValidator(DataTypeValidator.SupportedValidationDataType.Float, errorMessage);
}
private static string DefaultIfEmpty(string errorMessage, string defaultErrorMessage)
{
if (String.IsNullOrEmpty(errorMessage))
{
return defaultErrorMessage;
}
return errorMessage;
}
}
}