예제 #1
0
        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));
        }
예제 #2
0
        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>()));
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
        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);
 }
예제 #12
0
        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));
        }
예제 #14
0
        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);
        }
예제 #16
0
        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);
            }
        }
예제 #17
0
        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;
                    }
                }
            }
        }
예제 #18
0
        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);
                    }
                }
            }
        }