/// <inheritdoc /> public void Activate(IRazorPage page, ViewContext context) { if (page == null) { throw new ArgumentNullException(nameof(page)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } if (page is Page) { return; } var activationInfo = _activationInfo.GetOrAdd(page.GetType(), CreateViewActivationInfo); context.ViewData = CreateViewDataDictionary(context, activationInfo); for (var i = 0; i < activationInfo.PropertyActivators.Length; i++) { var activateInfo = activationInfo.PropertyActivators[i]; activateInfo.Activate(page, context); } }
/// <inheritdoc /> public void Activate(IRazorPage page, ViewContext context) { if (page == null) { throw new ArgumentNullException(nameof(page)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } var pageType = page.GetType(); RazorPagePropertyActivator propertyActivator; if (!_activationInfo.TryGetValue(pageType, out propertyActivator)) { // Look for a property named "Model". If it is non-null, we'll assume this is // the equivalent of TModel Model property on RazorPage<TModel>. // // Otherwise if we don't have a model property the activator will just skip setting // the view data. var modelType = pageType.GetRuntimeProperty(ModelPropertyName)?.PropertyType; propertyActivator = new RazorPagePropertyActivator( pageType, modelType, _metadataProvider, _propertyAccessors); propertyActivator = _activationInfo.GetOrAdd(pageType, propertyActivator); } propertyActivator.Activate(page, context); }
async Task <ViewBufferTextWriter> RenderPageAsync(IViewBufferScope bufferScope, IRazorPage page, ViewRenderingContext viewRenderingContext) { var writer = viewRenderingContext.Writer as ViewBufferTextWriter; if (writer == null) { // If we get here, this is likely the top-level page (not a partial) - this means // that context.Writer is wrapping the output stream. We need to buffer, so create a buffered writer. var buffer = new ViewBuffer(bufferScope, page.GetType().AssemblyQualifiedName, ViewBuffer.ViewPageSize); writer = new ViewBufferTextWriter(buffer, viewRenderingContext.Writer.Encoding, this.htmlEncoder, viewRenderingContext.Writer); } else { // This means we're writing something like a partial, where the output needs to be buffered. // Create a new buffer, but without the ability to flush. var buffer = new ViewBuffer(bufferScope, page.GetType().AssemblyQualifiedName, ViewBuffer.ViewPageSize); writer = new ViewBufferTextWriter(buffer, viewRenderingContext.Writer.Encoding); } // The writer for the body is passed through the ViewContext, allowing things like HtmlHelpers // and ViewComponents to reference it. var oldWriter = viewRenderingContext.Writer; //var oldFilePath = context.ExecutingFilePath; viewRenderingContext.Writer = writer; //context.ExecutingFilePath = page.Path; try { page.RenderingContext = viewRenderingContext; await page.ExecuteAsync(); return(writer); } finally { viewRenderingContext.Writer = oldWriter; //context.ExecutingFilePath = oldFilePath; } }
/// <inheritdoc /> public void Activate([NotNull] IRazorPage page, [NotNull] ViewContext context) { var activationInfo = _activationInfo.GetOrAdd(page.GetType(), CreateViewActivationInfo); context.ViewData = CreateViewDataDictionary(context, activationInfo); for (var i = 0; i < activationInfo.PropertyActivators.Length; i++) { var activateInfo = activationInfo.PropertyActivators[i]; activateInfo.Activate(page, context); } }
public void Activate(IRazorPage page, ViewContext context) { var view = context.View; this.DefaultActivator.Activate(page, context); if (!(page is RazorPageAdapter)) { var componentHelper = (IViewComponentHelper)page.GetType().GetProperty("Component").GetValue(page); // Maybe we should add the page type information. to get back extactly the helper for the desired page. this.HttpContextAccessor.HttpContext.Items[nameof(CoreExtensions.ViewComponentHelper)] = componentHelper; this.HttpContextAccessor.HttpContext.Items[nameof(CoreExtensions.RazorPage)] = page; } }
internal RazorPagePropertyActivator GetOrAddCacheEntry(IRazorPage page) { var pageType = page.GetType(); Type?providedModelType = null; if (page is IModelTypeProvider modelTypeProvider) { providedModelType = modelTypeProvider.GetModelType(); } // We only need to vary by providedModelType since it varies at runtime. Defined model type // is synonymous with the pageType and consequently does not need to be accounted for in the cache key. var cacheKey = new CacheKey(pageType, providedModelType); if (!_activationInfo.TryGetValue(cacheKey, out var propertyActivator)) { // Look for a property named "Model". If it is non-null, we'll assume this is // the equivalent of TModel Model property on RazorPage<TModel>. // // Otherwise if we don't have a model property the activator will just skip setting // the view data. var modelType = providedModelType; if (modelType == null) { modelType = pageType.GetRuntimeProperty(ModelPropertyName)?.PropertyType; } propertyActivator = new RazorPagePropertyActivator( pageType, modelType, _metadataProvider, _propertyAccessors); propertyActivator = _activationInfo.GetOrAdd(cacheKey, propertyActivator); } return(propertyActivator); }
/// <inheritdoc /> public void Activate(IRazorPage page, ViewContext context) { if (page == null) { throw new ArgumentNullException(nameof(page)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } var activationInfo = _activationInfo.GetOrAdd(page.GetType(), CreateViewActivationInfo); context.ViewData = CreateViewDataDictionary(context, activationInfo); for (var i = 0; i < activationInfo.PropertyActivators.Length; i++) { var activateInfo = activationInfo.PropertyActivators[i]; activateInfo.Activate(page, context); } }
async Task RenderLayoutAsync(IViewBufferScope bufferScope, IRazorPage previousPage, ViewResult viewResult, ViewRenderingContext viewRenderingContext, ViewBufferTextWriter bodyWriter) { // A layout page can specify another layout page. We'll need to continue // looking for layout pages until they're no longer specified. var renderedLayouts = new List <IRazorPage>(); // This loop will execute Layout pages from the inside to the outside. With each // iteration, bodyWriter is replaced with the aggregate of all the "body" content // (including the layout page we just rendered). while (!string.IsNullOrEmpty(previousPage.Layout)) { if (!bodyWriter.IsBuffering) { // Once a call to RazorPage.FlushAsync is made, we can no longer render Layout pages - content has // already been written to the client and the layout content would be appended rather than surround // the body content. Throwing this exception wouldn't return a 500 (since content has already been // written), but a diagnostic component should be able to capture it. var message = "Resources.FormatLayoutCannotBeRendered(Path, nameof(New.RazorPage.FlushAsync))"; throw new InvalidOperationException(message); } var layoutPage = this.GetLayoutPage(viewResult, previousPage.PipelineContext, previousPage.Layout); if (renderedLayouts.Count > 0 && renderedLayouts.Any(l => l.GetType() == layoutPage.GetType())) { // If the layout has been previously rendered as part of this view, we're potentially in a layout // rendering cycle. throw new InvalidOperationException("Layout has circular reference. Previous Page: `" + previousPage.GetType() + "`, Current Layout: `" + layoutPage.GetType() + "`"); } // Notify the previous page that any writes that are performed on it are part of sections being written // in the layout. previousPage.IsLayoutBeingRendered = true; layoutPage.PreviousSectionWriters = previousPage.SectionWriters; layoutPage.BodyContent = bodyWriter.Buffer; bodyWriter = await this.RenderPageAsync(bufferScope, layoutPage, viewRenderingContext); renderedLayouts.Add(layoutPage); previousPage = layoutPage; } // Now we've reached and rendered the outer-most layout page. Nothing left to execute. // Ensure all defined sections were rendered or RenderBody was invoked for page without defined sections. foreach (var layoutPage in renderedLayouts) { layoutPage.EnsureRenderedBodyOrSections(); } if (bodyWriter.IsBuffering) { // If IsBuffering - then we've got a bunch of content in the view buffer. How to best deal with it // really depends on whether or not we're writing directly to the output or if we're writing to // another buffer. var viewBufferTextWriter = viewRenderingContext.Writer as ViewBufferTextWriter; if (viewBufferTextWriter == null || !viewBufferTextWriter.IsBuffering) { // This means we're writing to a 'real' writer, probably to the actual output stream. // We're using PagedBufferedTextWriter here to 'smooth' synchronous writes of IHtmlContent values. using (var writer = bufferScope.CreateWriter(viewRenderingContext.Writer)) await bodyWriter.Buffer.WriteToAsync(writer, this.htmlEncoder); } else { // This means we're writing to another buffer. Use MoveTo to combine them. bodyWriter.Buffer.MoveTo(viewBufferTextWriter.Buffer); } } }