示例#1
0
        /// <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);
            }
        }
示例#2
0
        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;
        }
示例#3
0
        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;
                    }
                }
        }
示例#4
0
        /// <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();
            }
        }
示例#5
0
        /// <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());
                }
            }
        }
示例#6
0
        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;
        }
示例#7
0
        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);
                }
            }
        }