Add support for PageStarts
This commit is contained in:
parent
c95c2a5a6d
commit
8d5abd433f
|
|
@ -19,6 +19,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
_provider = provider;
|
||||
}
|
||||
|
||||
public override RazorProjectItem GetItem(string path)
|
||||
{
|
||||
EnsureValidPath(path);
|
||||
var fileInfo = _provider.GetFileInfo(path);
|
||||
return new DefaultRazorProjectItem(fileInfo, basePath: string.Empty, path: path);
|
||||
}
|
||||
|
||||
public override IEnumerable<RazorProjectItem> EnumerateItems(string path)
|
||||
{
|
||||
if (path == null)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
public override string Path { get; }
|
||||
|
||||
public override bool Exists => _fileInfo.Exists;
|
||||
|
||||
public override string PhysicalPath => _fileInfo.PhysicalPath;
|
||||
|
||||
public override Stream Read()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes a Razor Page.
|
||||
/// </summary>
|
||||
public class PageResultExecutor : ViewExecutor
|
||||
{
|
||||
private readonly IRazorViewEngine _razorViewEngine;
|
||||
private readonly IRazorPageActivator _razorPageActivator;
|
||||
private readonly HtmlEncoder _htmlEncoder;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="PageResultExecutor"/>.
|
||||
/// </summary>
|
||||
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
|
||||
/// <param name="compositeViewEngine">The <see cref="ICompositeViewEngine"/>.</param>
|
||||
/// <param name="razorViewEngine">The <see cref="IRazorViewEngine"/>.</param>
|
||||
/// <param name="razorPageActivator">The <see cref="IRazorPageActivator"/>.</param>
|
||||
/// <param name="diagnosticSource">The <see cref="DiagnosticSource"/>.</param>
|
||||
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
|
||||
public PageResultExecutor(
|
||||
IHttpResponseStreamWriterFactory writerFactory,
|
||||
ICompositeViewEngine compositeViewEngine,
|
||||
IRazorViewEngine razorViewEngine,
|
||||
IRazorPageActivator razorPageActivator,
|
||||
DiagnosticSource diagnosticSource,
|
||||
HtmlEncoder htmlEncoder)
|
||||
: base(writerFactory, compositeViewEngine, diagnosticSource)
|
||||
{
|
||||
_razorViewEngine = razorViewEngine;
|
||||
_razorPageActivator = razorPageActivator;
|
||||
_htmlEncoder = htmlEncoder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a Razor Page asynchronously.
|
||||
/// </summary>
|
||||
public virtual Task ExecuteAsync(PageContext pageContext, PageViewResult result)
|
||||
{
|
||||
if (result.Model != null)
|
||||
{
|
||||
pageContext.ViewData.Model = result.Model;
|
||||
}
|
||||
|
||||
var view = new RazorView(_razorViewEngine, _razorPageActivator, pageContext.PageStarts, result.Page, _htmlEncoder);
|
||||
return ExecuteAsync(pageContext, result.ContentType, result.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.Core.Internal;
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
|
@ -304,6 +305,23 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
_page = (Page)CacheEntry.PageFactory(_pageContext);
|
||||
_pageContext.Page = _page;
|
||||
|
||||
IRazorPage[] pageStarts;
|
||||
|
||||
if (CacheEntry.PageStartFactories == null || CacheEntry.PageStartFactories.Count == 0)
|
||||
{
|
||||
pageStarts = EmptyArray<IRazorPage>.Instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
pageStarts = new IRazorPage[CacheEntry.PageStartFactories.Count];
|
||||
for (var i = 0; i < pageStarts.Length; i++)
|
||||
{
|
||||
var pageFactory = CacheEntry.PageStartFactories[i];
|
||||
pageStarts[i] = pageFactory();
|
||||
}
|
||||
}
|
||||
_pageContext.PageStarts = pageStarts;
|
||||
|
||||
if (actionDescriptor.ModelTypeInfo == null)
|
||||
{
|
||||
_model = _page;
|
||||
|
|
|
|||
|
|
@ -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 Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||
{
|
||||
|
|
@ -14,6 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
Action<PageContext, object> releasePage,
|
||||
Func<PageContext, object> modelFactory,
|
||||
Action<PageContext, object> releaseModel,
|
||||
IReadOnlyList<Func<IRazorPage>> pageStartFactories,
|
||||
FilterItem[] cacheableFilters)
|
||||
{
|
||||
ActionDescriptor = actionDescriptor;
|
||||
|
|
@ -21,6 +24,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
ReleasePage = releasePage;
|
||||
ModelFactory = modelFactory;
|
||||
ReleaseModel = releaseModel;
|
||||
PageStartFactories = pageStartFactories;
|
||||
CacheableFilters = cacheableFilters;
|
||||
}
|
||||
|
||||
|
|
@ -35,6 +39,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
|
||||
public Func<PageContext, object> ModelFactory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the applicable PageStarts.
|
||||
/// </summary>
|
||||
public IReadOnlyList<Func<IRazorPage>> PageStartFactories { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The action invoked to release a model. This may be <c>null</c>.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -12,8 +12,10 @@ using Microsoft.AspNetCore.Mvc.Filters;
|
|||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
@ -21,10 +23,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
{
|
||||
public class PageActionInvokerProvider : IActionInvokerProvider
|
||||
{
|
||||
private const string PageStartFileName = "_PageStart.cshtml";
|
||||
private const string ModelPropertyName = "Model";
|
||||
private readonly IPageLoader _loader;
|
||||
private readonly IPageFactoryProvider _pageFactoryProvider;
|
||||
private readonly IPageModelFactoryProvider _modelFactoryProvider;
|
||||
private readonly IRazorPageFactoryProvider _razorPageFactoryProvider;
|
||||
private readonly IActionDescriptorCollectionProvider _collectionProvider;
|
||||
private readonly IFilterProvider[] _filterProviders;
|
||||
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
|
||||
|
|
@ -32,6 +36,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
private readonly ITempDataDictionaryFactory _tempDataFactory;
|
||||
private readonly HtmlHelperOptions _htmlHelperOptions;
|
||||
private readonly IPageHandlerMethodSelector _selector;
|
||||
private readonly RazorProject _razorProject;
|
||||
private readonly DiagnosticSource _diagnosticSource;
|
||||
private readonly ILogger<PageActionInvoker> _logger;
|
||||
private volatile InnerCache _currentCache;
|
||||
|
|
@ -40,6 +45,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
IPageLoader loader,
|
||||
IPageFactoryProvider pageFactoryProvider,
|
||||
IPageModelFactoryProvider modelFactoryProvider,
|
||||
IRazorPageFactoryProvider razorPageFactoryProvider,
|
||||
IActionDescriptorCollectionProvider collectionProvider,
|
||||
IEnumerable<IFilterProvider> filterProviders,
|
||||
IEnumerable<IValueProviderFactory> valueProviderFactories,
|
||||
|
|
@ -47,12 +53,14 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
ITempDataDictionaryFactory tempDataFactory,
|
||||
IOptions<HtmlHelperOptions> htmlHelperOptions,
|
||||
IPageHandlerMethodSelector selector,
|
||||
RazorProject razorProject,
|
||||
DiagnosticSource diagnosticSource,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_loader = loader;
|
||||
_pageFactoryProvider = pageFactoryProvider;
|
||||
_modelFactoryProvider = modelFactoryProvider;
|
||||
_razorPageFactoryProvider = razorPageFactoryProvider;
|
||||
_collectionProvider = collectionProvider;
|
||||
_filterProviders = filterProviders.ToArray();
|
||||
_valueProviderFactories = valueProviderFactories.ToArray();
|
||||
|
|
@ -60,6 +68,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
_tempDataFactory = tempDataFactory;
|
||||
_htmlHelperOptions = htmlHelperOptions.Value;
|
||||
_selector = selector;
|
||||
_razorProject = razorProject;
|
||||
_diagnosticSource = diagnosticSource;
|
||||
_logger = loggerFactory.CreateLogger<PageActionInvoker>();
|
||||
}
|
||||
|
|
@ -171,15 +180,34 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
modelReleaser = _modelFactoryProvider.CreateModelDisposer(compiledActionDescriptor);
|
||||
}
|
||||
|
||||
var pageStartFactories = GetPageStartFactories(compiledActionDescriptor);
|
||||
|
||||
return new PageActionInvokerCacheEntry(
|
||||
compiledActionDescriptor,
|
||||
pageFactory,
|
||||
pageDisposer,
|
||||
modelFactory,
|
||||
modelReleaser,
|
||||
pageStartFactories,
|
||||
cachedFilters);
|
||||
}
|
||||
|
||||
private 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)
|
||||
{
|
||||
pageStartFactories.Insert(0, factoryResult.RazorPageFactory);
|
||||
}
|
||||
}
|
||||
|
||||
return pageStartFactories;
|
||||
}
|
||||
|
||||
private class InnerCache
|
||||
{
|
||||
public InnerCache(int version)
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
// 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;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||
{
|
||||
public class PageResultExecutor
|
||||
{
|
||||
public virtual Task ExecuteAsync(PageContext pageContext, PageViewResult result)
|
||||
{
|
||||
if (result.Model != null)
|
||||
{
|
||||
result.Page.PageContext.ViewData.Model = result.Model;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||
|
|
@ -72,5 +75,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
|||
_page = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the applicable _PageStart instances.
|
||||
/// </summary>
|
||||
public IReadOnlyList<IRazorPage> PageStarts { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
|
|
@ -10,7 +11,6 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||
|
|
@ -25,8 +25,6 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
/// </summary>
|
||||
public static readonly string DefaultContentType = "text/html; charset=utf-8";
|
||||
|
||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ViewExecutor"/>.
|
||||
/// </summary>
|
||||
|
|
@ -43,22 +41,13 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
ITempDataDictionaryFactory tempDataFactory,
|
||||
DiagnosticSource diagnosticSource,
|
||||
IModelMetadataProvider modelMetadataProvider)
|
||||
: this(writerFactory, viewEngine, diagnosticSource)
|
||||
{
|
||||
if (viewOptions == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(viewOptions));
|
||||
}
|
||||
|
||||
if (writerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(writerFactory));
|
||||
}
|
||||
|
||||
if (viewEngine == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(viewEngine));
|
||||
}
|
||||
|
||||
if (tempDataFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tempDataFactory));
|
||||
|
|
@ -69,17 +58,40 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
throw new ArgumentNullException(nameof(diagnosticSource));
|
||||
}
|
||||
|
||||
if (modelMetadataProvider == null)
|
||||
ViewOptions = viewOptions.Value;
|
||||
TempDataFactory = tempDataFactory;
|
||||
ModelMetadataProvider = modelMetadataProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ViewExecutor"/>.
|
||||
/// </summary>
|
||||
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
|
||||
/// <param name="viewEngine">The <see cref="ICompositeViewEngine"/>.</param>
|
||||
/// <param name="diagnosticSource">The <see cref="System.Diagnostics.DiagnosticSource"/>.</param>
|
||||
protected ViewExecutor(
|
||||
IHttpResponseStreamWriterFactory writerFactory,
|
||||
ICompositeViewEngine viewEngine,
|
||||
DiagnosticSource diagnosticSource)
|
||||
{
|
||||
if (writerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(modelMetadataProvider));
|
||||
throw new ArgumentNullException(nameof(writerFactory));
|
||||
}
|
||||
|
||||
if (viewEngine == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(viewEngine));
|
||||
}
|
||||
|
||||
if (diagnosticSource == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(diagnosticSource));
|
||||
}
|
||||
|
||||
ViewOptions = viewOptions.Value;
|
||||
WriterFactory = writerFactory;
|
||||
ViewEngine = viewEngine;
|
||||
TempDataFactory = tempDataFactory;
|
||||
DiagnosticSource = diagnosticSource;
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -102,6 +114,11 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
/// </summary>
|
||||
protected MvcViewOptions ViewOptions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IModelMetadataProvider"/>.
|
||||
/// </summary>
|
||||
protected IModelMetadataProvider ModelMetadataProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IHttpResponseStreamWriterFactory"/>.
|
||||
/// </summary>
|
||||
|
|
@ -140,9 +157,24 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
throw new ArgumentNullException(nameof(view));
|
||||
}
|
||||
|
||||
if (ViewOptions == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatPropertyOfTypeCannotBeNull(nameof(ViewOptions), GetType().Name));
|
||||
}
|
||||
|
||||
if (TempDataFactory == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatPropertyOfTypeCannotBeNull(nameof(TempDataFactory), GetType().Name));
|
||||
}
|
||||
|
||||
if (ModelMetadataProvider == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatPropertyOfTypeCannotBeNull(nameof(ModelMetadataProvider), GetType().Name));
|
||||
}
|
||||
|
||||
if (viewData == null)
|
||||
{
|
||||
viewData = new ViewDataDictionary(_modelMetadataProvider, actionContext.ModelState);
|
||||
viewData = new ViewDataDictionary(ModelMetadataProvider, actionContext.ModelState);
|
||||
}
|
||||
|
||||
if (tempData == null)
|
||||
|
|
@ -150,7 +182,40 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
tempData = TempDataFactory.GetTempData(actionContext.HttpContext);
|
||||
}
|
||||
|
||||
var response = actionContext.HttpContext.Response;
|
||||
var viewContext = new ViewContext(
|
||||
actionContext,
|
||||
view,
|
||||
viewData,
|
||||
tempData,
|
||||
TextWriter.Null,
|
||||
ViewOptions.HtmlHelperOptions);
|
||||
|
||||
await ExecuteAsync(viewContext, contentType, statusCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a view asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="viewContext">The <see cref="ViewContext"/> associated with the current request.</param>
|
||||
/// <param name="contentType">
|
||||
/// The content-type header value to set in the response. If <c>null</c>,
|
||||
/// <see cref="DefaultContentType"/> will be used.
|
||||
/// </param>
|
||||
/// <param name="statusCode">
|
||||
/// The HTTP status code to set in the response. May be <c>null</c>.
|
||||
/// </param>
|
||||
/// <returns>A <see cref="Task"/> which will complete when view execution is completed.</returns>
|
||||
protected async Task ExecuteAsync(
|
||||
ViewContext viewContext,
|
||||
string contentType,
|
||||
int? statusCode)
|
||||
{
|
||||
if (viewContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(viewContext));
|
||||
}
|
||||
|
||||
var response = viewContext.HttpContext.Response;
|
||||
|
||||
string resolvedContentType = null;
|
||||
Encoding resolvedContentTypeEncoding = null;
|
||||
|
|
@ -170,19 +235,23 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
|
||||
using (var writer = WriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
|
||||
{
|
||||
var viewContext = new ViewContext(
|
||||
actionContext,
|
||||
view,
|
||||
viewData,
|
||||
tempData,
|
||||
writer,
|
||||
ViewOptions.HtmlHelperOptions);
|
||||
var view = viewContext.View;
|
||||
|
||||
DiagnosticSource.BeforeView(view, viewContext);
|
||||
var oldWriter = viewContext.Writer;
|
||||
try
|
||||
{
|
||||
viewContext.Writer = writer;
|
||||
|
||||
await view.RenderAsync(viewContext);
|
||||
DiagnosticSource.BeforeView(view, viewContext);
|
||||
|
||||
DiagnosticSource.AfterView(view, viewContext);
|
||||
await view.RenderAsync(viewContext);
|
||||
|
||||
DiagnosticSource.AfterView(view, viewContext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
viewContext.Writer = oldWriter;
|
||||
}
|
||||
|
||||
// Perf: Invoke FlushAsync to ensure any buffered content is asynchronously written to the underlying
|
||||
// response asynchronously. In the absence of this line, the buffer gets synchronously written to the
|
||||
|
|
|
|||
|
|
@ -8,10 +8,14 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.Evolution;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -120,6 +124,53 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
Assert.Same(modelDisposer, entry.ReleaseModel);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnProvidersExecuting_CachesViewStartFactories()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor = new PageActionDescriptor
|
||||
{
|
||||
RelativePath = "/Home/Path1/File.cshtml",
|
||||
ViewEnginePath = "/Home/Path1/File.cshtml",
|
||||
FilterDescriptors = new FilterDescriptor[0],
|
||||
};
|
||||
|
||||
var loader = new Mock<IPageLoader>();
|
||||
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
|
||||
.Returns(typeof(PageWithModel));
|
||||
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
|
||||
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
|
||||
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
|
||||
var razorPageFactoryProvider = new Mock<IRazorPageFactoryProvider>();
|
||||
Func<IRazorPage> factory1 = () => null;
|
||||
Func<IRazorPage> factory2 = () => null;
|
||||
razorPageFactoryProvider.Setup(f => f.CreateFactory("/Home/Path1/_PageStart.cshtml"))
|
||||
.Returns(new RazorPageFactoryResult(factory1, new IChangeToken[0]));
|
||||
razorPageFactoryProvider.Setup(f => f.CreateFactory("/_PageStart.cshtml"))
|
||||
.Returns(new RazorPageFactoryResult(factory2, new[] { Mock.Of<IChangeToken>() }));
|
||||
var fileProvider = new TestFileProvider();
|
||||
fileProvider.AddFile("/Home/Path1/_PageStart.cshtml", "content1");
|
||||
fileProvider.AddFile("/_PageStart.cshtml", "content2");
|
||||
var defaultRazorProject = new DefaultRazorProject(fileProvider);
|
||||
|
||||
var invokerProvider = CreateInvokerProvider(
|
||||
loader.Object,
|
||||
actionDescriptorProvider.Object,
|
||||
razorPageFactoryProvider: razorPageFactoryProvider.Object,
|
||||
razorProject: defaultRazorProject);
|
||||
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.Equal(new[] { factory2, factory1 }, entry.PageStartFactories);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OnProvidersExecuting_CachesEntries()
|
||||
{
|
||||
|
|
@ -207,16 +258,24 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
IPageLoader loader,
|
||||
IActionDescriptorCollectionProvider actionDescriptorProvider,
|
||||
IPageFactoryProvider pageProvider = null,
|
||||
IPageModelFactoryProvider modelProvider = null)
|
||||
IPageModelFactoryProvider modelProvider = null,
|
||||
IRazorPageFactoryProvider razorPageFactoryProvider = null,
|
||||
RazorProject razorProject = null)
|
||||
{
|
||||
var tempDataFactory = new Mock<ITempDataDictionaryFactory>();
|
||||
tempDataFactory.Setup(t => t.GetTempData(It.IsAny<HttpContext>()))
|
||||
.Returns((HttpContext context) => new TempDataDictionary(context, Mock.Of<ITempDataProvider>()));
|
||||
|
||||
if (razorProject == null)
|
||||
{
|
||||
razorProject = Mock.Of<RazorProject>();
|
||||
}
|
||||
|
||||
return new PageActionInvokerProvider(
|
||||
loader,
|
||||
pageProvider ?? Mock.Of<IPageFactoryProvider>(),
|
||||
modelProvider ?? Mock.Of<IPageModelFactoryProvider>(),
|
||||
razorPageFactoryProvider ?? Mock.Of<IRazorPageFactoryProvider>(),
|
||||
actionDescriptorProvider,
|
||||
new IFilterProvider[0],
|
||||
new IValueProviderFactory[0],
|
||||
|
|
@ -224,6 +283,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
tempDataFactory.Object,
|
||||
new TestOptionsManager<HtmlHelperOptions>(),
|
||||
Mock.Of<IPageHandlerMethodSelector>(),
|
||||
razorProject,
|
||||
new DiagnosticListener("Microsoft.AspNetCore"),
|
||||
NullLoggerFactory.Instance);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,15 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -346,6 +350,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
null,
|
||||
(context) => null,
|
||||
null,
|
||||
null,
|
||||
new FilterItem[0]);
|
||||
var invoker = CreateInvoker(
|
||||
new[] { filter1.Object, filter2.Object, filter3.Object },
|
||||
|
|
@ -399,6 +404,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
null,
|
||||
(context) => null,
|
||||
null,
|
||||
null,
|
||||
new FilterItem[0]);
|
||||
var invoker = CreateInvoker(
|
||||
new IFilterMetadata[] { filter1.Object, filter2.Object, filter3.Object },
|
||||
|
|
@ -530,12 +536,24 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
int maxAllowedErrorsInModelState = 200,
|
||||
List<IValueProviderFactory> valueProviderFactories = null,
|
||||
RouteData routeData = null,
|
||||
ILogger logger = null,
|
||||
object diagnosticListener = null)
|
||||
ILogger logger = null)
|
||||
{
|
||||
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddSingleton(executor ?? new PageResultExecutor());
|
||||
if (executor == null)
|
||||
{
|
||||
executor = new PageResultExecutor(
|
||||
Mock.Of<IHttpResponseStreamWriterFactory>(),
|
||||
Mock.Of<ICompositeViewEngine>(),
|
||||
Mock.Of<IRazorViewEngine>(),
|
||||
Mock.Of<IRazorPageActivator>(),
|
||||
diagnosticSource,
|
||||
HtmlEncoder.Default);
|
||||
}
|
||||
|
||||
serviceCollection.AddSingleton(executor ?? executor);
|
||||
httpContext.RequestServices = serviceCollection.BuildServiceProvider();
|
||||
|
||||
if (routeData == null)
|
||||
|
|
@ -584,8 +602,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
(c, page) => { (page as IDisposable)?.Dispose(); },
|
||||
_ => Activator.CreateInstance(actionDescriptor.ModelTypeInfo.AsType()),
|
||||
(c, model) => { (model as IDisposable)?.Dispose(); },
|
||||
null,
|
||||
new FilterItem[0]);
|
||||
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
|
||||
|
||||
var invoker = new PageActionInvoker(
|
||||
selector,
|
||||
|
|
@ -603,6 +621,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
private readonly Func<PageContext, Task> _executeAction;
|
||||
|
||||
public TestPageResultExecutor(Func<PageContext, Task> executeAction)
|
||||
: base(
|
||||
Mock.Of<IHttpResponseStreamWriterFactory>(),
|
||||
Mock.Of<ICompositeViewEngine>(),
|
||||
Mock.Of<IRazorViewEngine>(),
|
||||
Mock.Of<IRazorPageActivator>(),
|
||||
new DiagnosticListener("Microsoft.AspNetCore"),
|
||||
HtmlEncoder.Default)
|
||||
{
|
||||
_executeAction = executeAction;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue