private PageActionInvokerCacheEntry CreateCacheEntry( CompiledPageActionDescriptor compiledActionDescriptor, FilterItem[] cachedFilters) { var viewDataFactory = ViewDataDictionaryFactory.CreateFactory(compiledActionDescriptor.DeclaredModelTypeInfo); var pageFactory = _pageFactoryProvider.CreatePageFactory(compiledActionDescriptor); var pageDisposer = _pageFactoryProvider.CreatePageDisposer(compiledActionDescriptor); var propertyBinder = PageBinderFactory.CreatePropertyBinder( _parameterBinder, _modelMetadataProvider, _modelBinderFactory, compiledActionDescriptor); Func <PageContext, object> modelFactory = null; Action <PageContext, object> modelReleaser = null; if (compiledActionDescriptor.ModelTypeInfo != compiledActionDescriptor.PageTypeInfo) { modelFactory = _modelFactoryProvider.CreateModelFactory(compiledActionDescriptor); modelReleaser = _modelFactoryProvider.CreateModelDisposer(compiledActionDescriptor); } var viewStartFactories = GetViewStartFactories(compiledActionDescriptor); var handlerExecutors = GetHandlerExecutors(compiledActionDescriptor); var handlerBinders = GetHandlerBinders(compiledActionDescriptor); return(new PageActionInvokerCacheEntry( compiledActionDescriptor, viewDataFactory, pageFactory, pageDisposer, modelFactory, modelReleaser, propertyBinder, handlerExecutors, handlerBinders, viewStartFactories, cachedFilters)); }
public void CreateActivator_ReturnsFactoryForPage(Type type) { // Arrange var pageContext = new PageContext(); var viewContext = new ViewContext(); var descriptor = new CompiledPageActionDescriptor { PageTypeInfo = type.GetTypeInfo(), }; var activator = new DefaultPageActivatorProvider(); // Act var factory = activator.CreateActivator(descriptor); var instance = factory(pageContext, viewContext); // Assert Assert.NotNull(instance); Assert.IsType(type, instance); }
public void CreateReleaser_CreatesDelegateThatDisposesDisposableTypes() { // Arrange var context = new PageContext(); var activator = new DefaultPageModelActivatorProvider(); var actionDescriptor = new CompiledPageActionDescriptor { ModelTypeInfo = typeof(DisposableModel).GetTypeInfo(), }; var model = new DisposableModel(); // Act & Assert var releaser = activator.CreateReleaser(actionDescriptor); releaser(context, model); // Assert Assert.True(model.Disposed); }
/// <inheritdoc /> public virtual Func <PageContext, object> CreateActivator(CompiledPageActionDescriptor actionDescriptor) { if (actionDescriptor == null) { throw new ArgumentNullException(nameof(actionDescriptor)); } var modelTypeInfo = actionDescriptor.ModelTypeInfo?.AsType(); if (modelTypeInfo == null) { throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull( nameof(actionDescriptor.ModelTypeInfo), nameof(actionDescriptor)), nameof(actionDescriptor)); } var factory = ActivatorUtilities.CreateFactory(modelTypeInfo, Type.EmptyTypes); return((context) => factory(context.HttpContext.RequestServices, Array.Empty <object>())); }
public void CreateModelDisposer_ReturnsDisposerFromModelActivatorProvider() { // Arrange var descriptor = new CompiledPageActionDescriptor { ModelTypeInfo = typeof(SimpleModel).GetTypeInfo() }; var pageContext = new PageContext(); var modelActivatorProvider = new Mock <IPageModelActivatorProvider>(); Action <PageContext, object> disposer = (_, __) => { }; modelActivatorProvider.Setup(p => p.CreateReleaser(descriptor)) .Returns(disposer); var factoryProvider = CreateModelFactoryProvider(modelActivatorProvider.Object); // Act var actual = factoryProvider.CreateModelDisposer(descriptor); // Assert Assert.Same(disposer, actual); }
private PageHandlerBinderDelegate[] GetHandlerBinders(CompiledPageActionDescriptor actionDescriptor) { if (actionDescriptor.HandlerMethods == null || actionDescriptor.HandlerMethods.Count == 0) { return(Array.Empty <PageHandlerBinderDelegate>()); } var results = new PageHandlerBinderDelegate[actionDescriptor.HandlerMethods.Count]; for (var i = 0; i < actionDescriptor.HandlerMethods.Count; i++) { results[i] = PageBinderFactory.CreateHandlerBinder( _parameterBinder, _modelMetadataProvider, _modelBinderFactory, actionDescriptor, actionDescriptor.HandlerMethods[i], _mvcOptions); } return(results); }
public async Task LoadAsync_CompiledPageActionDescriptor_ReturnsSelf() { // Arrange var mvcOptions = Options.Create(new MvcOptions()); var endpointFactory = new ActionEndpointFactory(Mock.Of <RoutePatternTransformer>(), Enumerable.Empty <IRequestDelegateFactory>()); var loader = new DefaultPageLoader( new[] { Mock.Of <IPageApplicationModelProvider>() }, Mock.Of <IViewCompilerProvider>(), endpointFactory, RazorPagesOptions, mvcOptions); var pageDescriptor = new CompiledPageActionDescriptor(); // Act var result1 = await loader.LoadAsync(pageDescriptor, new EndpointMetadataCollection()); var result2 = await loader.LoadAsync(pageDescriptor, new EndpointMetadataCollection()); // Assert Assert.Same(pageDescriptor, result1); Assert.Same(pageDescriptor, result2); }
/// <inheritdoc/> public Func <PageContext, object> CreateActivator(CompiledPageActionDescriptor descriptor) { if (descriptor == null) { throw new ArgumentNullException(nameof(descriptor)); } var modelType = descriptor.ModelTypeInfo?.AsType(); if (modelType == null) { throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull( nameof(descriptor.ModelTypeInfo), nameof(descriptor)), nameof(descriptor)); } return(context => { return context.HttpContext.RequestServices.GetRequiredService(modelType); }); }
public void PageFactorySetsPageContext() { // Arrange var descriptor = new CompiledPageActionDescriptor { PageTypeInfo = typeof(TestPage).GetTypeInfo(), }; var pageContext = new PageContext { ActionDescriptor = descriptor }; var viewContext = new ViewContext(); var factoryProvider = CreatePageFactory(); // Act var factory = factoryProvider.CreatePageFactory(descriptor); var instance = factory(pageContext, viewContext); // Assert var testPage = Assert.IsType <TestPage>(instance); Assert.Same(pageContext, testPage.PageContext); }
public void GetModelBinderFactory_ReturnsNullIfPageHasNoVisibleBoundProperties() { // Arrange var actionDescriptor = new CompiledPageActionDescriptor { PageTypeInfo = typeof(PageWithNoVisibleBoundProperties).GetTypeInfo(), }; var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var modelBinderFactory = TestModelBinderFactory.CreateDefault(); var binder = new ParameterBinder( modelMetadataProvider, modelBinderFactory, Mock.Of <IObjectModelValidator>(), _optionsAccessor, NullLoggerFactory.Instance); // Act var factory = PageBinderFactory.CreatePropertyBinder(binder, modelMetadataProvider, modelBinderFactory, actionDescriptor); // Assert Assert.Same(PageBinderFactory.NullPropertyBinder, factory); }
/// <inheritdoc/> public Action <PageContext, object>?CreateReleaser(CompiledPageActionDescriptor descriptor) { return(null); }
public void GetViewStartFactories_FindsFullHierarchy() { // Arrange var descriptor = new PageActionDescriptor() { RelativePath = "/Pages/Level1/Level2/Index.cshtml", FilterDescriptors = new FilterDescriptor[0], ViewEnginePath = "/Pages/Level1/Level2/Index.cshtml" }; var compiledPageDescriptor = new CompiledPageActionDescriptor(descriptor) { PageTypeInfo = typeof(object).GetTypeInfo(), }; var loader = new Mock <IPageLoader>(); loader .Setup(l => l.Load(It.IsAny <PageActionDescriptor>())) .Returns(compiledPageDescriptor); var fileProvider = new TestFileProvider(); fileProvider.AddFile("/_ViewStart.cshtml", "page content"); fileProvider.AddFile("/Pages/_ViewStart.cshtml", "page content"); fileProvider.AddFile("/Pages/Level1/_ViewStart.cshtml", "page content"); fileProvider.AddFile("/Pages/Level1/Level2/_ViewStart.cshtml", "page content"); fileProvider.AddFile("/Pages/Level1/Level3/_ViewStart.cshtml", "page content"); var fileSystem = new TestRazorProjectFileSystem(fileProvider, _hostingEnvironment); var mock = new Mock <IRazorPageFactoryProvider>(MockBehavior.Strict); mock .Setup(p => p.CreateFactory("/Pages/Level1/Level2/_ViewStart.cshtml")) .Returns(new RazorPageFactoryResult(new CompiledViewDescriptor(), () => null)) .Verifiable(); mock .Setup(p => p.CreateFactory("/Pages/Level1/_ViewStart.cshtml")) .Returns(new RazorPageFactoryResult(new CompiledViewDescriptor(), () => null)) .Verifiable(); mock .Setup(p => p.CreateFactory("/Pages/_ViewStart.cshtml")) .Returns(new RazorPageFactoryResult(new CompiledViewDescriptor(), () => null)) .Verifiable(); mock .Setup(p => p.CreateFactory("/_ViewStart.cshtml")) .Returns(new RazorPageFactoryResult(new CompiledViewDescriptor(), () => null)) .Verifiable(); var razorPageFactoryProvider = mock.Object; var invokerProvider = CreateInvokerProvider( loader.Object, CreateActionDescriptorCollection(descriptor), razorPageFactoryProvider: razorPageFactoryProvider, fileSystem: fileSystem); // Act var factories = invokerProvider.GetViewStartFactories(compiledPageDescriptor); // Assert mock.Verify(); }
public Func <PageContext, ViewContext, object, ValueTask> CreateAsyncPageDisposer(CompiledPageActionDescriptor descriptor) { if (descriptor == null) { throw new ArgumentNullException(nameof(descriptor)); } return(_pageActivator.CreateAsyncReleaser(descriptor)); }
public void OnProvidersExecuting(ActionInvokerProviderContext context) { var actionDescriptor = context.ActionContext.ActionDescriptor as PageActionDescriptor; if (actionDescriptor != null) { var itemCount = actionDescriptor.FilterDescriptors?.Count ?? 0; var filterItems = new List <FilterItem>(itemCount); for (var i = 0; i < itemCount; i++) { var item = new FilterItem(actionDescriptor.FilterDescriptors[i]); filterItems.Add(item); } var filterProviderContext = new FilterProviderContext(context.ActionContext, filterItems); for (var i = 0; i < _filterProviders.Length; i++) { _filterProviders[i].OnProvidersExecuting(filterProviderContext); } for (var i = _filterProviders.Length - 1; i >= 0; i--) { _filterProviders[i].OnProvidersExecuted(filterProviderContext); } var filters = new IFilterMetadata[filterProviderContext.Results.Count]; for (var i = 0; i < filterProviderContext.Results.Count; i++) { filters[i] = filterProviderContext.Results[i].Filter; } var compiledType = _loader.Load(actionDescriptor); var compiledActionDescriptor = new CompiledPageActionDescriptor(actionDescriptor) { PageType = compiledType.GetTypeInfo(), HandlerMethods = new List <HandlerMethodDescriptor>(), }; foreach (var method in compiledType.GetTypeInfo().GetMethods()) { if (method.Name.StartsWith("OnGet") || method.Name.StartsWith("OnPost")) { compiledActionDescriptor.HandlerMethods.Add(new HandlerMethodDescriptor() { Method = method, }); } } context.Result = new PageActionInvoker( _diagnosticSource, _logger, _factory, _selector, _metadataProvider, _tempDataFactory, _viewOptions, filters, _valueProviderFactories, context.ActionContext, compiledActionDescriptor, _pagePersistedPropertyProvider); } }
public Func <PageContext, ViewContext, object, ValueTask>?CreateAsyncReleaser(CompiledPageActionDescriptor actionDescriptor) { if (actionDescriptor == null) { throw new ArgumentNullException(nameof(actionDescriptor)); } if (typeof(IAsyncDisposable).GetTypeInfo().IsAssignableFrom(actionDescriptor.PageTypeInfo)) { return(_asyncDisposer); } if (typeof(IDisposable).GetTypeInfo().IsAssignableFrom(actionDescriptor.PageTypeInfo)) { return(_syncAsyncDisposer); } return(null); }
public void OnProvidersExecuting(ActionInvokerProviderContext context) { var actionDescriptor = context.ActionContext.ActionDescriptor as PageActionDescriptor; if (actionDescriptor != null) { var itemCount = actionDescriptor.FilterDescriptors?.Count ?? 0; var filterItems = new List <FilterItem>(itemCount); for (var i = 0; i < itemCount; i++) { var item = new FilterItem(actionDescriptor.FilterDescriptors[i]); filterItems.Add(item); } var filterProviderContext = new FilterProviderContext(context.ActionContext, filterItems); for (var i = 0; i < _filterProviders.Length; i++) { _filterProviders[i].OnProvidersExecuting(filterProviderContext); } for (var i = _filterProviders.Length - 1; i >= 0; i--) { _filterProviders[i].OnProvidersExecuted(filterProviderContext); } var filters = new IFilterMetadata[filterProviderContext.Results.Count]; for (var i = 0; i < filterProviderContext.Results.Count; i++) { filters[i] = filterProviderContext.Results[i].Filter; } var compiledType = _loader.Load(actionDescriptor).GetTypeInfo(); var modelType = compiledType.GetProperty("Model")?.PropertyType.GetTypeInfo(); var compiledActionDescriptor = new CompiledPageActionDescriptor(actionDescriptor) { ModelType = modelType, PageType = compiledType, HandlerMethods = new List <HandlerMethodDescriptor>(), }; if (modelType != null && modelType != compiledType) { // If the model and page type are different discover handler methods on the model as well. PopulateHandlerMethodDescriptors(modelType, compiledActionDescriptor); } PopulateHandlerMethodDescriptors(compiledType, compiledActionDescriptor); context.Result = new PageActionInvoker( _diagnosticSource, _logger, _factory, _modelFactory, _selector, _metadataProvider, _tempDataFactory, _viewOptions, filters, _valueProviderFactories, context.ActionContext, compiledActionDescriptor, _pagePersistedPropertyProvider); } }
public static PageHandlerBinderDelegate CreateHandlerBinder( ParameterBinder parameterBinder, IModelMetadataProvider modelMetadataProvider, IModelBinderFactory modelBinderFactory, CompiledPageActionDescriptor actionDescriptor, HandlerMethodDescriptor handler, MvcOptions mvcOptions) { if (handler.Parameters == null || handler.Parameters.Count == 0) { return(NullHandlerBinder); } var handlerType = actionDescriptor.HandlerTypeInfo.AsType(); var parameterBindingInfo = new BinderItem[handler.Parameters.Count]; for (var i = 0; i < parameterBindingInfo.Length; i++) { var parameter = handler.Parameters[i]; ModelMetadata metadata; if (modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase) { // The default model metadata provider derives from ModelMetadataProvider // and can therefore supply information about attributes applied to parameters. metadata = modelMetadataProviderBase.GetMetadataForParameter(parameter.ParameterInfo); } else { // For backward compatibility, if there's a custom model metadata provider that // only implements the older IModelMetadataProvider interface, access the more // limited metadata information it supplies. In this scenario, validation attributes // are not supported on parameters. metadata = modelMetadataProvider.GetMetadataForType(parameter.ParameterType); } var binder = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext { BindingInfo = parameter.BindingInfo, Metadata = metadata, CacheToken = parameter, }); parameterBindingInfo[i] = new BinderItem(binder, metadata); } return(Bind); async Task Bind(PageContext pageContext, IDictionary <string, object?> arguments) { var(success, valueProvider) = await CompositeValueProvider.TryCreateAsync(pageContext, pageContext.ValueProviderFactories); if (!success) { return; } for (var i = 0; i < parameterBindingInfo.Length; i++) { var parameter = handler.Parameters[i]; var bindingInfo = parameterBindingInfo[i]; var modelMetadata = bindingInfo.ModelMetadata; if (!modelMetadata.IsBindingAllowed) { continue; } var result = await parameterBinder.BindModelAsync( pageContext, bindingInfo.ModelBinder, valueProvider !, parameter, modelMetadata, value : null, container : null); // Parameters do not have containers. if (result.IsModelSet) { arguments[parameter.Name] = result.Model; } } } }
public static Func <PageContext, object, Task> CreatePropertyBinder( ParameterBinder parameterBinder, IModelMetadataProvider modelMetadataProvider, IModelBinderFactory modelBinderFactory, CompiledPageActionDescriptor actionDescriptor) { if (parameterBinder == null) { throw new ArgumentNullException(nameof(parameterBinder)); } if (actionDescriptor == null) { throw new ArgumentNullException(nameof(actionDescriptor)); } var properties = actionDescriptor.BoundProperties; if (properties == null || properties.Count == 0) { return(NullPropertyBinder); } var handlerType = actionDescriptor.HandlerTypeInfo.AsType(); var propertyBindingInfo = new BinderItem[properties.Count]; for (var i = 0; i < properties.Count; i++) { var property = properties[i]; var metadata = modelMetadataProvider.GetMetadataForProperty(handlerType, property.Name); var binder = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext { BindingInfo = property.BindingInfo, Metadata = metadata, CacheToken = property, }); propertyBindingInfo[i] = new BinderItem(binder, metadata); } return(Bind); async Task Bind(PageContext pageContext, object instance) { var(success, valueProvider) = await CompositeValueProvider.TryCreateAsync(pageContext, pageContext.ValueProviderFactories); if (!success) { return; } for (var i = 0; i < properties.Count; i++) { var property = properties[i]; var bindingInfo = propertyBindingInfo[i]; var modelMetadata = bindingInfo.ModelMetadata; if (!modelMetadata.IsBindingAllowed) { continue; } var result = await parameterBinder.BindModelAsync( pageContext, bindingInfo.ModelBinder, valueProvider !, property, modelMetadata, value : null, container : instance); if (result.IsModelSet) { PropertyValueSetter.SetValue(bindingInfo.ModelMetadata, instance, result.Model); } } } }