parent
1d1b88cf44
commit
8b03e9ef73
|
|
@ -1,5 +1,9 @@
|
||||||
@page
|
@page
|
||||||
@model TestModel
|
@model TestModel
|
||||||
|
@{
|
||||||
|
|
||||||
|
ViewData["Title"] = "Hello from pages";
|
||||||
|
}
|
||||||
|
|
||||||
@functions {
|
@functions {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@{ Layout = "_Layout";}
|
||||||
|
|
@ -4,21 +4,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Antiforgery;
|
|
||||||
using Microsoft.AspNetCore.Html;
|
using Microsoft.AspNetCore.Html;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
using Microsoft.AspNetCore.Mvc.Routing;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
|
||||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor
|
namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -28,34 +21,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
public abstract class RazorPage : RazorPageBase, IRazorPage
|
public abstract class RazorPage : RazorPageBase, IRazorPage
|
||||||
{
|
{
|
||||||
private readonly HashSet<string> _renderedSections = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
private readonly HashSet<string> _renderedSections = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
private readonly Stack<TagHelperScopeInfo> _tagHelperScopes = new Stack<TagHelperScopeInfo>();
|
|
||||||
private IUrlHelper _urlHelper;
|
|
||||||
private ITagHelperFactory _tagHelperFactory;
|
|
||||||
private bool _renderedBody;
|
private bool _renderedBody;
|
||||||
private StringWriter _valueBuffer;
|
|
||||||
private IViewBufferScope _bufferScope;
|
|
||||||
private bool _ignoreBody;
|
private bool _ignoreBody;
|
||||||
private HashSet<string> _ignoredSections;
|
private HashSet<string> _ignoredSections;
|
||||||
private TextWriter _pageWriter;
|
|
||||||
|
|
||||||
public RazorPage()
|
|
||||||
{
|
|
||||||
SectionWriters = new Dictionary<string, RenderAsyncDelegate>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An <see cref="HttpContext"/> representing the current request execution.
|
|
||||||
/// </summary>
|
|
||||||
public HttpContext Context => ViewContext?.HttpContext;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Path { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ViewContext ViewContext { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Layout { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="System.Text.Encodings.Web.HtmlEncoder"/> to use when this <see cref="RazorPage"/>
|
/// Gets the <see cref="System.Text.Encodings.Web.HtmlEncoder"/> to use when this <see cref="RazorPage"/>
|
||||||
|
|
@ -70,33 +38,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
[RazorInject]
|
[RazorInject]
|
||||||
public DiagnosticSource DiagnosticSource { get; set; }
|
public DiagnosticSource DiagnosticSource { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="TextWriter"/> that the page is writing output to.
|
|
||||||
/// </summary>
|
|
||||||
public virtual TextWriter Output
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (ViewContext == null)
|
|
||||||
{
|
|
||||||
var message = Resources.FormatViewContextMustBeSet("ViewContext", "Output");
|
|
||||||
throw new InvalidOperationException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ViewContext.Writer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="ClaimsPrincipal"/> of the current logged in user.
|
/// Gets the <see cref="ClaimsPrincipal"/> of the current logged in user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual ClaimsPrincipal User => Context?.User;
|
public virtual ClaimsPrincipal User => Context?.User;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the dynamic view data dictionary.
|
|
||||||
/// </summary>
|
|
||||||
public dynamic ViewBag => ViewContext?.ViewBag;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="ITempDataDictionary"/> from the <see cref="ViewContext"/>.
|
/// Gets the <see cref="ITempDataDictionary"/> from the <see cref="ViewContext"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -106,47 +52,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IHtmlContent BodyContent { get; set; }
|
public IHtmlContent BodyContent { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool IsLayoutBeingRendered { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IDictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; }
|
public IDictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IDictionary<string, RenderAsyncDelegate> SectionWriters { get; }
|
|
||||||
|
|
||||||
protected override TextWriter Writer => Output;
|
|
||||||
|
|
||||||
protected override HtmlEncoder Encoder => HtmlEncoder;
|
protected override HtmlEncoder Encoder => HtmlEncoder;
|
||||||
|
|
||||||
private ITagHelperFactory TagHelperFactory
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_tagHelperFactory == null)
|
|
||||||
{
|
|
||||||
var services = ViewContext.HttpContext.RequestServices;
|
|
||||||
_tagHelperFactory = services.GetRequiredService<ITagHelperFactory>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _tagHelperFactory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IViewBufferScope BufferScope
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_bufferScope == null)
|
|
||||||
{
|
|
||||||
var services = ViewContext.HttpContext.RequestServices;
|
|
||||||
_bufferScope = services.GetRequiredService<IViewBufferScope>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _bufferScope;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Format an error message about using an indexer when the tag helper property is <c>null</c>.
|
/// Format an error message about using an indexer when the tag helper property is <c>null</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -165,142 +75,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
propertyName);
|
propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates and activates a <see cref="ITagHelper"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TTagHelper">A <see cref="ITagHelper"/> type.</typeparam>
|
|
||||||
/// <returns>The activated <see cref="ITagHelper"/>.</returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// <typeparamref name="TTagHelper"/> must have a parameterless constructor.
|
|
||||||
/// </remarks>
|
|
||||||
public TTagHelper CreateTagHelper<TTagHelper>() where TTagHelper : ITagHelper
|
|
||||||
{
|
|
||||||
return TagHelperFactory.CreateTagHelper<TTagHelper>(ViewContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Starts a new writing scope and optionally overrides <see cref="HtmlEncoder"/> within that scope.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encoder">
|
|
||||||
/// The <see cref="System.Text.Encodings.Web.HtmlEncoder"/> to use when this <see cref="RazorPage"/> handles
|
|
||||||
/// non-<see cref="IHtmlContent"/> C# expressions. If <c>null</c>, does not change <see cref="HtmlEncoder"/>.
|
|
||||||
/// </param>
|
|
||||||
/// <remarks>
|
|
||||||
/// All writes to the <see cref="Writer"/> or <see cref="ViewContext.Writer"/> after calling this method will
|
|
||||||
/// be buffered until <see cref="EndTagHelperWritingScope"/> is called.
|
|
||||||
/// </remarks>
|
|
||||||
public void StartTagHelperWritingScope(HtmlEncoder encoder)
|
|
||||||
{
|
|
||||||
var buffer = new ViewBuffer(BufferScope, Path, ViewBuffer.TagHelperPageSize);
|
|
||||||
_tagHelperScopes.Push(new TagHelperScopeInfo(buffer, HtmlEncoder, ViewContext.Writer));
|
|
||||||
|
|
||||||
// If passed an HtmlEncoder, override the property.
|
|
||||||
if (encoder != null)
|
|
||||||
{
|
|
||||||
HtmlEncoder = encoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to replace the ViewContext's Writer to ensure that all content (including content written
|
|
||||||
// from HTML helpers) is redirected.
|
|
||||||
ViewContext.Writer = new ViewBufferTextWriter(buffer, ViewContext.Writer.Encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ends the current writing scope that was started by calling <see cref="StartTagHelperWritingScope"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The buffered <see cref="TagHelperContent"/>.</returns>
|
|
||||||
public TagHelperContent EndTagHelperWritingScope()
|
|
||||||
{
|
|
||||||
if (_tagHelperScopes.Count == 0)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Resources.RazorPage_ThereIsNoActiveWritingScopeToEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
var scopeInfo = _tagHelperScopes.Pop();
|
|
||||||
|
|
||||||
// Get the content written during the current scope.
|
|
||||||
var tagHelperContent = new DefaultTagHelperContent();
|
|
||||||
tagHelperContent.AppendHtml(scopeInfo.Buffer);
|
|
||||||
|
|
||||||
// Restore previous scope.
|
|
||||||
HtmlEncoder = scopeInfo.Encoder;
|
|
||||||
ViewContext.Writer = scopeInfo.Writer;
|
|
||||||
|
|
||||||
return tagHelperContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Starts a new scope for writing <see cref="ITagHelper"/> attribute values.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// All writes to the <see cref="Writer"/> or <see cref="ViewContext.Writer"/> after calling this method will
|
|
||||||
/// be buffered until <see cref="EndWriteTagHelperAttribute"/> is called.
|
|
||||||
/// The content will be buffered using a shared <see cref="StringWriter"/> within this <see cref="RazorPage"/>
|
|
||||||
/// Nesting of <see cref="BeginWriteTagHelperAttribute"/> and <see cref="EndWriteTagHelperAttribute"/> method calls
|
|
||||||
/// is not supported.
|
|
||||||
/// </remarks>
|
|
||||||
public void BeginWriteTagHelperAttribute()
|
|
||||||
{
|
|
||||||
if (_pageWriter != null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Resources.RazorPage_NestingAttributeWritingScopesNotSupported);
|
|
||||||
}
|
|
||||||
|
|
||||||
_pageWriter = ViewContext.Writer;
|
|
||||||
|
|
||||||
if (_valueBuffer == null)
|
|
||||||
{
|
|
||||||
_valueBuffer = new StringWriter();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to replace the ViewContext's Writer to ensure that all content (including content written
|
|
||||||
// from HTML helpers) is redirected.
|
|
||||||
ViewContext.Writer = _valueBuffer;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ends the current writing scope that was started by calling <see cref="BeginWriteTagHelperAttribute"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The content buffered by the shared <see cref="StringWriter"/> of this <see cref="RazorPage"/>.</returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// This method assumes that there will be no nesting of <see cref="BeginWriteTagHelperAttribute"/>
|
|
||||||
/// and <see cref="EndWriteTagHelperAttribute"/> method calls.
|
|
||||||
/// </remarks>
|
|
||||||
public string EndWriteTagHelperAttribute()
|
|
||||||
{
|
|
||||||
if (_pageWriter == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(Resources.RazorPage_ThereIsNoActiveWritingScopeToEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
var content = _valueBuffer.ToString();
|
|
||||||
_valueBuffer.GetStringBuilder().Clear();
|
|
||||||
|
|
||||||
// Restore previous writer.
|
|
||||||
ViewContext.Writer = _pageWriter;
|
|
||||||
_pageWriter = null;
|
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Href(string contentPath)
|
|
||||||
{
|
|
||||||
if (contentPath == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_urlHelper == null)
|
|
||||||
{
|
|
||||||
var services = Context.RequestServices;
|
|
||||||
var factory = services.GetRequiredService<IUrlHelperFactory>();
|
|
||||||
_urlHelper = factory.GetUrlHelper(ViewContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _urlHelper.Content(contentPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// In a Razor layout page, renders the portion of a content page that is not within a named section.
|
/// In a Razor layout page, renders the portion of a content page that is not within a named section.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -371,7 +145,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the section to render.</param>
|
/// <param name="name">The name of the section to render.</param>
|
||||||
/// <returns>An empty <see cref="IHtmlContent"/>.</returns>
|
/// <returns>An empty <see cref="IHtmlContent"/>.</returns>
|
||||||
/// <remarks>The method writes to the <see cref="Writer"/> and the value returned is a token
|
/// <remarks>The method writes to the <see cref="RazorPageBase.Output"/> and the value returned is a token
|
||||||
/// value that allows the Write (produced due to @RenderSection(..)) to succeed. However the
|
/// value that allows the Write (produced due to @RenderSection(..)) to succeed. However the
|
||||||
/// value does not represent the rendered content.</remarks>
|
/// value does not represent the rendered content.</remarks>
|
||||||
public HtmlString RenderSection(string name)
|
public HtmlString RenderSection(string name)
|
||||||
|
|
@ -390,7 +164,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
/// <param name="name">The section to render.</param>
|
/// <param name="name">The section to render.</param>
|
||||||
/// <param name="required">Indicates if this section must be rendered.</param>
|
/// <param name="required">Indicates if this section must be rendered.</param>
|
||||||
/// <returns>An empty <see cref="IHtmlContent"/>.</returns>
|
/// <returns>An empty <see cref="IHtmlContent"/>.</returns>
|
||||||
/// <remarks>The method writes to the <see cref="Writer"/> and the value returned is a token
|
/// <remarks>The method writes to the <see cref="RazorPageBase.Output"/> and the value returned is a token
|
||||||
/// value that allows the Write (produced due to @RenderSection(..)) to succeed. However the
|
/// value that allows the Write (produced due to @RenderSection(..)) to succeed. However the
|
||||||
/// value does not represent the rendered content.</remarks>
|
/// value does not represent the rendered content.</remarks>
|
||||||
public HtmlString RenderSection(string name, bool required)
|
public HtmlString RenderSection(string name, bool required)
|
||||||
|
|
@ -413,7 +187,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// A <see cref="Task{HtmlString}"/> that on completion returns an empty <see cref="IHtmlContent"/>.
|
/// A <see cref="Task{HtmlString}"/> that on completion returns an empty <see cref="IHtmlContent"/>.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <remarks>The method writes to the <see cref="Writer"/> and the value returned is a token
|
/// <remarks>The method writes to the <see cref="RazorPageBase.Output"/> and the value returned is a token
|
||||||
/// value that allows the Write (produced due to @RenderSection(..)) to succeed. However the
|
/// value that allows the Write (produced due to @RenderSection(..)) to succeed. However the
|
||||||
/// value does not represent the rendered content.</remarks>
|
/// value does not represent the rendered content.</remarks>
|
||||||
public Task<HtmlString> RenderSectionAsync(string name)
|
public Task<HtmlString> RenderSectionAsync(string name)
|
||||||
|
|
@ -435,7 +209,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// A <see cref="Task{HtmlString}"/> that on completion returns an empty <see cref="IHtmlContent"/>.
|
/// A <see cref="Task{HtmlString}"/> that on completion returns an empty <see cref="IHtmlContent"/>.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
/// <remarks>The method writes to the <see cref="Writer"/> and the value returned is a token
|
/// <remarks>The method writes to the <see cref="RazorPageBase.Output"/> and the value returned is a token
|
||||||
/// value that allows the Write (produced due to @RenderSection(..)) to succeed. However the
|
/// value that allows the Write (produced due to @RenderSection(..)) to succeed. However the
|
||||||
/// value does not represent the rendered content.</remarks>
|
/// value does not represent the rendered content.</remarks>
|
||||||
/// <exception cref="InvalidOperationException">if <paramref name="required"/> is <c>true</c> and the section
|
/// <exception cref="InvalidOperationException">if <paramref name="required"/> is <c>true</c> and the section
|
||||||
|
|
@ -514,40 +288,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
_ignoredSections.Add(sectionName);
|
_ignoredSections.Add(sectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invokes <see cref="TextWriter.FlushAsync"/> on <see cref="Writer"/> and <see cref="M:Stream.FlushAsync"/>
|
|
||||||
/// on the response stream, writing out any buffered content to the <see cref="HttpResponse.Body"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A <see cref="Task{HtmlString}"/> that represents the asynchronous flush operation and on
|
|
||||||
/// completion returns an empty <see cref="IHtmlContent"/>.</returns>
|
|
||||||
/// <remarks>The value returned is a token value that allows FlushAsync to work directly in an HTML
|
|
||||||
/// section. However the value does not represent the rendered content.
|
|
||||||
/// This method also writes out headers, so any modifications to headers must be done before
|
|
||||||
/// <see cref="FlushAsync"/> is called. For example, call <see cref="SetAntiforgeryCookieAndHeader"/> to send
|
|
||||||
/// antiforgery cookie token and X-Frame-Options header to client before this method flushes headers out.
|
|
||||||
/// </remarks>
|
|
||||||
public async Task<HtmlString> FlushAsync()
|
|
||||||
{
|
|
||||||
// If there are active scopes, then we should throw. Cannot flush content that has the potential to change.
|
|
||||||
if (_tagHelperScopes.Count > 0)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
Resources.FormatRazorPage_CannotFlushWhileInAWritingScope(nameof(FlushAsync), Path));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calls to Flush are allowed if the page does not specify a Layout or if it is executing a section in the
|
|
||||||
// Layout.
|
|
||||||
if (!IsLayoutBeingRendered && !string.IsNullOrEmpty(Layout))
|
|
||||||
{
|
|
||||||
var message = Resources.FormatLayoutCannotBeRendered(Path, nameof(FlushAsync));
|
|
||||||
throw new InvalidOperationException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Writer.FlushAsync();
|
|
||||||
await Context.Response.Body.FlushAsync();
|
|
||||||
return HtmlString.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void EnsureRenderedBodyOrSections()
|
public void EnsureRenderedBodyOrSections()
|
||||||
{
|
{
|
||||||
|
|
@ -619,20 +359,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets antiforgery cookie and X-Frame-Options header on the response.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>An empty <see cref="IHtmlContent"/>.</returns>
|
|
||||||
/// <remarks> Call this method to send antiforgery cookie token and X-Frame-Options header to client
|
|
||||||
/// before <see cref="FlushAsync"/> flushes the headers. </remarks>
|
|
||||||
public virtual HtmlString SetAntiforgeryCookieAndHeader()
|
|
||||||
{
|
|
||||||
var antiforgery = Context.RequestServices.GetRequiredService<IAntiforgery>();
|
|
||||||
antiforgery.SetCookieTokenAndHeader(Context);
|
|
||||||
|
|
||||||
return HtmlString.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureMethodCanBeInvoked(string methodName)
|
private void EnsureMethodCanBeInvoked(string methodName)
|
||||||
{
|
{
|
||||||
if (PreviousSectionWriters == null)
|
if (PreviousSectionWriters == null)
|
||||||
|
|
@ -640,21 +366,5 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
throw new InvalidOperationException(Resources.FormatRazorPage_MethodCannotBeCalled(methodName, Path));
|
throw new InvalidOperationException(Resources.FormatRazorPage_MethodCannotBeCalled(methodName, Path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct TagHelperScopeInfo
|
|
||||||
{
|
|
||||||
public TagHelperScopeInfo(ViewBuffer buffer, HtmlEncoder encoder, TextWriter writer)
|
|
||||||
{
|
|
||||||
Buffer = buffer;
|
|
||||||
Encoder = encoder;
|
|
||||||
Writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ViewBuffer Buffer { get; }
|
|
||||||
|
|
||||||
public HtmlEncoder Encoder { get; }
|
|
||||||
|
|
||||||
public TextWriter Writer { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,14 +2,20 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Antiforgery;
|
||||||
using Microsoft.AspNetCore.Html;
|
using Microsoft.AspNetCore.Html;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Routing;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
|
||||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Razor
|
namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -18,26 +24,245 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class RazorPageBase
|
public abstract class RazorPageBase
|
||||||
{
|
{
|
||||||
|
private StringWriter _valueBuffer;
|
||||||
|
private ITagHelperFactory _tagHelperFactory;
|
||||||
|
private IViewBufferScope _bufferScope;
|
||||||
|
private TextWriter _pageWriter;
|
||||||
private AttributeInfo _attributeInfo;
|
private AttributeInfo _attributeInfo;
|
||||||
private TagHelperAttributeInfo _tagHelperAttributeInfo;
|
private TagHelperAttributeInfo _tagHelperAttributeInfo;
|
||||||
private StringWriter _valueBuffer;
|
private IUrlHelper _urlHelper;
|
||||||
|
|
||||||
|
public ViewContext ViewContext { get; set; }
|
||||||
|
|
||||||
|
public string Layout { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="HttpContext"/> representing the current request execution.
|
||||||
|
/// </summary>
|
||||||
|
public HttpContext Context => ViewContext?.HttpContext;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="TextWriter"/> that the page is writing output to.
|
/// Gets the <see cref="TextWriter"/> that the page is writing output to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract TextWriter Writer { get; }
|
/// <summary>
|
||||||
|
/// Gets the <see cref="TextWriter"/> that the page is writing output to.
|
||||||
|
/// </summary>
|
||||||
|
public virtual TextWriter Output
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (ViewContext == null)
|
||||||
|
{
|
||||||
|
var message = Resources.FormatViewContextMustBeSet("ViewContext", "Output");
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract HtmlEncoder Encoder { get; }
|
return ViewContext.Writer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Path { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IDictionary<string, RenderAsyncDelegate> SectionWriters { get; } =
|
||||||
|
new Dictionary<string, RenderAsyncDelegate>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the dynamic view data dictionary.
|
||||||
|
/// </summary>
|
||||||
|
public dynamic ViewBag => ViewContext?.ViewBag;
|
||||||
|
|
||||||
|
public bool IsLayoutBeingRendered { get; set; }
|
||||||
|
|
||||||
|
protected virtual HtmlEncoder Encoder { get; set; }
|
||||||
|
|
||||||
|
protected Stack<TagHelperScopeInfo> TagHelperScopes { get; } = new Stack<TagHelperScopeInfo>();
|
||||||
|
|
||||||
|
private ITagHelperFactory TagHelperFactory
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_tagHelperFactory == null)
|
||||||
|
{
|
||||||
|
var services = ViewContext.HttpContext.RequestServices;
|
||||||
|
_tagHelperFactory = services.GetRequiredService<ITagHelperFactory>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _tagHelperFactory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IViewBufferScope BufferScope
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_bufferScope == null)
|
||||||
|
{
|
||||||
|
var services = ViewContext.HttpContext.RequestServices;
|
||||||
|
_bufferScope = services.GetRequiredService<IViewBufferScope>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _bufferScope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public abstract Task ExecuteAsync();
|
public abstract Task ExecuteAsync();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes the specified <paramref name="value"/> with HTML encoding to <see cref="Writer"/>.
|
/// Creates and activates a <see cref="ITagHelper"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TTagHelper">A <see cref="ITagHelper"/> type.</typeparam>
|
||||||
|
/// <returns>The activated <see cref="ITagHelper"/>.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// <typeparamref name="TTagHelper"/> must have a parameterless constructor.
|
||||||
|
/// </remarks>
|
||||||
|
public TTagHelper CreateTagHelper<TTagHelper>() where TTagHelper : ITagHelper
|
||||||
|
{
|
||||||
|
return TagHelperFactory.CreateTagHelper<TTagHelper>(ViewContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts a new writing scope and optionally overrides <see cref="HtmlEncoder"/> within that scope.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="encoder">
|
||||||
|
/// The <see cref="System.Text.Encodings.Web.HtmlEncoder"/> to use when this <see cref="RazorPage"/> handles
|
||||||
|
/// non-<see cref="IHtmlContent"/> C# expressions. If <c>null</c>, does not change <see cref="HtmlEncoder"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <remarks>
|
||||||
|
/// All writes to the <see cref="Output"/> or <see cref="ViewContext.Writer"/> after calling this method will
|
||||||
|
/// be buffered until <see cref="EndTagHelperWritingScope"/> is called.
|
||||||
|
/// </remarks>
|
||||||
|
public void StartTagHelperWritingScope(HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
var buffer = new ViewBuffer(BufferScope, Path, ViewBuffer.TagHelperPageSize);
|
||||||
|
TagHelperScopes.Push(new TagHelperScopeInfo(buffer, Encoder, ViewContext.Writer));
|
||||||
|
|
||||||
|
// If passed an HtmlEncoder, override the property.
|
||||||
|
if (encoder != null)
|
||||||
|
{
|
||||||
|
Encoder = encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to replace the ViewContext's Writer to ensure that all content (including content written
|
||||||
|
// from HTML helpers) is redirected.
|
||||||
|
ViewContext.Writer = new ViewBufferTextWriter(buffer, ViewContext.Writer.Encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ends the current writing scope that was started by calling <see cref="StartTagHelperWritingScope"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The buffered <see cref="TagHelperContent"/>.</returns>
|
||||||
|
public TagHelperContent EndTagHelperWritingScope()
|
||||||
|
{
|
||||||
|
var scopeInfo = TagHelperScopes.Pop();
|
||||||
|
|
||||||
|
// Get the content written during the current scope.
|
||||||
|
var tagHelperContent = new DefaultTagHelperContent();
|
||||||
|
tagHelperContent.AppendHtml(scopeInfo.Buffer);
|
||||||
|
|
||||||
|
// Restore previous scope.
|
||||||
|
Encoder = scopeInfo.Encoder;
|
||||||
|
ViewContext.Writer = scopeInfo.Writer;
|
||||||
|
|
||||||
|
return tagHelperContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts a new scope for writing <see cref="ITagHelper"/> attribute values.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// All writes to the <see cref="Output"/> or <see cref="ViewContext.Writer"/> after calling this method will
|
||||||
|
/// be buffered until <see cref="EndWriteTagHelperAttribute"/> is called.
|
||||||
|
/// The content will be buffered using a shared <see cref="StringWriter"/> within this <see cref="RazorPage"/>
|
||||||
|
/// Nesting of <see cref="BeginWriteTagHelperAttribute"/> and <see cref="EndWriteTagHelperAttribute"/> method calls
|
||||||
|
/// is not supported.
|
||||||
|
/// </remarks>
|
||||||
|
public void BeginWriteTagHelperAttribute()
|
||||||
|
{
|
||||||
|
_pageWriter = ViewContext.Writer;
|
||||||
|
|
||||||
|
if (_valueBuffer == null)
|
||||||
|
{
|
||||||
|
_valueBuffer = new StringWriter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to replace the ViewContext's Writer to ensure that all content (including content written
|
||||||
|
// from HTML helpers) is redirected.
|
||||||
|
ViewContext.Writer = _valueBuffer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ends the current writing scope that was started by calling <see cref="BeginWriteTagHelperAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The content buffered by the shared <see cref="StringWriter"/> of this <see cref="RazorPage"/>.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method assumes that there will be no nesting of <see cref="BeginWriteTagHelperAttribute"/>
|
||||||
|
/// and <see cref="EndWriteTagHelperAttribute"/> method calls.
|
||||||
|
/// </remarks>
|
||||||
|
public string EndWriteTagHelperAttribute()
|
||||||
|
{
|
||||||
|
var content = _valueBuffer.ToString();
|
||||||
|
_valueBuffer.GetStringBuilder().Clear();
|
||||||
|
|
||||||
|
// Restore previous writer.
|
||||||
|
ViewContext.Writer = _pageWriter;
|
||||||
|
_pageWriter = null;
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string Href(string contentPath)
|
||||||
|
{
|
||||||
|
if (contentPath == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(contentPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_urlHelper == null)
|
||||||
|
{
|
||||||
|
var services = Context.RequestServices;
|
||||||
|
var factory = services.GetRequiredService<IUrlHelperFactory>();
|
||||||
|
_urlHelper = factory.GetUrlHelper(ViewContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _urlHelper.Content(contentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a named content section in the page that can be invoked in a Layout page using
|
||||||
|
/// <c>RenderSection</c> or <c>RenderSectionAsync</c>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the section to create.</param>
|
||||||
|
/// <param name="section">The <see cref="RenderAsyncDelegate"/> to execute when rendering the section.</param>
|
||||||
|
public virtual void DefineSection(string name, RenderAsyncDelegate section)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(section));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SectionWriters.ContainsKey(name))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.FormatSectionAlreadyDefined(name));
|
||||||
|
}
|
||||||
|
SectionWriters[name] = section;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the specified <paramref name="value"/> with HTML encoding to <see cref="Output"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The <see cref="object"/> to write.</param>
|
/// <param name="value">The <see cref="object"/> to write.</param>
|
||||||
public virtual void Write(object value)
|
public virtual void Write(object value)
|
||||||
{
|
{
|
||||||
WriteTo(Writer, value);
|
WriteTo(Output, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -149,12 +374,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes the specified <paramref name="value"/> without HTML encoding to <see cref="Writer"/>.
|
/// Writes the specified <paramref name="value"/> without HTML encoding to <see cref="Output"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The <see cref="object"/> to write.</param>
|
/// <param name="value">The <see cref="object"/> to write.</param>
|
||||||
public virtual void WriteLiteral(object value)
|
public virtual void WriteLiteral(object value)
|
||||||
{
|
{
|
||||||
WriteLiteralTo(Writer, value);
|
WriteLiteralTo(Output, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -176,7 +401,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes the specified <paramref name="value"/> without HTML encoding to <see cref="Writer"/>.
|
/// Writes the specified <paramref name="value"/> without HTML encoding to <see cref="Output"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="writer">The <see cref="TextWriter"/> instance to write to.</param>
|
/// <param name="writer">The <see cref="TextWriter"/> instance to write to.</param>
|
||||||
/// <param name="value">The <see cref="string"/> to write.</param>
|
/// <param name="value">The <see cref="string"/> to write.</param>
|
||||||
|
|
@ -201,7 +426,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
int suffixOffset,
|
int suffixOffset,
|
||||||
int attributeValuesCount)
|
int attributeValuesCount)
|
||||||
{
|
{
|
||||||
BeginWriteAttributeTo(Writer, name, prefix, prefixOffset, suffix, suffixOffset, attributeValuesCount);
|
BeginWriteAttributeTo(Output, name, prefix, prefixOffset, suffix, suffixOffset, attributeValuesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void BeginWriteAttributeTo(
|
public virtual void BeginWriteAttributeTo(
|
||||||
|
|
@ -246,7 +471,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
int valueLength,
|
int valueLength,
|
||||||
bool isLiteral)
|
bool isLiteral)
|
||||||
{
|
{
|
||||||
WriteAttributeValueTo(Writer, prefix, prefixOffset, value, valueOffset, valueLength, isLiteral);
|
WriteAttributeValueTo(Output, prefix, prefixOffset, value, valueOffset, valueLength, isLiteral);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteAttributeValueTo(
|
public void WriteAttributeValueTo(
|
||||||
|
|
@ -297,7 +522,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
|
|
||||||
public virtual void EndWriteAttribute()
|
public virtual void EndWriteAttribute()
|
||||||
{
|
{
|
||||||
EndWriteAttributeTo(Writer);
|
EndWriteAttributeTo(Output);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void EndWriteAttributeTo(TextWriter writer)
|
public virtual void EndWriteAttributeTo(TextWriter writer)
|
||||||
|
|
@ -392,7 +617,54 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract string Href(string contentPath);
|
/// <summary>
|
||||||
|
/// Invokes <see cref="TextWriter.FlushAsync"/> on <see cref="Output"/> and <see cref="m:Stream.FlushAsync"/>
|
||||||
|
/// on the response stream, writing out any buffered content to the <see cref="HttpResponse.Body"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="Task{HtmlString}"/> that represents the asynchronous flush operation and on
|
||||||
|
/// completion returns an empty <see cref="IHtmlContent"/>.</returns>
|
||||||
|
/// <remarks>The value returned is a token value that allows FlushAsync to work directly in an HTML
|
||||||
|
/// section. However the value does not represent the rendered content.
|
||||||
|
/// This method also writes out headers, so any modifications to headers must be done before
|
||||||
|
/// <see cref="FlushAsync"/> is called. For example, call <see cref="SetAntiforgeryCookieAndHeader"/> to send
|
||||||
|
/// antiforgery cookie token and X-Frame-Options header to client before this method flushes headers out.
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
public virtual async Task<HtmlString> FlushAsync()
|
||||||
|
{
|
||||||
|
// If there are active scopes, then we should throw. Cannot flush content that has the potential to change.
|
||||||
|
if (TagHelperScopes.Count > 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Resources.FormatRazorPage_CannotFlushWhileInAWritingScope(nameof(FlushAsync), Path))");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls to Flush are allowed if the page does not specify a Layout or if it is executing a section in the
|
||||||
|
// Layout.
|
||||||
|
if (!IsLayoutBeingRendered && !string.IsNullOrEmpty(Layout))
|
||||||
|
{
|
||||||
|
var message = Resources.FormatLayoutCannotBeRendered(Path, nameof(FlushAsync));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Output.FlushAsync();
|
||||||
|
await Context.Response.Body.FlushAsync();
|
||||||
|
return HtmlString.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets antiforgery cookie and X-Frame-Options header on the response.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An empty <see cref="IHtmlContent"/>.</returns>
|
||||||
|
/// <remarks> Call this method to send antiforgery cookie token and X-Frame-Options header to client
|
||||||
|
/// before <see cref="RazorPageBase.FlushAsync"/> flushes the headers. </remarks>
|
||||||
|
public virtual HtmlString SetAntiforgeryCookieAndHeader()
|
||||||
|
{
|
||||||
|
var antiforgery = Context.RequestServices.GetRequiredService<IAntiforgery>();
|
||||||
|
antiforgery.SetCookieTokenAndHeader(Context);
|
||||||
|
|
||||||
|
return HtmlString.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
private void WriteUnprefixedAttributeValueTo(TextWriter writer, object value, bool isLiteral)
|
private void WriteUnprefixedAttributeValueTo(TextWriter writer, object value, bool isLiteral)
|
||||||
{
|
{
|
||||||
|
|
@ -424,13 +696,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
EndContext();
|
EndContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a named content section in the page.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of the section to create.</param>
|
|
||||||
/// <param name="section">The <see cref="RenderAsyncDelegate"/> to execute when rendering the section.</param>
|
|
||||||
public abstract void DefineSection(string name, RenderAsyncDelegate section);
|
|
||||||
|
|
||||||
public abstract void BeginContext(int position, int length, bool isLiteral);
|
public abstract void BeginContext(int position, int length, bool isLiteral);
|
||||||
|
|
||||||
public abstract void EndContext();
|
public abstract void EndContext();
|
||||||
|
|
@ -510,5 +775,21 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
|
|
||||||
public bool Suppressed { get; set; }
|
public bool Suppressed { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected struct TagHelperScopeInfo
|
||||||
|
{
|
||||||
|
public TagHelperScopeInfo(ViewBuffer buffer, HtmlEncoder encoder, TextWriter writer)
|
||||||
|
{
|
||||||
|
Buffer = buffer;
|
||||||
|
Encoder = encoder;
|
||||||
|
Writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ViewBuffer Buffer { get; }
|
||||||
|
|
||||||
|
public HtmlEncoder Encoder { get; }
|
||||||
|
|
||||||
|
public TextWriter Writer { get; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,8 +40,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
: base(writerFactory, compositeViewEngine, diagnosticSource)
|
: base(writerFactory, compositeViewEngine, diagnosticSource)
|
||||||
{
|
{
|
||||||
_razorViewEngine = razorViewEngine;
|
_razorViewEngine = razorViewEngine;
|
||||||
_razorPageActivator = new PassThruRazorPageActivator(razorPageActivator);
|
|
||||||
_htmlEncoder = htmlEncoder;
|
_htmlEncoder = htmlEncoder;
|
||||||
|
_razorPageActivator = new PassThruRazorPageActivator(razorPageActivator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
{
|
{
|
||||||
|
|
@ -20,10 +22,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
var razorView = (RazorView)context.View;
|
var razorView = (RazorView)context.View;
|
||||||
if (ReferenceEquals(page, razorView.RazorPage))
|
if (ReferenceEquals(page, razorView.RazorPage))
|
||||||
{
|
{
|
||||||
return;
|
var pageContext = (PageContext)context;
|
||||||
}
|
var vddType = typeof(ViewDataDictionary<>);
|
||||||
|
vddType = vddType.MakeGenericType(pageContext.ActionDescriptor.ModelTypeInfo.AsType());
|
||||||
|
|
||||||
_pageActivator.Activate(page, context);
|
context.ViewData = (ViewDataDictionary)Activator.CreateInstance(vddType, context.ViewData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pageActivator.Activate(page, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using Microsoft.AspNetCore.Html;
|
using Microsoft.AspNetCore.Html;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Routing;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.RazorPages
|
namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
|
|
@ -27,29 +24,14 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IHtmlContent BodyContent { get; set; }
|
public IHtmlContent BodyContent { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool IsLayoutBeingRendered { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Layout { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Path { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IDictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; }
|
public IDictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IDictionary<string, RenderAsyncDelegate> SectionWriters { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="PageContext"/>.
|
/// The <see cref="PageContext"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PageContext PageContext { get; set; }
|
public PageContext PageContext { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ViewContext ViewContext { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a <see cref="System.Diagnostics.DiagnosticSource"/> instance used to instrument the page execution.
|
/// Gets or sets a <see cref="System.Diagnostics.DiagnosticSource"/> instance used to instrument the page execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -61,7 +43,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
/// handles non-<see cref="IHtmlContent"/> C# expressions.
|
/// handles non-<see cref="IHtmlContent"/> C# expressions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RazorInject]
|
[RazorInject]
|
||||||
public HtmlEncoder HtmlEncoder { get; set; }
|
public HtmlEncoder HtmlEncoder
|
||||||
|
{
|
||||||
|
get { return Encoder; }
|
||||||
|
set { Encoder = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public PageArgumentBinder Binder
|
public PageArgumentBinder Binder
|
||||||
{
|
{
|
||||||
|
|
@ -86,10 +72,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HtmlEncoder Encoder => HtmlEncoder;
|
|
||||||
|
|
||||||
protected override TextWriter Writer => ViewContext.Writer;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void EnsureRenderedBodyOrSections()
|
public void EnsureRenderedBodyOrSections()
|
||||||
{
|
{
|
||||||
|
|
@ -131,26 +113,5 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Href(string contentPath)
|
|
||||||
{
|
|
||||||
if (contentPath == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(contentPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_urlHelper == null)
|
|
||||||
{
|
|
||||||
var services = ViewContext.HttpContext.RequestServices;
|
|
||||||
var factory = services.GetRequiredService<IUrlHelperFactory>();
|
|
||||||
_urlHelper = factory.GetUrlHelper(ViewContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _urlHelper.Content(contentPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void DefineSection(string name, RenderAsyncDelegate section)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue