public void PopulateHandlerMethods_IgnoresAbstractMethods() { // Arrange var provider = CreateProvider(); var typeInfo = typeof(PageModelWithAbstractMethod).GetTypeInfo(); var expected = typeInfo.GetMethod(nameof(PageModelWithAbstractMethod.OnGet), BindingFlags.Public | BindingFlags.Instance); var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]); // Act provider.PopulateHandlerMethods(pageModel); // Assert var handlerMethods = pageModel.HandlerMethods; Assert.Collection( handlerMethods, handler => Assert.Same(expected, handler.MethodInfo)); }
public void CreateDescriptor_AddsGlobalFiltersWithTheRightScope() { // Arrange var actionDescriptor = new PageActionDescriptor { ActionConstraints = new List <IActionConstraintMetadata>(), AttributeRouteInfo = new AttributeRouteInfo(), FilterDescriptors = new List <FilterDescriptor>(), RelativePath = "/Foo", RouteValues = new Dictionary <string, string>(), ViewEnginePath = "/Pages/Foo", }; var handlerTypeInfo = typeof(TestModel).GetTypeInfo(); var pageApplicationModel = new PageApplicationModel(actionDescriptor, handlerTypeInfo, new object[0]) { PageType = typeof(TestPage).GetTypeInfo(), ModelType = typeof(TestModel).GetTypeInfo(), Filters = { Mock.Of <IFilterMetadata>(), }, }; var globalFilters = new FilterCollection { Mock.Of <IFilterMetadata>(), }; // Act var compiledPageActionDescriptor = CompiledPageActionDescriptorBuilder.Build(pageApplicationModel, globalFilters); // Assert Assert.Collection( compiledPageActionDescriptor.FilterDescriptors, filterDescriptor => { Assert.Same(globalFilters[0], filterDescriptor.Filter); Assert.Equal(FilterScope.Global, filterDescriptor.Scope); }, filterDescriptor => { Assert.Same(pageApplicationModel.Filters[0], filterDescriptor.Filter); Assert.Equal(FilterScope.Action, filterDescriptor.Scope); }); }
/// <summary> /// A copy constructor for <see cref="PageApplicationModel"/>. /// </summary> /// <param name="other">The <see cref="PageApplicationModel"/> to copy from.</param> public PageApplicationModel(PageApplicationModel other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } ActionDescriptor = other.ActionDescriptor; HandlerType = other.HandlerType; PageType = other.PageType; ModelType = other.ModelType; Filters = new List <IFilterMetadata>(other.Filters); Properties = new Dictionary <object, object>(other.Properties); HandlerMethods = new List <PageHandlerModel>(other.HandlerMethods.Select(m => new PageHandlerModel(m))); HandlerProperties = new List <PagePropertyModel>(other.HandlerProperties.Select(p => new PagePropertyModel(p))); HandlerTypeAttributes = other.HandlerTypeAttributes; }
public void PopulateHandlerProperties_UsesPropertyHelpers_ToFindProperties() { // Arrange var provider = CreateProvider(); var typeInfo = typeof(HidesAProperty).GetTypeInfo(); var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]); // Act provider.PopulateHandlerProperties(pageModel); // Assert var properties = pageModel.HandlerProperties; Assert.Collection( properties, p => { Assert.Equal(typeof(HidesAProperty).GetTypeInfo(), p.PropertyInfo.DeclaringType.GetTypeInfo()); }); }
// Internal for unit testing internal static HandlerMethodDescriptor[] CreateHandlerMethods(PageApplicationModel applicationModel) { var handlerModels = applicationModel.HandlerMethods; var handlerDescriptors = new HandlerMethodDescriptor[handlerModels.Count]; for (var i = 0; i < handlerDescriptors.Length; i++) { var handlerModel = handlerModels[i]; handlerDescriptors[i] = new HandlerMethodDescriptor { HttpMethod = handlerModel.HttpMethod, Name = handlerModel.HandlerName, MethodInfo = handlerModel.MethodInfo, Parameters = CreateHandlerParameters(handlerModel), }; } return(handlerDescriptors); }
public void CreateBoundProperties_IgnoresPropertiesWithoutBindingInfo() { // Arrange var actionDescriptor = new PageActionDescriptor(); var handlerTypeInfo = typeof(HandlerWithIgnoredProperties).GetTypeInfo(); var propertyModel1 = new PagePropertyModel( handlerTypeInfo.GetProperty(nameof(HandlerWithIgnoredProperties.Property)), new object[0]) { PropertyName = nameof(HandlerWithIgnoredProperties.Property), BindingInfo = new BindingInfo(), }; var propertyModel2 = new PagePropertyModel( handlerTypeInfo.GetProperty(nameof(HandlerWithIgnoredProperties.IgnoreMe)), new object[0]) { PropertyName = nameof(HandlerWithIgnoredProperties.IgnoreMe), }; var pageApplicationModel = new PageApplicationModel(actionDescriptor, handlerTypeInfo, new object[0]) { HandlerProperties = { propertyModel1, propertyModel2, } }; // Act var propertyDescriptors = CompiledPageActionDescriptorBuilder.CreateBoundProperties(pageApplicationModel); // Assert Assert.Collection( propertyDescriptors, p => { Assert.Same(propertyModel1.PropertyName, p.Name); Assert.Same(typeof(int), p.ParameterType); Assert.Same(propertyModel1.PropertyInfo, p.Property); Assert.Same(propertyModel1.BindingInfo, p.BindingInfo); }); }
/// <summary> /// Creates a <see cref="CompiledPageActionDescriptor"/> from the specified <paramref name="applicationModel"/>. /// </summary> /// <param name="applicationModel">The <see cref="PageApplicationModel"/>.</param> /// <param name="globalFilters">Global filters to apply to the page.</param> /// <returns>The <see cref="CompiledPageActionDescriptor"/>.</returns> public static CompiledPageActionDescriptor Build( PageApplicationModel applicationModel, FilterCollection globalFilters) { var boundProperties = CreateBoundProperties(applicationModel); var filters = Enumerable.Concat( globalFilters.Select(f => new FilterDescriptor(f, FilterScope.Global)), applicationModel.Filters.Select(f => new FilterDescriptor(f, FilterScope.Action))) .ToArray(); var handlerMethods = CreateHandlerMethods(applicationModel); if (applicationModel.ModelType != null && applicationModel.DeclaredModelType != null && !applicationModel.DeclaredModelType.IsAssignableFrom(applicationModel.ModelType)) { var message = Resources.FormatInvalidActionDescriptorModelType( applicationModel.ActionDescriptor.DisplayName, applicationModel.ModelType.Name, applicationModel.DeclaredModelType.Name); throw new InvalidOperationException(message); } var actionDescriptor = applicationModel.ActionDescriptor; return(new CompiledPageActionDescriptor(actionDescriptor) { ActionConstraints = actionDescriptor.ActionConstraints, AttributeRouteInfo = actionDescriptor.AttributeRouteInfo, BoundProperties = boundProperties, EndpointMetadata = CreateEndPointMetadata(applicationModel), FilterDescriptors = filters, HandlerMethods = handlerMethods, HandlerTypeInfo = applicationModel.HandlerType, DeclaredModelTypeInfo = applicationModel.DeclaredModelType, ModelTypeInfo = applicationModel.ModelType, RouteValues = actionDescriptor.RouteValues, PageTypeInfo = applicationModel.PageType, Properties = applicationModel.Properties, }); }
public void CreateDescriptor_ThrowsIfModelIsNotCompatibleWithDeclaredModel() { // Arrange var actionDescriptor = new PageActionDescriptor { ActionConstraints = new List <IActionConstraintMetadata>(), AttributeRouteInfo = new AttributeRouteInfo(), FilterDescriptors = new List <FilterDescriptor>(), RelativePath = "/Foo", RouteValues = new Dictionary <string, string>(), ViewEnginePath = "/Pages/Foo", }; var handlerTypeInfo = typeof(TestModel).GetTypeInfo(); var pageApplicationModel = new PageApplicationModel(actionDescriptor, typeof(TestModel).GetTypeInfo(), handlerTypeInfo, new object[0]) { PageType = typeof(TestPage).GetTypeInfo(), ModelType = typeof(string).GetTypeInfo(), Filters = { Mock.Of <IFilterMetadata>(), Mock.Of <IFilterMetadata>(), }, HandlerMethods = { new PageHandlerModel(handlerTypeInfo.GetMethod(nameof(TestModel.OnGet)), new object[0]), }, HandlerProperties = { new PagePropertyModel(handlerTypeInfo.GetProperty(nameof(TestModel.Property)), new object[0]) { BindingInfo = new BindingInfo(), }, } }; var globalFilters = new FilterCollection(); // Act & Assert var actual = Assert.Throws <InvalidOperationException>(() => CompiledPageActionDescriptorBuilder.Build(pageApplicationModel, globalFilters)); }
public void CreateHandlerModel_ParsesMethod() { // Arrange var provider = CreateProvider(); var typeInfo = typeof(PageModelWithHandlerNames).GetTypeInfo(); var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]); // Act provider.PopulateHandlerMethods(pageModel); // Assert var handlerMethods = pageModel.HandlerMethods; Assert.Collection( handlerMethods.OrderBy(h => h.MethodInfo.Name), handler => { Assert.Same(typeInfo.GetMethod(nameof(PageModelWithHandlerNames.OnPutDeleteAsync)), handler.MethodInfo); Assert.Equal("Put", handler.HttpMethod); Assert.Equal("Delete", handler.HandlerName); }); }
public void CreateHandlerMethods_WithLegacyValidationBehavior_AddsParameterDescriptors() { // Arrange var provider = new DefaultPageApplicationModelProvider( TestModelMetadataProvider.CreateDefaultProvider(), Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = false }), Options.Create(new RazorPagesOptions())); var typeInfo = typeof(PageWithHandlerParameters).GetTypeInfo(); var expected = typeInfo.GetMethod(nameof(PageWithHandlerParameters.OnPost)); var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]); // Act provider.PopulateHandlerMethods(pageModel); // Assert var handlerMethods = pageModel.HandlerMethods; var handler = Assert.Single(handlerMethods); Assert.Collection( handler.Parameters, p => { Assert.NotNull(p.ParameterInfo); Assert.Equal(typeof(string), p.ParameterInfo.ParameterType); Assert.Equal("name", p.ParameterName); }, p => { Assert.NotNull(p.ParameterInfo); Assert.Equal(typeof(int), p.ParameterInfo.ParameterType); Assert.Equal("id", p.ParameterName); Assert.Equal("personId", p.BindingInfo.BinderModelName); }); }
internal void PopulateFilters(PageApplicationModel pageModel) { for (var i = 0; i < pageModel.HandlerTypeAttributes.Count; i++) { if (pageModel.HandlerTypeAttributes[i] is IFilterMetadata filter) { pageModel.Filters.Add(filter); } } if (typeof(IAsyncPageFilter).IsAssignableFrom(pageModel.HandlerType) || typeof(IPageFilter).IsAssignableFrom(pageModel.HandlerType)) { pageModel.Filters.Add(_pageHandlerPageFilter); } if (typeof(IAsyncResultFilter).IsAssignableFrom(pageModel.HandlerType) || typeof(IResultFilter).IsAssignableFrom(pageModel.HandlerType)) { pageModel.Filters.Add(_pageHandlerResultFilter); } pageModel.Filters.Add(_handleOptionsRequestsFilter); }
/// <summary> /// Creates a <see cref="PageApplicationModel"/> for the given <paramref name="pageTypeInfo"/>. /// </summary> /// <param name="actionDescriptor">The <see cref="PageActionDescriptor"/>.</param> /// <param name="pageTypeInfo">The <see cref="TypeInfo"/>.</param> /// <returns>A <see cref="PageApplicationModel"/> for the given <see cref="TypeInfo"/>.</returns> protected virtual PageApplicationModel CreateModel( PageActionDescriptor actionDescriptor, TypeInfo pageTypeInfo) { if (actionDescriptor == null) { throw new ArgumentNullException(nameof(actionDescriptor)); } if (pageTypeInfo == null) { throw new ArgumentNullException(nameof(pageTypeInfo)); } if (!typeof(PageBase).GetTypeInfo().IsAssignableFrom(pageTypeInfo)) { throw new InvalidOperationException(Resources.FormatInvalidPageType_WrongBase( pageTypeInfo.FullName, typeof(PageBase).FullName)); } // Pages always have a model type. If it's not set explicitly by the developer using // @model, it will be the same as the page type. var modelProperty = pageTypeInfo.GetProperty(ModelPropertyName, BindingFlags.Public | BindingFlags.Instance); if (modelProperty == null) { throw new InvalidOperationException(Resources.FormatInvalidPageType_NoModelProperty( pageTypeInfo.FullName, ModelPropertyName)); } var modelTypeInfo = modelProperty.PropertyType.GetTypeInfo(); var declaredModelType = modelTypeInfo; // Now we want figure out which type is the handler type. TypeInfo handlerType; if (modelProperty.PropertyType.IsDefined(typeof(PageModelAttribute), inherit: true)) { handlerType = modelTypeInfo; } else { handlerType = pageTypeInfo; } var handlerTypeAttributes = handlerType.GetCustomAttributes(inherit: true); var pageModel = new PageApplicationModel( actionDescriptor, declaredModelType, handlerType, handlerTypeAttributes) { PageType = pageTypeInfo, ModelType = modelTypeInfo, }; PopulateHandlerMethods(pageModel); PopulateHandlerProperties(pageModel); PopulateFilters(pageModel); return(pageModel); }
/// <summary> /// Creates a <see cref="PageApplicationModel"/> for the given <paramref name="pageTypeInfo"/>. /// </summary> /// <param name="actionDescriptor">The <see cref="PageActionDescriptor"/>.</param> /// <param name="pageTypeInfo">The <see cref="TypeInfo"/>.</param> /// <returns>A <see cref="PageApplicationModel"/> for the given <see cref="TypeInfo"/>.</returns> protected virtual PageApplicationModel CreateModel( PageActionDescriptor actionDescriptor, TypeInfo pageTypeInfo) { if (actionDescriptor == null) { throw new ArgumentNullException(nameof(actionDescriptor)); } if (pageTypeInfo == null) { throw new ArgumentNullException(nameof(pageTypeInfo)); } if (!typeof(PageBase).GetTypeInfo().IsAssignableFrom(pageTypeInfo)) { throw new InvalidOperationException(Resources.FormatInvalidPageType_WrongBase( pageTypeInfo.FullName, typeof(PageBase).FullName)); } // Pages always have a model type. If it's not set explicitly by the developer using // @model, it will be the same as the page type. var modelProperty = pageTypeInfo.GetProperty(ModelPropertyName, BindingFlags.Public | BindingFlags.Instance); if (modelProperty == null) { throw new InvalidOperationException(Resources.FormatInvalidPageType_NoModelProperty( pageTypeInfo.FullName, ModelPropertyName)); } var modelTypeInfo = modelProperty.PropertyType.GetTypeInfo(); var declaredModelType = modelTypeInfo; // Now we want figure out which type is the handler type. TypeInfo handlerType; var pageTypeAttributes = pageTypeInfo.GetCustomAttributes(inherit: true); object[] handlerTypeAttributes; if (modelProperty.PropertyType.IsDefined(typeof(PageModelAttribute), inherit: true)) { handlerType = modelTypeInfo; // If a PageModel is specified, combine the attributes specified on the Page and the Model type. // Attributes that appear earlier in the are more significant. In this case, we'll treat attributes on the model (code) // to be more signficant than the page (code-generated). handlerTypeAttributes = modelTypeInfo.GetCustomAttributes(inherit: true).Concat(pageTypeAttributes).ToArray(); } else { handlerType = pageTypeInfo; handlerTypeAttributes = pageTypeInfo.GetCustomAttributes(inherit: true); } var pageModel = new PageApplicationModel( actionDescriptor, declaredModelType, handlerType, handlerTypeAttributes) { PageType = pageTypeInfo, ModelType = modelTypeInfo, }; PopulateHandlerMethods(pageModel); PopulateHandlerProperties(pageModel); PopulateFilters(pageModel); return(pageModel); }