Allow ValidationAttributes and IValidatableObjects to resolve services from the RequestServices provider by injecting it into the ValidationContext.
This commit is contained in:
parent
a229b20c48
commit
328f4d648b
|
|
@ -82,7 +82,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
var memberName = metadata.PropertyName ?? metadata.ModelType.Name;
|
var memberName = metadata.PropertyName ?? metadata.ModelType.Name;
|
||||||
var container = validationContext.Container;
|
var container = validationContext.Container;
|
||||||
|
|
||||||
var context = new ValidationContext(container ?? validationContext.Model)
|
var context = new ValidationContext(
|
||||||
|
instance: container ?? validationContext.Model,
|
||||||
|
serviceProvider: validationContext.ActionContext?.HttpContext?.RequestServices,
|
||||||
|
items: null)
|
||||||
{
|
{
|
||||||
DisplayName = metadata.GetDisplayName(),
|
DisplayName = metadata.GetDisplayName(),
|
||||||
MemberName = memberName
|
MemberName = memberName
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
throw new InvalidOperationException(message);
|
throw new InvalidOperationException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
var validationContext = new ValidationContext(validatable, serviceProvider: null, items: null);
|
var validationContext = new ValidationContext(
|
||||||
|
instance: validatable,
|
||||||
|
serviceProvider: context.ActionContext?.HttpContext?.RequestServices,
|
||||||
|
items: null);
|
||||||
|
|
||||||
return ConvertResults(validatable.Validate(validationContext));
|
return ConvertResults(validatable.Validate(validationContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ using System.Linq;
|
||||||
#if DNXCORE50
|
#if DNXCORE50
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
#endif
|
#endif
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -431,6 +433,49 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
Assert.Equal("Error3", error.ErrorMessage);
|
Assert.Equal("Error3", error.ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Validate_ComplexType_IValidatableObject_CanUseRequestServices()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var service = new Mock<IExampleService>();
|
||||||
|
service.Setup(x => x.DoSomething()).Verifiable();
|
||||||
|
|
||||||
|
var provider = new ServiceCollection().AddSingleton(service.Object).BuildServiceProvider();
|
||||||
|
|
||||||
|
var httpContext = new Mock<HttpContext>();
|
||||||
|
httpContext.SetupGet(x => x.RequestServices).Returns(provider);
|
||||||
|
|
||||||
|
var actionContext = new ActionContext { HttpContext = httpContext.Object };
|
||||||
|
|
||||||
|
var validatorProvider = CreateValidatorProvider();
|
||||||
|
var modelState = actionContext.ModelState;
|
||||||
|
var validationState = new ValidationStateDictionary();
|
||||||
|
|
||||||
|
var validator = CreateValidator();
|
||||||
|
|
||||||
|
var model = new Mock<IValidatableObject>();
|
||||||
|
model
|
||||||
|
.Setup(x => x.Validate(It.IsAny<ValidationContext>()))
|
||||||
|
.Callback((ValidationContext context) =>
|
||||||
|
{
|
||||||
|
var receivedService = context.GetService<IExampleService>();
|
||||||
|
Assert.Equal(service.Object, receivedService);
|
||||||
|
receivedService.DoSomething();
|
||||||
|
})
|
||||||
|
.Returns(new List<ValidationResult>());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
validator.Validate(
|
||||||
|
actionContext,
|
||||||
|
validatorProvider,
|
||||||
|
validationState,
|
||||||
|
null,
|
||||||
|
model.Object);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
service.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[ReplaceCulture]
|
[ReplaceCulture]
|
||||||
public void Validate_ComplexType_FieldsAreIgnored_Valid()
|
public void Validate_ComplexType_FieldsAreIgnored_Valid()
|
||||||
|
|
@ -1071,5 +1116,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IExampleService
|
||||||
|
{
|
||||||
|
void DoSomething();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.DataAnnotations;
|
using Microsoft.AspNet.Mvc.DataAnnotations;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -152,7 +154,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Validatate_ValidationResultSuccess()
|
public void Validate_ValidationResultSuccess()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var metadata = _metadataProvider.GetMetadataForType(typeof(string));
|
var metadata = _metadataProvider.GetMetadataForType(typeof(string));
|
||||||
|
|
@ -315,6 +317,50 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
Assert.Equal("Longueur est invalide : 4", validationResult.Message);
|
Assert.Equal("Longueur est invalide : 4", validationResult.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Validate_CanUseRequestServices_WithinValidationAttribute()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var service = new Mock<IExampleService>();
|
||||||
|
service.Setup(x => x.DoSomething()).Verifiable();
|
||||||
|
|
||||||
|
var provider = new ServiceCollection().AddSingleton(service.Object).BuildServiceProvider();
|
||||||
|
|
||||||
|
var httpContext = new Mock<HttpContext>();
|
||||||
|
httpContext.SetupGet(x => x.RequestServices).Returns(provider);
|
||||||
|
|
||||||
|
var attribute = new Mock<TestableValidationAttribute> { CallBase = true };
|
||||||
|
attribute
|
||||||
|
.Setup(p => p.IsValidPublic(It.IsAny<object>(), It.IsAny<ValidationContext>()))
|
||||||
|
.Callback((object o, ValidationContext context) =>
|
||||||
|
{
|
||||||
|
var receivedService = context.GetService<IExampleService>();
|
||||||
|
Assert.Equal(service.Object, receivedService);
|
||||||
|
receivedService.DoSomething();
|
||||||
|
});
|
||||||
|
|
||||||
|
var validator = new DataAnnotationsModelValidator(
|
||||||
|
new ValidationAttributeAdapterProvider(),
|
||||||
|
attribute.Object,
|
||||||
|
stringLocalizer: null);
|
||||||
|
|
||||||
|
var validationContext = new ModelValidationContext(
|
||||||
|
actionContext: new ActionContext
|
||||||
|
{
|
||||||
|
HttpContext = httpContext.Object
|
||||||
|
},
|
||||||
|
modelMetadata: _metadataProvider.GetMetadataForType(typeof(object)),
|
||||||
|
metadataProvider: _metadataProvider,
|
||||||
|
container: null,
|
||||||
|
model: new object());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var results = validator.Validate(validationContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
service.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
private const string LocalizationKey = "LocalizeIt";
|
private const string LocalizationKey = "LocalizeIt";
|
||||||
|
|
||||||
public static TheoryData Validate_AttributesIncludeValues
|
public static TheoryData Validate_AttributesIncludeValues
|
||||||
|
|
@ -430,5 +476,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IExampleService
|
||||||
|
{
|
||||||
|
void DoSomething();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue