In Umbraco 7.0.3 I:
I then have a Surface Controller
that I call with some AJAX
to display the page (more specifically the Body property of the page):
public class JsController : SurfaceController
{
public ActionResult GetPage(int id)
{
var page = new Node(id);
if (page == null || page.GetProperty("body") == null)
return Content(@"Hmm, something went wrong. Unable to find what you're looking for.");
return Content(page.GetProperty("body").Value);
}
}
This setup almost works but the problem is that instead of the rendered form, what is returned is:
<!--?UMBRACO_MACRO macroAlias="ContactForm" /-->
So now I need to render this macro\form\partial view...I think that I probably need to do it in the Controller, but if I can do it on the other side (via Javascript) that would work as well. Is there an Umbraco function I can call in the controller to render a macro based on the page id and macro alias?
So after spending several hours fuming at how painfully stupid the Umbraco
team made this process, reading threads like this and this, I finally figured out a fairly ugly, but working way...things would have been so much more simple if the PublishedContentRequest
class constructor was not internal
!
Anyways, here's what I had to do:
1) Extend EnsurePublishedContentRequestAttribute
public class CreatePublishedContentRequestAttribute
: EnsurePublishedContentRequestAttribute
{
public CreatePublishedContentRequestAttribute() : base(0) { }
protected override void ConfigurePublishedContentRequest(
PublishedContentRequest publishedContentRequest,
ActionExecutedContext filterContext)
{
var contentId = filterContext.RouteData.Values["id"];
int id = 0;
if (contentId != null && int.TryParse(contentId.ToString(), out id))
{
var content = UmbracoContext.ContentCache.GetById(id);
publishedContentRequest.PublishedContent = content;
var defaultLanguage = Language.GetAllAsList().FirstOrDefault();
publishedContentRequest.Culture = (defaultLanguage == null)
? CultureInfo.CurrentUICulture
: new CultureInfo(defaultLanguage.CultureAlias);
publishedContentRequest.ConfigureRequest();
HttpContext.Current.Session["PublishedContentRequest"]
= publishedContentRequest;
}
}
}
2) Redirect to an action decorated with this attribute that redirects back to my GetPage action and retrieve the PCR
from the Session
. Now we can render our macro:
public ActionResult GetPage(int id)
{
var publishedContent = UmbracoContext.ContentCache.GetById(id);
if (publishedContent == null || publishedContent.GetProperty("body") == null)
{ return Content(@"Unable to find what you're looking for."); }
if (UmbracoContext.PublishedContentRequest == null
&& Session["PublishedContentRequest"] == null)
{ return RedirectToAction("CreatePublishedContentRequest", new { id }); }
UmbracoContext.PublishedContentRequest =
(PublishedContentRequest) Session["PublishedContentRequest"];
Session["PublishedContentRequest"] = null;
UmbracoContext.HttpContext.Items["pageID"] = id;
return Content(GetHtmlContent(publishedContent));
}
[CreatePublishedContentRequest]
public ActionResult CreatePublishedContentRequest(int id)
{
return RedirectToAction("GetPage", new { id });
}
private string GetHtmlContent(IPublishedContent publishedContent)
{
string content = publishedContent.GetProperty("body").Value.ToString();
if (string.IsNullOrEmpty(content) || !content.Contains("UMBRACO_MACRO"))
{ return content;}
int startIndex = content.IndexOf("macroAlias=") + 12;
int length = content.LastIndexOf('"') - startIndex;
var macroAlias = content.Substring(startIndex, length);
return (Umbraco.RenderMacro(macroAlias) ?? new HtmlString("")).ToString();
}
This works, but this is some pretty hacky stuff. If the Umbraco
team made the PublishedContentRequest
constructor public
, this could have been much, much cleaner. Of course, there's probably a better way to do this, if so, I'm all ears.