November Happy Hour will be moved to Thursday December 5th.

Render view to string

Vote:
 

I want to render a view to a string, given a PageReference. So I need to:

1) Find the controller associated with the page type

2) Get an instance to the controller with correct controller context (node and language)

3) Render the view as a string

How can I achieve this?

#121897
May 20, 2015 10:02
Vote:
 

The lazy way

var relativUrl = EPiServer.Web.Routing.UrlResolver.Current.GetUrl(pageReference, null, new EPiServer.Web.Routing.VirtualPathArguments { ContextMode = EPiServer.Web.ContextMode.Default });
var url = new Uri(UriSupport.SiteUrl, relativUrl);
var htmlStr = string.Empty;
using (var client = new WebClient()) {
	htmlStr = client.DownloadString(url);
}



#121931
May 20, 2015 17:22
Vote:
 

It depends a little on what MVC version you are using, there are a lot of questions like this on stackoverflow

MVC5
http://stackoverflow.com/questions/23494741/mvc-5-render-view-to-string

MVC2

http://stackoverflow.com/questions/483091/render-a-view-as-a-string

Here it is a little more explained

http://www.codemag.com/Article/1312081

#121932
May 20, 2015 20:58
Vote:
 

Thanks guys, I have found out how to render the view thanks to stack but I still need answer on how to get the controller from a page reference, and to get the context right of that controller.

#121942
May 21, 2015 10:49
Vote:
 

Hi Johan!

About gettting the controller, I think you should be able to go along these lines.

            var myRef = currentPage.ContentLink;
            var httpContext = default(HttpContextBase);
            var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
            var typeRepo = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
            var templateRepo = ServiceLocator.Current.GetInstance<TemplateResolver>();

            var content = contentLoader.Get<IContent>(myRef);
            var type = typeRepo.Load(content.ContentTypeID);
            var template = templateRepo.Resolve(httpContext, type, TemplateTypeCategories.MvcController);
            var controllerName = template.Name.EndsWith("Controller", StringComparison.InvariantCultureIgnoreCase)
                ? template.Name.Substring(0, template.Name.LastIndexOf("Controller", StringComparison.InvariantCultureIgnoreCase))
                : template.Name;

Depending on how you're running it the context part could be tricky though..

Cheers,
//Patrick

#121968
May 22, 2015 11:37
Vote:
 

I wrote something to render EPiServer pages as a child action. :

    using System.Globalization;
    using System.IO;
    using System.Web.Routing;
    using EPiServer.Core;
    using EPiServer.Web;
    using EPiServer.Web.Routing;

    public class MvcPageDataRenderer 
    {
        private readonly TemplateResolver templateResolver;

        public MvcPageDataRenderer(TemplateResolver templateResolver)
        {
            this.templateResolver = templateResolver;
        }

        public string ExecuteChildRequest(RequestContext existingRequestContext, PageData pageToRender, string preferredLanguageToRender)
        {
            var templateModel = this.templateResolver.ResolveMvcTemplate(existingRequestContext.HttpContext, pageToRender);

            existingRequestContext.SetController(templateModel.TemplateType.Name.Replace("Controller", string.Empty));
            existingRequestContext.SetControllerType(templateModel.TemplateType);
            existingRequestContext.SetContentLink(pageToRender.ContentLink);
            existingRequestContext.SetRoutedData(pageToRender);
            existingRequestContext.SetContextMode(ContextMode.Default);

            existingRequestContext.RouteData.Values["action"] = "Index";
            existingRequestContext.RouteData.DataTokens["namespaces"] = new[] { templateModel.TemplateType.Namespace };

            if (!string.IsNullOrWhiteSpace(preferredLanguageToRender))
            {
                existingRequestContext.SetLanguage(preferredLanguageToRender);
                EPiServer.BaseLibrary.Context.Current["EPiServer:ContentLanguage"] = new CultureInfo(preferredLanguageToRender);
            }

            var handler = new ChildActionHandler(existingRequestContext);

            using (var stringWriter = new StringWriter(CultureInfo.CurrentCulture))
            {
                existingRequestContext.HttpContext.Server.Execute(handler, stringWriter, true);
                return stringWriter.ToString();
            }
        }
    }

    using System;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using System.Web.UI;

    /// <summary>
    /// Shamelessly "inspired" by classes in System.Web.Mvc assembly
    /// It appears that only a System.Web.UI.Page can be executed
    /// as a child request. If you try to execute an MvcHandler
    /// directly an exception (with no detail) is thrown
    /// </summary>
    internal class ChildActionHandler : Page, IHttpAsyncHandler
    {
        internal class ChildActionMvcHandler : MvcHandler
        {
            public ChildActionMvcHandler(RequestContext context)
                : base(context)
            {
            }

            protected override void AddVersionHeader(HttpContextBase httpContext)
            {
            }
        }
        
        private readonly ChildActionMvcHandler mvcHandler;

        public ChildActionHandler(RequestContext context)
        {
            this.mvcHandler = new ChildActionMvcHandler(context);
        }

        public override void ProcessRequest(HttpContext context)
        {
            ((IHttpHandler)this.mvcHandler).ProcessRequest(context);
        }

        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            return ((IHttpAsyncHandler)this.mvcHandler).BeginProcessRequest(context, cb, extraData);
        }

        public void EndProcessRequest(IAsyncResult result)
        {
            ((IHttpAsyncHandler)this.mvcHandler).EndProcessRequest(result);
        }
    }
#122213
Edited, May 28, 2015 12:04
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.