public static string Render <TModel>(this WebViewPage <TModel> view, HttpContextBase httpContext, TModel model = default(TModel)) { var writer = new StringWriter(); view.ViewData.Model = model; view.Initialize(httpContext, writer); var webPageContext = new WebPageContext(view.ViewContext.HttpContext, page: null, model: null); // Using private reflection to access some internals // Note: ideally we would not have to do this, but WebPages is just not mockable enough :( var dynamicPageContext = webPageContext.AsDynamic(); dynamicPageContext.OutputStack.Push(writer); // Push some section writer dictionary onto the stack. We need two, because the logic in WebPageBase.RenderBody // checks that as a way to make sure the layout page is not called directly var sectionWriters = new Dictionary <string, SectionWriter>(StringComparer.OrdinalIgnoreCase); dynamicPageContext.SectionWritersStack.Push(sectionWriters); dynamicPageContext.SectionWritersStack.Push(sectionWriters); // Set the body delegate to do nothing dynamicPageContext.BodyAction = (Action <TextWriter>)(w => { }); view.AsDynamic().PageContext = webPageContext; view.Execute(); return(writer.ToString()); }
public static string Render(this WebViewPage view, HttpContextBase httpContext, object model = null) { StringWriter writer = new StringWriter(); view.Initialize(httpContext, writer); view.ViewData.Model = model; WebPageContext webPageContext = new WebPageContext(view.ViewContext.HttpContext, null, model); // Using private reflection to access some internals // Also make sure the use the same writer used for initializing the ViewContext in the OutputStack // Note: ideally we would not have to do this, but WebPages is just not mockable enough :( // Add the writer to the output stack PropertyInfo outputStackProp = typeof(WebPageContext).GetProperty("OutputStack", BindingFlags.Instance | BindingFlags.NonPublic); Stack <TextWriter> outputStack = (Stack <TextWriter>)outputStackProp.GetValue(webPageContext, null); outputStack.Push(writer); // Push some section writer dictionary onto the stack. We need two, because the logic in WebPageBase.RenderBody // checks that as a way to make sure the layout page is not called directly PropertyInfo sectionWritersStackProp = typeof(WebPageContext).GetProperty("SectionWritersStack", BindingFlags.Instance | BindingFlags.NonPublic); Stack <Dictionary <string, SectionWriter> > sectionWritersStack = (Stack <Dictionary <string, SectionWriter> >)sectionWritersStackProp.GetValue(webPageContext, null); Dictionary <string, SectionWriter> sectionWriters = new Dictionary <string, SectionWriter>(StringComparer.OrdinalIgnoreCase); sectionWritersStack.Push(sectionWriters); sectionWritersStack.Push(sectionWriters); // Set the body delegate to do nothing PropertyInfo bodyActionProp = typeof(WebPageContext).GetProperty("BodyAction", BindingFlags.Instance | BindingFlags.NonPublic); bodyActionProp.SetValue(webPageContext, (Action <TextWriter>)(w => { }), null); // Set the page context on the view (the property is public, but the setter is internal) PropertyInfo pageContextProp = typeof(WebPageRenderingBase).GetProperty("PageContext", BindingFlags.Instance | BindingFlags.Public); pageContextProp.SetValue(view, webPageContext, BindingFlags.NonPublic, null, null, null); // Execute/render the view view.Execute(); return(writer.ToString()); }