Add tests for PageActionInvokerProvider (#5882)
This commit is contained in:
parent
7f3f6957be
commit
1c74e31715
|
|
@ -4,6 +4,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
{
|
||||
public interface IPageLoader
|
||||
{
|
||||
Type Load(PageActionDescriptor actionDescriptor);
|
||||
CompiledPageActionDescriptor Load(PageActionDescriptor actionDescriptor);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
|
|
@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
{
|
||||
public class DefaultPageLoader : IPageLoader
|
||||
{
|
||||
private const string ModelPropertyName = "Model";
|
||||
private readonly RazorCompilationService _razorCompilationService;
|
||||
private readonly ICompilationService _compilationService;
|
||||
private readonly RazorProject _project;
|
||||
|
|
@ -33,22 +34,20 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public Type Load(PageActionDescriptor actionDescriptor)
|
||||
public CompiledPageActionDescriptor Load(PageActionDescriptor actionDescriptor)
|
||||
{
|
||||
var item = _project.GetItem(actionDescriptor.RelativePath);
|
||||
if (!item.Exists)
|
||||
{
|
||||
throw new InvalidOperationException($"File {actionDescriptor.RelativePath} was not found.");
|
||||
}
|
||||
|
||||
RazorCodeDocument codeDocument;
|
||||
RazorCSharpDocument cSharpDocument;
|
||||
|
||||
_logger.RazorFileToCodeCompilationStart(item.Path);
|
||||
|
||||
var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;
|
||||
|
||||
codeDocument = CreateCodeDocument(item);
|
||||
cSharpDocument = _razorCompilationService.ProcessCodeDocument(codeDocument);
|
||||
var codeDocument = CreateCodeDocument(item);
|
||||
var cSharpDocument = _razorCompilationService.ProcessCodeDocument(codeDocument);
|
||||
|
||||
_logger.RazorFileToCodeCompilationEnd(item.Path, startTimestamp);
|
||||
|
||||
|
|
@ -63,7 +62,21 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
}
|
||||
|
||||
compilationResult.EnsureSuccessful();
|
||||
return compilationResult.CompiledType;
|
||||
|
||||
// If a model type wasn't set in code then the model property's type will be the same
|
||||
// as the compiled type.
|
||||
var pageType = compilationResult.CompiledType.GetTypeInfo();
|
||||
var modelType = pageType.GetProperty(ModelPropertyName)?.PropertyType.GetTypeInfo();
|
||||
if (modelType == pageType)
|
||||
{
|
||||
modelType = null;
|
||||
}
|
||||
|
||||
return new CompiledPageActionDescriptor(actionDescriptor)
|
||||
{
|
||||
ModelTypeInfo = modelType,
|
||||
PageTypeInfo = pageType,
|
||||
};
|
||||
}
|
||||
|
||||
private RazorCodeDocument CreateCodeDocument(RazorProjectItem item)
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
{
|
||||
public class PageActionInvokerProvider : IActionInvokerProvider
|
||||
{
|
||||
private static readonly string[] _handlerMethodNames = new string[] { "OnGet", "OnPost" };
|
||||
private const string PageStartFileName = "_PageStart.cshtml";
|
||||
private const string ModelPropertyName = "Model";
|
||||
private readonly IPageLoader _loader;
|
||||
private readonly IPageFactoryProvider _pageFactoryProvider;
|
||||
private readonly IPageModelFactoryProvider _modelFactoryProvider;
|
||||
|
|
@ -166,34 +166,20 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
FilterItem[] cachedFilters)
|
||||
{
|
||||
var actionDescriptor = (PageActionDescriptor)context.ActionContext.ActionDescriptor;
|
||||
var compiledType = _loader.Load(actionDescriptor).GetTypeInfo();
|
||||
|
||||
// If a model type wasn't set in code then the model property's type will be the same
|
||||
// as the compiled type.
|
||||
var modelType = compiledType.GetProperty(ModelPropertyName)?.PropertyType.GetTypeInfo();
|
||||
if (modelType == compiledType)
|
||||
{
|
||||
modelType = null;
|
||||
}
|
||||
|
||||
var compiledActionDescriptor = new CompiledPageActionDescriptor(actionDescriptor)
|
||||
{
|
||||
ModelTypeInfo = modelType,
|
||||
PageTypeInfo = compiledType,
|
||||
};
|
||||
var compiledActionDescriptor = _loader.Load(actionDescriptor);
|
||||
|
||||
var pageFactory = _pageFactoryProvider.CreatePageFactory(compiledActionDescriptor);
|
||||
var pageDisposer = _pageFactoryProvider.CreatePageDisposer(compiledActionDescriptor);
|
||||
|
||||
Func<PageContext, object> modelFactory = null;
|
||||
Action<PageContext, object> modelReleaser = null;
|
||||
if (modelType == null)
|
||||
if (compiledActionDescriptor.ModelTypeInfo == null)
|
||||
{
|
||||
PopulateHandlerMethodDescriptors(compiledType, compiledActionDescriptor);
|
||||
PopulateHandlerMethodDescriptors(compiledActionDescriptor.PageTypeInfo, compiledActionDescriptor);
|
||||
}
|
||||
else
|
||||
{
|
||||
PopulateHandlerMethodDescriptors(modelType, compiledActionDescriptor);
|
||||
PopulateHandlerMethodDescriptors(compiledActionDescriptor.ModelTypeInfo, compiledActionDescriptor);
|
||||
|
||||
modelFactory = _modelFactoryProvider.CreateModelFactory(compiledActionDescriptor);
|
||||
modelReleaser = _modelFactoryProvider.CreateModelDisposer(compiledActionDescriptor);
|
||||
|
|
@ -211,30 +197,34 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
cachedFilters);
|
||||
}
|
||||
|
||||
private List<Func<IRazorPage>> GetPageStartFactories(CompiledPageActionDescriptor descriptor)
|
||||
// Internal for testing.
|
||||
internal List<Func<IRazorPage>> GetPageStartFactories(CompiledPageActionDescriptor descriptor)
|
||||
{
|
||||
var pageStartFactories = new List<Func<IRazorPage>>();
|
||||
var pageStartItems = _razorProject.FindHierarchicalItems(descriptor.ViewEnginePath, PageStartFileName);
|
||||
foreach (var item in pageStartItems)
|
||||
{
|
||||
var factoryResult = _razorPageFactoryProvider.CreateFactory(item.Path);
|
||||
if (factoryResult.Success)
|
||||
if(item.Exists)
|
||||
{
|
||||
pageStartFactories.Insert(0, factoryResult.RazorPageFactory);
|
||||
var factoryResult = _razorPageFactoryProvider.CreateFactory(item.Path);
|
||||
if (factoryResult.Success)
|
||||
{
|
||||
pageStartFactories.Insert(0, factoryResult.RazorPageFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pageStartFactories;
|
||||
}
|
||||
|
||||
private static void PopulateHandlerMethodDescriptors(TypeInfo type, CompiledPageActionDescriptor actionDescriptor)
|
||||
// Internal for testing.
|
||||
internal static void PopulateHandlerMethodDescriptors(TypeInfo type, CompiledPageActionDescriptor actionDescriptor)
|
||||
{
|
||||
var methods = type.GetMethods();
|
||||
for (var i = 0; i < methods.Length; i++)
|
||||
for (var i = 0; i < _handlerMethodNames.Length; i++)
|
||||
{
|
||||
var method = methods[i];
|
||||
if (method.Name.StartsWith("OnGet", StringComparison.Ordinal) ||
|
||||
method.Name.StartsWith("OnPost", StringComparison.Ordinal))
|
||||
var methodName = _handlerMethodNames[i];
|
||||
var method = type.GetMethod(methodName);
|
||||
if (method != null && !method.IsGenericMethod)
|
||||
{
|
||||
actionDescriptor.HandlerMethods.Add(new HandlerMethodDescriptor()
|
||||
{
|
||||
|
|
@ -245,7 +235,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
}
|
||||
}
|
||||
|
||||
private class InnerCache
|
||||
internal class InnerCache
|
||||
{
|
||||
public InnerCache(int version)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -95,6 +95,31 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
Assert.Equal("Hello, handler!", content.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HelloWorldWithPageModelHandler_CanPostContent()
|
||||
{
|
||||
// Arrange
|
||||
var getRequest = new HttpRequestMessage(HttpMethod.Get, "http://localhost/HelloWorldWithPageModelHandler?message=message");
|
||||
var getResponse = await Client.SendAsync(getRequest);
|
||||
var getResponseBody = await getResponse.Content.ReadAsStringAsync();
|
||||
var formToken = AntiforgeryTestHelper.RetrieveAntiforgeryToken(getResponseBody, "/HelloWorlWithPageModelHandler");
|
||||
var cookie = AntiforgeryTestHelper.RetrieveAntiforgeryCookie(getResponse);
|
||||
|
||||
|
||||
var postRequest = new HttpRequestMessage(HttpMethod.Post, "http://localhost/HelloWorldWithPageModelHandler");
|
||||
postRequest.Headers.Add("Cookie", cookie.Key + "=" + cookie.Value);
|
||||
postRequest.Headers.Add("RequestVerificationToken", formToken);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(postRequest);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.StartsWith("Hello, You posted!", content.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HelloWorldWithPageModelHandler_CanGetContent()
|
||||
{
|
||||
|
|
@ -108,7 +133,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Hello, pagemodel!", content.Trim());
|
||||
Assert.StartsWith("Hello, pagemodel!", content.Trim());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
|
@ -14,6 +16,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
|||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moq;
|
||||
|
|
@ -37,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(object));
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
|
|
@ -69,6 +72,61 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
Assert.Null(entry.ReleaseModel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnProvidersExecuting_SetsHandlers()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor
|
||||
{
|
||||
RelativePath = "Path1",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
};
|
||||
Func<PageContext, object> factory = _ => null;
|
||||
Action<PageContext, object> releaser = (_, __) => { };
|
||||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor, typeof(TestSetPageWithModel)));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
var pageFactoryProvider = new Mock<IPageFactoryProvider>();
|
||||
pageFactoryProvider.Setup(f => f.CreatePageFactory(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns(factory);
|
||||
pageFactoryProvider.Setup(f => f.CreatePageDisposer(It.IsAny<CompiledPageActionDescriptor>()))
|
||||
.Returns(releaser);
|
||||
|
||||
var modelFactoryProvider = new Mock<IPageModelFactoryProvider>();
|
||||
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object,
|
||||
pageFactoryProvider.Object,
|
||||
modelFactoryProvider.Object);
|
||||
var context = new ActionInvokerProviderContext(
|
||||
new ActionContext(new DefaultHttpContext(), new RouteData(), descriptor));
|
||||
|
||||
// Act
|
||||
invokerProvider.OnProvidersExecuting(context);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(context.Result);
|
||||
var actionInvoker = Assert.IsType<PageActionInvoker>(context.Result);
|
||||
var entry = actionInvoker.CacheEntry;
|
||||
|
||||
Assert.Collection(entry.ActionDescriptor.HandlerMethods,
|
||||
handlerDescriptor =>
|
||||
{
|
||||
Assert.Equal(nameof(TestSetPageModel.OnGet), handlerDescriptor.Method.Name);
|
||||
Assert.NotNull(handlerDescriptor.Executor);
|
||||
},
|
||||
handlerDescriptor =>
|
||||
{
|
||||
Assert.Equal(nameof(TestSetPageModel.OnPost), handlerDescriptor.Method.Name);
|
||||
Assert.NotNull(handlerDescriptor.Executor);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnProvidersExecuting_WithModel_PopulatesCacheEntry()
|
||||
{
|
||||
|
|
@ -85,7 +143,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(PageWithModel));
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor, pageType: typeof(PageWithModel)));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
|
|
@ -137,7 +195,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(PageWithModel));
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor, pageType: typeof(PageWithModel)));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
|
|
@ -184,7 +242,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(PageWithModel));
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor, pageType: typeof(PageWithModel)));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
|
|
@ -215,7 +273,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void OnProvidersExecuting_CachesEntries()
|
||||
{
|
||||
|
|
@ -227,7 +284,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
};
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(object));
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
|
|
@ -274,7 +331,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(object));
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor));
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object);
|
||||
|
|
@ -299,6 +356,229 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
Assert.NotSame(entry1, entry2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PopulateHandlerMethodDescriptors_DiscoversHandlersFromBaseType()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor()
|
||||
{
|
||||
RelativePath = "Path1",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
ViewEnginePath = "/Views/Deeper/Index.cshtml"
|
||||
};
|
||||
|
||||
var actionDescriptor = CreateCompiledPageActionDescriptor(descriptor, typeof(InheritsMethods));
|
||||
|
||||
var type = actionDescriptor.ModelTypeInfo ?? actionDescriptor.PageTypeInfo;
|
||||
|
||||
// Act
|
||||
PageActionInvokerProvider.PopulateHandlerMethodDescriptors(type, actionDescriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(actionDescriptor.HandlerMethods,
|
||||
(handler) =>
|
||||
{
|
||||
Assert.Equal("OnGet", handler.Method.Name);
|
||||
Assert.Equal(typeof(InheritsMethods), handler.Method.DeclaringType);
|
||||
},
|
||||
(handler) =>
|
||||
{
|
||||
Assert.Equal("OnPost", handler.Method.Name);
|
||||
Assert.Equal(typeof(TestSetPageModel), handler.Method.DeclaringType);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PopulateHandlerMethodDescriptors_ProtectedMethodsNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor()
|
||||
{
|
||||
RelativePath = "Path1",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
ViewEnginePath = "/Views/Deeper/Index.cshtml"
|
||||
};
|
||||
|
||||
var actionDescriptor = CreateCompiledPageActionDescriptor(descriptor, typeof(ProtectedModel));
|
||||
|
||||
var type = actionDescriptor.ModelTypeInfo ?? actionDescriptor.PageTypeInfo;
|
||||
|
||||
// Act
|
||||
PageActionInvokerProvider.PopulateHandlerMethodDescriptors(type, actionDescriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(actionDescriptor.HandlerMethods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PopulateHandlerMethodDescriptors_IgnoreGenericTypeParameters()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor()
|
||||
{
|
||||
RelativePath = "Path1",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
ViewEnginePath = "/Views/Deeper/Index.cshtml"
|
||||
};
|
||||
|
||||
var actionDescriptor = CreateCompiledPageActionDescriptor(descriptor, typeof(GenericClassModel));
|
||||
|
||||
var type = actionDescriptor.ModelTypeInfo ?? actionDescriptor.PageTypeInfo;
|
||||
|
||||
// Act
|
||||
PageActionInvokerProvider.PopulateHandlerMethodDescriptors(type, actionDescriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(actionDescriptor.HandlerMethods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PopulateHandlerMethodDescriptors_AllowOnlyOneMethod()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor()
|
||||
{
|
||||
RelativePath = "Path1",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
ViewEnginePath = "/Views/Deeper/Index.cshtml"
|
||||
};
|
||||
|
||||
var actionDescriptor = CreateCompiledPageActionDescriptor(descriptor, typeof(TestPageModel));
|
||||
|
||||
var type = actionDescriptor.ModelTypeInfo ?? actionDescriptor.PageTypeInfo;
|
||||
|
||||
// Act
|
||||
PageActionInvokerProvider.PopulateHandlerMethodDescriptors(type, actionDescriptor);
|
||||
|
||||
// Assert
|
||||
var handler = Assert.Single(actionDescriptor.HandlerMethods);
|
||||
Assert.Equal("OnGet", handler.Method.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPageStartFactories_FindsFullHeirarchy()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor()
|
||||
{
|
||||
RelativePath = "Path1",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
ViewEnginePath = "/Views/Deeper/Index.cshtml"
|
||||
};
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor, typeof(TestPageModel)));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
|
||||
var fileProvider = new TestFileProvider();
|
||||
fileProvider.AddFile("/View/Deeper/Not_PageStart.cshtml", "page content");
|
||||
fileProvider.AddFile("/View/Wrong/_PageStart.cshtml", "page content");
|
||||
fileProvider.AddFile("/_PageStart.cshtml", "page content ");
|
||||
fileProvider.AddFile("/Views/_PageStart.cshtml", "@page starts!");
|
||||
fileProvider.AddFile("/Views/Deeper/_PageStart.cshtml", "page content");
|
||||
|
||||
var razorProject = CreateRazorProject(fileProvider);
|
||||
|
||||
var mock = new Mock<IRazorPageFactoryProvider>();
|
||||
mock.Setup(p => p.CreateFactory("/Views/Deeper/_PageStart.cshtml"))
|
||||
.Returns(new RazorPageFactoryResult(() => null, new List<IChangeToken>()))
|
||||
.Verifiable();
|
||||
mock.Setup(p => p.CreateFactory("/Views/_PageStart.cshtml"))
|
||||
.Returns(new RazorPageFactoryResult(() => null, new List<IChangeToken>()))
|
||||
.Verifiable();
|
||||
mock.Setup(p => p.CreateFactory("/_PageStart.cshtml"))
|
||||
.Returns(new RazorPageFactoryResult(() => null, new List<IChangeToken>()))
|
||||
.Verifiable();
|
||||
var razorPageFactoryProvider = mock.Object;
|
||||
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object,
|
||||
pageProvider: null,
|
||||
modelProvider: null,
|
||||
razorPageFactoryProvider: razorPageFactoryProvider,
|
||||
razorProject: razorProject);
|
||||
|
||||
var compiledDescriptor = CreateCompiledPageActionDescriptor(descriptor);
|
||||
|
||||
// Act
|
||||
var factories = invokerProvider.GetPageStartFactories(compiledDescriptor);
|
||||
|
||||
// Assert
|
||||
mock.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPageStartFactories_NoFactoriesForMissingFiles()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor()
|
||||
{
|
||||
RelativePath = "Path1",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
ViewEnginePath = "/Views/Deeper/Index.cshtml"
|
||||
};
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(CreateCompiledPageActionDescriptor(descriptor, typeof(TestPageModel)));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
|
||||
// No files
|
||||
var fileProvider = new TestFileProvider();
|
||||
|
||||
var razorProject = CreateRazorProject(fileProvider);
|
||||
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object,
|
||||
pageProvider: null,
|
||||
modelProvider: null,
|
||||
razorPageFactoryProvider: CreateRazorPageFactoryProvider(),
|
||||
razorProject: razorProject);
|
||||
|
||||
var compiledDescriptor = CreateCompiledPageActionDescriptor(descriptor);
|
||||
|
||||
// Act
|
||||
var factories = invokerProvider.GetPageStartFactories(compiledDescriptor);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(factories);
|
||||
}
|
||||
|
||||
private IRazorPageFactoryProvider CreateRazorPageFactoryProvider()
|
||||
{
|
||||
var mock = new Mock<IRazorPageFactoryProvider>();
|
||||
mock.Setup(p => p.CreateFactory(It.IsAny<string>()))
|
||||
.Returns(new RazorPageFactoryResult(() => null, new List<IChangeToken>()));
|
||||
return mock.Object;
|
||||
}
|
||||
|
||||
private RazorProject CreateRazorProject(IFileProvider fileProvider)
|
||||
{
|
||||
return new DefaultRazorProject(fileProvider);
|
||||
}
|
||||
|
||||
private static CompiledPageActionDescriptor CreateCompiledPageActionDescriptor(
|
||||
PageActionDescriptor descriptor,
|
||||
Type pageType = null)
|
||||
{
|
||||
TypeInfo modelTypeInfo = null;
|
||||
if (pageType != null)
|
||||
{
|
||||
modelTypeInfo = pageType.GetTypeInfo().GetProperty("Model")?.PropertyType.GetTypeInfo();
|
||||
}
|
||||
|
||||
return new CompiledPageActionDescriptor(descriptor)
|
||||
{
|
||||
ModelTypeInfo = modelTypeInfo,
|
||||
PageTypeInfo = (pageType ?? typeof(object)).GetTypeInfo()
|
||||
};
|
||||
}
|
||||
|
||||
private static PageActionInvokerProvider CreateInvokerProvider(
|
||||
IPageLoader loader,
|
||||
IActionDescriptorCollectionProvider actionDescriptorProvider,
|
||||
|
|
@ -334,6 +614,53 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
NullLoggerFactory.Instance);
|
||||
}
|
||||
|
||||
private class GenericClassModel
|
||||
{
|
||||
public void OnGet<T>()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSetPageWithModel
|
||||
{
|
||||
public TestSetPageModel Model { get; set; }
|
||||
}
|
||||
|
||||
private class InheritsMethods : TestSetPageModel
|
||||
{
|
||||
public new void OnGet()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class ProtectedModel
|
||||
{
|
||||
protected void OnGet()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void OnPost()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class TestSetPageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnPost()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class PageWithModel
|
||||
{
|
||||
public TestPageModel Model { get; set; }
|
||||
|
|
|
|||
|
|
@ -13,5 +13,10 @@ namespace RazorPagesWebSite
|
|||
{
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public void OnPost()
|
||||
{
|
||||
Message = "You posted!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
@page
|
||||
@model RazorPagesWebSite.HelloWorldWithPageModelHandler
|
||||
|
||||
Hello, @Model.Message!
|
||||
Hello, @Model.Message!
|
||||
|
||||
@using (Html.BeginForm())
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
}
|
||||
Loading…
Reference in New Issue