コード例 #1
0
        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());
        }
コード例 #2
0
    public static RazorViewExecutionResult ExecuteTemplate(WebViewPage <T> viewPage, T model, HttpContextBase httpContext)
    {
        var result = new RazorViewExecutionResult();

        // Warning: lots of mocking below

        // mock HTTP state objects
        var context = new Mock <HttpContextBase>();

        context.Setup(x => x.Items).Returns(new Dictionary <object, object>());
        var response = new Mock <HttpResponseBase>();

        response.Setup(x => x.ApplyAppPathModifier(It.IsAny <string>()))
        .Returns(new Func <string, string>(x => x));
        context.Setup(x => x.Response).Returns(response.Object);
        var request = new Mock <HttpRequestBase>();

        context.Setup(x => x.Request).Returns(request.Object);
        request.Setup(x => x.ApplicationPath).Returns("/");
        request.Setup(x => x.IsLocal).Returns(true);
        var requestRouteContext = new RequestContext(context.Object, new RouteData());
        // mock page view context
        var view = new Mock <ViewContext>();

        view.Setup(x => x.HttpContext).Returns(context.Object);
        var viewMock = new Mock <IView>();

        view.Setup(x => x.View).Returns(viewMock.Object);
        view.Setup(x => x.TempData).Returns(new TempDataDictionary());
        view.Setup(x => x.ViewData).Returns(new ViewDataDictionary <T>(model));
        var viewDataContainer = new Mock <IViewDataContainer>();

        // mock view data used by the page
        viewDataContainer.Setup(c => c.ViewData).Returns(new ViewDataDictionary <T>(model));
        // mock html helper
        var html      = new Mock <HtmlHelper <T> >(view.Object, viewDataContainer.Object);
        var urlHelper = new Mock <UrlHelper>(requestRouteContext);
        // mock viewengine (for partial views fake resolution)
        var viewEngine = new Mock <IViewEngine>();

        viewEngine.Setup(x => x.FindPartialView(
                             It.IsAny <ControllerContext>(),
                             It.IsAny <string>(),
                             It.IsAny <bool>()))
        .Returns(new ViewEngineResult(viewMock.Object, viewEngine.Object));
        using (var tw = new StringWriter())
            using (var twNull = new StringWriter()) // this writer is used to discard unnecessary results
            {
                view.Setup(x => x.Writer).Returns(tw);

                // inject mocked context
                viewPage.Context = httpContext;

                var pageContext = new WebPageContext(context: context.Object, page: null, model: null);
                viewPage.ViewContext = view.Object;
                if (model != null)
                {
                    viewPage.ViewData = new ViewDataDictionary <T>(model);
                }

                viewPage.Html = html.Object;
                viewPage.Url  = urlHelper.Object;

                // insert mocked viewEngine for fake partial views resolution
                ViewEngines.Engines.Clear();
                ViewEngines.Engines.Add(viewEngine.Object);

                // prepare view for execution, discard all generated results
                viewPage.PushContext(pageContext, twNull);
                viewPage.ExecutePageHierarchy(pageContext, twNull);
                // inject textwriter
                viewPage.OutputStack.Push(tw);
                // execute compiled page
                viewPage.Execute();

                // find all sections and render them too
                var dynMethod = pageContext.GetType().GetProperty("SectionWritersStack", BindingFlags.NonPublic | BindingFlags.Instance);
                var res       = (Stack <Dictionary <string, SectionWriter> >)dynMethod.GetValue(pageContext, null);
                foreach (var section in res.Peek())
                {
                    section.Value();
                    result.SectionNames.Add(section.Key);
                }

                result.Text = tw.ToString();
                return(result);
            }
    }