/// <summary> /// Renders a template to the specified <paramref name="textWriter"/> /// </summary> /// <param name="templatePage">Instance of a template</param> /// <param name="model">Template model</param> /// <param name="modelType">Type of the model</param> /// <param name="viewBag">Dynamic viewBag of the page</param> /// <param name="textWriter">Output</param> public async Task RenderTemplateAsync( ITemplatePage templatePage, object model, Type modelType, TextWriter textWriter, ExpandoObject viewBag = null) { if (textWriter == null) { throw new ArgumentNullException(nameof(textWriter)); } var pageContext = new PageContext(viewBag) { ExecutingPageKey = templatePage.Key, Writer = textWriter }; if (model != null) { pageContext.ModelTypeInfo = new ModelTypeInfo(modelType); object pageModel = pageContext.ModelTypeInfo.CreateTemplateModel(model); templatePage.SetModel(pageModel); } templatePage.PageContext = pageContext; using (var renderer = new TemplateRenderer(templatePage, this, HtmlEncoder.Default)) { await renderer.RenderAsync().ConfigureAwait(false); } }
private void SetModelContext <T>( ITemplatePage templatePage, TextWriter textWriter, T model, ExpandoObject viewBag) { if (textWriter == null) { throw new ArgumentNullException(nameof(textWriter)); } var pageContext = new PageContext(viewBag) { ExecutingPageKey = templatePage.Key, Writer = textWriter }; if (model != null) { pageContext.ModelTypeInfo = new ModelTypeInfo(model.GetType()); object pageModel = pageContext.ModelTypeInfo.CreateTemplateModel(model); templatePage.SetModel(pageModel); pageContext.Model = pageModel; } templatePage.PageContext = pageContext; }
public async Task <string> RenderTemplateAsync <T>(ITemplatePage templatePage, T model, IPageContext context) { TkDebug.AssertArgumentNull(templatePage, nameof(templatePage), this); TkDebug.AssertArgumentNull(context, nameof(context), this); templatePage.SetModel(model); context.Convert <PageContext>().Model = model; using (var writer = new StringWriter()) using (var scope = new MemoryPoolViewBufferScope()) { var oldWriter = context.Writer; try { context.Writer = writer; var renderer = new TemplateRenderer(this, HtmlEncoder.Default, scope); await renderer.RenderAsync(templatePage).ConfigureAwait(false); return(writer.ToString()); } finally { context.Writer = oldWriter; } } }
/// <summary> /// Includes the template with the specified key /// </summary> /// <param name="key">Key used to resolve a template</param> /// <param name="model">Template model</param> public async Task IncludeAsync(string key, object model = null) { if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException(nameof(key)); } if (this.PageLookup == null) { throw new RazorLightException("Can't locate a page as PageLookup is not set"); } PageLookupResult pageResult = PageLookup.GetPage(key); if (pageResult.Success) { ITemplatePage page = pageResult.ViewEntry.PageFactory(); page.PageContext = new PageContext(this.PageContext.ViewBag) { Writer = this.PageContext.Writer }; if (model != null) { var modelTypeInfo = new ModelTypeInfo(model.GetType()); page.PageContext.ModelTypeInfo = modelTypeInfo; object pageModel = modelTypeInfo.CreateTemplateModel(model); page.SetModel(pageModel); } await page.ExecuteAsync(); } }
/// <summary> /// Runs a template, renders a Layout pages and sections. /// </summary> /// <param name="page">Page to run</param> /// <param name="model">Mode of the page</param> public string RunTemplate(ITemplatePage page, object model) { object pageModel = page.PageContext.ModelTypeInfo.CreateTemplateModel(model); page.SetModel(pageModel); page.Path = page.PageContext.ExecutingFilePath; using (var writer = new StringWriter()) { page.PageContext.Writer = writer; using (var renderer = new PageRenderer(page, pageLookup)) { renderer.ViewStartPages.AddRange(page.PageContext.ViewStartPages); renderer.PreRenderCallbacks.AddRange(Configuration.PreRenderCallbacks); renderer.RenderAsync(page.PageContext).GetAwaiter().GetResult(); return(writer.ToString()); } } }
private void SetModelContext <T>(ITemplatePage templatePage, TextWriter textWriter, T model, object initData, ExpandoObject viewBag) { var pageContext = new PageContext(viewBag, initData) { ExecutingPageKey = templatePage.Key, Writer = textWriter }; if (model != null) { pageContext.ModelTypeInfo = new ModelTypeInfo(model.GetType()); object pageModel = pageContext.ModelTypeInfo.CreateTemplateModel(model); templatePage.SetModel(pageModel); pageContext.Model = pageModel; } templatePage.PageContext = pageContext; }
private async Task RenderLayoutAsync( ITemplatePage page, PageContext context, 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 previousPage = page; var renderedLayouts = new List <ITemplatePage>(); // 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. throw new InvalidOperationException("Layout can not be rendered"); } ITemplatePage layoutPage = await _engineHandler.CompileTemplateAsync(previousPage.Layout).ConfigureAwait(false); layoutPage.SetModel(context.Model); if (renderedLayouts.Count > 0 && renderedLayouts.Any(l => string.Equals(l.Key, layoutPage.Key, StringComparison.Ordinal))) { // If the layout has been previously rendered as part of this view, we're potentially in a layout // rendering cycle. throw new InvalidOperationException($"Layout {layoutPage.Key} has circular reference"); } // 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 RenderPageAsync(layoutPage, context, invokeViewStarts : false).ConfigureAwait(false); 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 = context.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(context.Writer)) { await bodyWriter.Buffer.WriteToAsync(writer, _htmlEncoder).ConfigureAwait(false); } } else { // This means we're writing to another buffer. Use MoveTo to combine them. bodyWriter.Buffer.MoveTo(viewBufferTextWriter.Buffer); } } }