319 lines
12 KiB
C#
319 lines
12 KiB
C#
// 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.ComponentModel;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
|
using Microsoft.AspNetCore.Mvc.RazorPages.Internal;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|
{
|
|
// Integration tests for binding top level models with [BindProperty]
|
|
public class BindPropertyIntegrationTest
|
|
{
|
|
private class Person
|
|
{
|
|
public string Name { get; set; }
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BindModelAsync_WithBindProperty_BindsModel_WhenRequestIsNotGet()
|
|
{
|
|
// Arrange
|
|
var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
|
|
var parameter = new ParameterDescriptor()
|
|
{
|
|
Name = "parameter",
|
|
ParameterType = typeof(Person),
|
|
BindingInfo = BindingInfo.GetBindingInfo(new[] { new BindPropertyAttribute() }),
|
|
};
|
|
|
|
var testContext = ModelBindingTestHelper.GetTestContext(request =>
|
|
{
|
|
request.Method = "POST";
|
|
request.QueryString = new QueryString("?parameter.Name=Joey");
|
|
});
|
|
|
|
// Act
|
|
var result = await parameterBinder.BindModelAsync(parameter, testContext);
|
|
|
|
// Assert
|
|
Assert.True(result.IsModelSet);
|
|
|
|
Assert.Equal("Joey", Assert.IsType<Person>(result.Model).Name);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BindModelAsync_WithBindProperty_SupportsGet_BindsModel_WhenRequestIsGet()
|
|
{
|
|
// Arrange
|
|
var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
|
|
var parameter = new ParameterDescriptor()
|
|
{
|
|
Name = "parameter",
|
|
ParameterType = typeof(Person),
|
|
BindingInfo = BindingInfo.GetBindingInfo(new[] { new BindPropertyAttribute() { SupportsGet = true } }),
|
|
};
|
|
|
|
var testContext = ModelBindingTestHelper.GetTestContext(request =>
|
|
{
|
|
request.Method = "GET";
|
|
request.QueryString = new QueryString("?parameter.Name=Joey");
|
|
});
|
|
|
|
// Act
|
|
var result = await parameterBinder.BindModelAsync(parameter, testContext);
|
|
|
|
// Assert
|
|
Assert.True(result.IsModelSet);
|
|
|
|
Assert.Equal("Joey", Assert.IsType<Person>(result.Model).Name);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BindModelAsync_WithBindProperty_DoesNotBindModel_WhenRequestIsGet()
|
|
{
|
|
// Arrange
|
|
var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
|
|
var parameter = new ParameterDescriptor()
|
|
{
|
|
Name = "parameter",
|
|
ParameterType = typeof(Person),
|
|
BindingInfo = BindingInfo.GetBindingInfo(new[] { new BindPropertyAttribute() }),
|
|
};
|
|
|
|
var testContext = ModelBindingTestHelper.GetTestContext(request =>
|
|
{
|
|
request.Method = "GET";
|
|
request.QueryString = new QueryString("?parameter.Name=Joey");
|
|
});
|
|
|
|
// Act
|
|
var result = await parameterBinder.BindModelAsync(parameter, testContext);
|
|
|
|
// Assert
|
|
Assert.False(result.IsModelSet);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task BindModelAsync_WithBindProperty_BindNever_DoesNotBindModel()
|
|
{
|
|
// Arrange
|
|
var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
|
|
var parameter = new ParameterDescriptor()
|
|
{
|
|
Name = nameof(TestController.BindNeverProp),
|
|
ParameterType = typeof(string),
|
|
BindingInfo = BindingInfo.GetBindingInfo(new[] { new BindPropertyAttribute() }),
|
|
};
|
|
|
|
var testContext = ModelBindingTestHelper.GetTestContext(request =>
|
|
{
|
|
request.Method = "POST";
|
|
request.QueryString = new QueryString($"?{parameter.Name}=Joey");
|
|
});
|
|
|
|
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
|
var modelMetadata = modelMetadataProvider
|
|
.GetMetadataForProperty(typeof(TestController), parameter.Name);
|
|
|
|
// Act
|
|
var result = await parameterBinder.BindModelAsync(
|
|
parameter,
|
|
testContext,
|
|
modelMetadataProvider,
|
|
modelMetadata);
|
|
|
|
// Assert
|
|
Assert.False(result.IsModelSet);
|
|
Assert.True(testContext.ModelState.IsValid);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null, false)]
|
|
[InlineData(123, true)]
|
|
public async Task BindModelAsync_WithBindProperty_EnforcesBindRequired(int? input, bool isValid)
|
|
{
|
|
// Arrange
|
|
var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
|
|
var parameter = new ParameterDescriptor()
|
|
{
|
|
Name = nameof(TestController.BindRequiredProp),
|
|
ParameterType = typeof(string),
|
|
BindingInfo = BindingInfo.GetBindingInfo(new[] { new BindPropertyAttribute() }),
|
|
};
|
|
|
|
var testContext = ModelBindingTestHelper.GetTestContext(request =>
|
|
{
|
|
request.Method = "POST";
|
|
|
|
if (input.HasValue)
|
|
{
|
|
request.QueryString = new QueryString($"?{parameter.Name}={input.Value}");
|
|
}
|
|
});
|
|
|
|
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
|
var modelMetadata = modelMetadataProvider
|
|
.GetMetadataForProperty(typeof(TestController), parameter.Name);
|
|
|
|
// Act
|
|
var result = await parameterBinder.BindModelAsync(
|
|
parameter,
|
|
testContext,
|
|
modelMetadataProvider,
|
|
modelMetadata);
|
|
|
|
// Assert
|
|
Assert.Equal(input.HasValue, result.IsModelSet);
|
|
Assert.Equal(isValid, testContext.ModelState.IsValid);
|
|
if (isValid)
|
|
{
|
|
Assert.Equal(input.Value, Assert.IsType<int>(result.Model));
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null, false)]
|
|
[InlineData(123, true)]
|
|
public async Task BindModelAsync_WithBindPageProperty_EnforcesBindRequired(int? input, bool isValid)
|
|
{
|
|
// Arrange
|
|
var propertyInfo = typeof(TestPage).GetProperty(nameof(TestPage.BindRequiredProperty));
|
|
var propertyDescriptor = new PageBoundPropertyDescriptor
|
|
{
|
|
BindingInfo = BindingInfo.GetBindingInfo(new[]
|
|
{
|
|
new FromQueryAttribute { Name = propertyInfo.Name },
|
|
}),
|
|
Name = propertyInfo.Name,
|
|
ParameterType = propertyInfo.PropertyType,
|
|
Property = propertyInfo,
|
|
};
|
|
|
|
var typeInfo = typeof(TestPage).GetTypeInfo();
|
|
var actionDescriptor = new CompiledPageActionDescriptor
|
|
{
|
|
BoundProperties = new[] { propertyDescriptor },
|
|
HandlerTypeInfo = typeInfo,
|
|
ModelTypeInfo = typeInfo,
|
|
PageTypeInfo = typeInfo,
|
|
};
|
|
|
|
var testContext = ModelBindingTestHelper.GetTestContext(request =>
|
|
{
|
|
request.Method = "POST";
|
|
if (input.HasValue)
|
|
{
|
|
request.QueryString = new QueryString($"?{propertyDescriptor.Name}={input.Value}");
|
|
}
|
|
});
|
|
|
|
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
|
var parameterBinder = ModelBindingTestHelper.GetParameterBinder(modelMetadataProvider);
|
|
var modelBinderFactory = ModelBindingTestHelper.GetModelBinderFactory(modelMetadataProvider);
|
|
var modelMetadata = modelMetadataProvider
|
|
.GetMetadataForProperty(typeof(TestPage), propertyDescriptor.Name);
|
|
|
|
var pageBinder = PageBinderFactory.CreatePropertyBinder(
|
|
parameterBinder,
|
|
modelMetadataProvider,
|
|
modelBinderFactory,
|
|
actionDescriptor);
|
|
var pageContext = new PageContext
|
|
{
|
|
ActionDescriptor = actionDescriptor,
|
|
HttpContext = testContext.HttpContext,
|
|
RouteData = testContext.RouteData,
|
|
ValueProviderFactories = testContext.ValueProviderFactories,
|
|
};
|
|
|
|
var page = new TestPage();
|
|
|
|
// Act
|
|
await pageBinder(pageContext, page);
|
|
|
|
// Assert
|
|
Assert.Equal(isValid, pageContext.ModelState.IsValid);
|
|
if (isValid)
|
|
{
|
|
Assert.Equal(input.Value, page.BindRequiredProperty);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("RequiredAndStringLengthProp", null, false)]
|
|
[InlineData("RequiredAndStringLengthProp", "", false)]
|
|
[InlineData("RequiredAndStringLengthProp", "abc", true)]
|
|
[InlineData("RequiredAndStringLengthProp", "abcTooLong", false)]
|
|
[InlineData("DisplayNameStringLengthProp", null, true)]
|
|
[InlineData("DisplayNameStringLengthProp", "", true)]
|
|
[InlineData("DisplayNameStringLengthProp", "abc", true)]
|
|
[InlineData("DisplayNameStringLengthProp", "abcTooLong", false, "My Display Name")]
|
|
public async Task BindModelAsync_WithBindProperty_EnforcesDataAnnotationsAttributes(
|
|
string propertyName, string input, bool isValid, string displayName = null)
|
|
{
|
|
// Arrange
|
|
var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
|
|
var parameter = new ParameterDescriptor()
|
|
{
|
|
Name = propertyName,
|
|
ParameterType = typeof(string),
|
|
BindingInfo = BindingInfo.GetBindingInfo(new[] { new BindPropertyAttribute() }),
|
|
};
|
|
|
|
var testContext = ModelBindingTestHelper.GetTestContext(request =>
|
|
{
|
|
request.Method = "POST";
|
|
|
|
if (input != null)
|
|
{
|
|
request.QueryString = new QueryString($"?{parameter.Name}={input}");
|
|
}
|
|
});
|
|
|
|
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
|
var modelMetadata = modelMetadataProvider
|
|
.GetMetadataForProperty(typeof(TestController), parameter.Name);
|
|
|
|
// Act
|
|
var result = await parameterBinder.BindModelAsync(
|
|
parameter,
|
|
testContext,
|
|
modelMetadataProvider,
|
|
modelMetadata);
|
|
|
|
// Assert
|
|
Assert.Equal(input != null, result.IsModelSet);
|
|
Assert.Equal(isValid, testContext.ModelState.IsValid);
|
|
if (!isValid)
|
|
{
|
|
var message = testContext.ModelState[propertyName].Errors.Single().ErrorMessage;
|
|
Assert.Contains(displayName ?? parameter.Name, message);
|
|
}
|
|
}
|
|
|
|
private class TestController
|
|
{
|
|
[BindNever] public string BindNeverProp { get; set; }
|
|
[BindRequired] public int BindRequiredProp { get; set; }
|
|
[Required, StringLength(3)] public string RequiredAndStringLengthProp { get; set; }
|
|
[DisplayName("My Display Name"), StringLength(3)] public string DisplayNameStringLengthProp { get; set; }
|
|
}
|
|
|
|
private class TestPage : PageModel
|
|
{
|
|
[BindRequired]
|
|
public int BindRequiredProperty { get; set; }
|
|
}
|
|
}
|
|
}
|