Join us this Friday for AI in Action at the Virtual Happy Hour! This free virtual event is open to all—enroll now on Academy and don’t miss out.

 

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.