/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Mvc/test/Mvc.IntegrationTests/ServicesModelBinderIntegrationTest.cs
412 строк
14 KB
Bruno Oliveira
Surrogate argument list in Minimal APIs (#41325)
13 май 2022, 02:59
Не верифицирован
13 май 2022, 02:59
65bb1ec
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace Microsoft.AspNetCore.Mvc.IntegrationTests; public class ServicesModelBinderIntegrationTest { [Fact] public async Task BindParameterFromService_WithData_GetsBound() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameter = new ParameterDescriptor() { Name = "Parameter1", BindingInfo = new BindingInfo() { BinderModelName = "CustomParameter", BindingSource = BindingSource.Services }, // Using a service type already in defaults. ParameterType = typeof(ITypeActivatorCache) }; var testContext = ModelBindingTestHelper.GetTestContext(); var modelState = testContext.ModelState; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert // ModelBindingResult Assert.True(modelBindingResult.IsModelSet); // Model var provider = Assert.IsAssignableFrom<ITypeActivatorCache>(modelBindingResult.Model); Assert.NotNull(provider); // ModelState Assert.True(modelState.IsValid); Assert.Empty(modelState.Keys); } [Fact] public async Task BindParameterFromService_NoPrefix_GetsBound() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameter = new ParameterDescriptor { Name = "ControllerProperty", BindingInfo = new BindingInfo { BindingSource = BindingSource.Services, }, // Use a service type already in defaults. ParameterType = typeof(ITypeActivatorCache), }; var testContext = ModelBindingTestHelper.GetTestContext(); var modelState = testContext.ModelState; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert // ModelBindingResult Assert.True(modelBindingResult.IsModelSet); // Model var provider = Assert.IsAssignableFrom<ITypeActivatorCache>(modelBindingResult.Model); Assert.NotNull(provider); // ModelState Assert.True(modelState.IsValid); Assert.Empty(modelState); } [Fact] public async Task BindEnumerableParameterFromService_NoPrefix_GetsBound() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameter = new ParameterDescriptor { Name = "ControllerProperty", BindingInfo = new BindingInfo { BindingSource = BindingSource.Services, }, // Use a service type already in defaults. ParameterType = typeof(IEnumerable<ITypeActivatorCache>), }; var testContext = ModelBindingTestHelper.GetTestContext(); var modelState = testContext.ModelState; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert // ModelBindingResult Assert.True(modelBindingResult.IsModelSet); // Model var formatterArray = Assert.IsType<ITypeActivatorCache[]>(modelBindingResult.Model); Assert.Single(formatterArray); // ModelState Assert.True(modelState.IsValid); Assert.Empty(modelState); } [Fact] public async Task BindEnumerableParameterFromService_NoService_GetsBound() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameter = new ParameterDescriptor { Name = "ControllerProperty", BindingInfo = new BindingInfo { BindingSource = BindingSource.Services, }, // Use a service type not available in DI. ParameterType = typeof(IEnumerable<IActionResult>), }; var testContext = ModelBindingTestHelper.GetTestContext(); var modelState = testContext.ModelState; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert // ModelBindingResult Assert.True(modelBindingResult.IsModelSet); // Model var actionResultArray = Assert.IsType<IActionResult[]>(modelBindingResult.Model); Assert.Empty(actionResultArray); // ModelState Assert.True(modelState.IsValid); Assert.Empty(modelState); } [Fact] public async Task BindParameterFromService_NoService_Throws() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameter = new ParameterDescriptor { Name = "ControllerProperty", BindingInfo = new BindingInfo { BindingSource = BindingSource.Services, }, // Use a service type not available in DI. ParameterType = typeof(IActionResult), }; var testContext = ModelBindingTestHelper.GetTestContext(); // Act & Assert var exception = await Assert.ThrowsAsync<InvalidOperationException>( () => parameterBinder.BindModelAsync(parameter, testContext)); Assert.Contains(typeof(IActionResult).FullName, exception.Message); } private class TestController { #nullable enable public void Action(IActionResult? service, ITypeActivatorCache? service2) { } #nullable restore public void ActionWithDefaultValue(IActionResult service = default, ITypeActivatorCache service2 = default) { } } [Fact] public async Task BindNullableParameterFromService_WithData_GetBounds() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameters = typeof(TestController).GetMethod(nameof(TestController.Action)).GetParameters(); var parameter = new ControllerParameterDescriptor { Name = "ControllerProperty", BindingInfo = new BindingInfo { BindingSource = BindingSource.Services, }, ParameterInfo = parameters[1], // Use a service type already in defaults. ParameterType = typeof(ITypeActivatorCache), }; var testContext = ModelBindingTestHelper.GetTestContext(); var modelState = testContext.ModelState; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Model var provider = Assert.IsAssignableFrom<ITypeActivatorCache>(modelBindingResult.Model); Assert.NotNull(provider); // ModelState Assert.True(modelState.IsValid); Assert.Empty(modelState.Keys); } [Fact] public async Task BindNullableParameterFromService_NoService_BindsToNull() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameters = typeof(TestController).GetMethod(nameof(TestController.Action)).GetParameters(); var parameter = new ControllerParameterDescriptor { Name = "ControllerProperty", BindingInfo = new BindingInfo { BindingSource = BindingSource.Services, }, ParameterInfo = parameters[0], // Use a service type not available in DI. ParameterType = typeof(IActionResult), }; var testContext = ModelBindingTestHelper.GetTestContext(); var modelState = testContext.ModelState; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert // ModelBindingResult Assert.True(modelBindingResult.IsModelSet); // Model Assert.Null(modelBindingResult.Model); // ModelState Assert.True(modelState.IsValid); Assert.Empty(modelState); } [Fact] public async Task BindParameterWithDefaultValueFromService_WithData_GetBounds() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameters = typeof(TestController).GetMethod(nameof(TestController.ActionWithDefaultValue)).GetParameters(); var parameter = new ControllerParameterDescriptor { Name = "ControllerProperty", BindingInfo = new BindingInfo { BindingSource = BindingSource.Services, }, ParameterInfo = parameters[1], // Use a service type already in defaults. ParameterType = typeof(ITypeActivatorCache), }; var testContext = ModelBindingTestHelper.GetTestContext(); var modelState = testContext.ModelState; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Model var provider = Assert.IsAssignableFrom<ITypeActivatorCache>(modelBindingResult.Model); Assert.NotNull(provider); // ModelState Assert.True(modelState.IsValid); Assert.Empty(modelState.Keys); } [Fact] public async Task BindParameterWithDefaultValueFromService_NoService_BindsToDefaultValue() { // Arrange var parameterBinder = ModelBindingTestHelper.GetParameterBinder(); var parameters = typeof(TestController).GetMethod(nameof(TestController.ActionWithDefaultValue)).GetParameters(); var parameter = new ControllerParameterDescriptor { Name = "ControllerProperty", BindingInfo = new BindingInfo { BindingSource = BindingSource.Services, }, ParameterInfo = parameters[0], // Use a service type not available in DI. ParameterType = typeof(IActionResult), }; var testContext = ModelBindingTestHelper.GetTestContext(); var modelState = testContext.ModelState; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert // ModelBindingResult Assert.True(modelBindingResult.IsModelSet); // Model Assert.Null(modelBindingResult.Model); // ModelState Assert.True(modelState.IsValid); Assert.Empty(modelState); } private class Person { [FromServices] public ITypeActivatorCache Service { get; set; } } // [FromServices] cannot be associated with a type. But a [FromServices] or [ModelBinder] subclass or custom // IBindingSourceMetadata implementation might not have the same restriction. Make sure the metadata is honored // when such an attribute is associated with a type somewhere in the type hierarchy of an action parameter. [Theory] [MemberData( nameof(BinderTypeBasedModelBinderIntegrationTest.NullAndEmptyBindingInfo), MemberType = typeof(BinderTypeBasedModelBinderIntegrationTest))] public async Task FromServicesOnPropertyType_WithData_Succeeds(BindingInfo bindingInfo) { // Arrange // Similar to a custom IBindingSourceMetadata implementation or [ModelBinder] subclass on a custom service. var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForProperty<Person>(nameof(Person.Service)); var testContext = ModelBindingTestHelper.GetTestContext(metadataProvider: metadataProvider); var modelState = testContext.ModelState; var parameterBinder = ModelBindingTestHelper.GetParameterBinder(testContext.HttpContext.RequestServices); var parameter = new ParameterDescriptor { Name = "parameter-name", BindingInfo = bindingInfo, ParameterType = typeof(Person), }; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert Assert.True(modelBindingResult.IsModelSet); var person = Assert.IsType<Person>(modelBindingResult.Model); Assert.NotNull(person.Service); Assert.True(modelState.IsValid); Assert.Empty(modelState); } // [FromServices] cannot be associated with a type. But a [FromServices] or [ModelBinder] subclass or custom // IBindingSourceMetadata implementation might not have the same restriction. Make sure the metadata is honored // when such an attribute is associated with an action parameter's type. [Theory] [MemberData( nameof(BinderTypeBasedModelBinderIntegrationTest.NullAndEmptyBindingInfo), MemberType = typeof(BinderTypeBasedModelBinderIntegrationTest))] public async Task FromServicesOnParameterType_WithData_Succeeds(BindingInfo bindingInfo) { // Arrange // Similar to a custom IBindingSourceMetadata implementation or [ModelBinder] subclass on a custom service. var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForType<ITypeActivatorCache>() .BindingDetails(binding => binding.BindingSource = BindingSource.Services); var testContext = ModelBindingTestHelper.GetTestContext(metadataProvider: metadataProvider); var modelState = testContext.ModelState; var parameterBinder = ModelBindingTestHelper.GetParameterBinder(testContext.HttpContext.RequestServices); var parameter = new ParameterDescriptor { Name = "parameter-name", BindingInfo = bindingInfo, ParameterType = typeof(ITypeActivatorCache), }; // Act var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext); // Assert Assert.True(modelBindingResult.IsModelSet); Assert.IsAssignableFrom<ITypeActivatorCache>(modelBindingResult.Model); Assert.True(modelState.IsValid); Assert.Empty(modelState); } }