diff --git a/src/Orchard/Mvc/Html/LayoutHelperExtensions.cs b/src/Orchard/Mvc/Html/LayoutHelperExtensions.cs
new file mode 100644
index 000000000..41b58f685
--- /dev/null
+++ b/src/Orchard/Mvc/Html/LayoutHelperExtensions.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Web.Mvc;
+using Orchard.Mvc.ViewEngines;
+
+namespace Orchard.Mvc.Html {
+ public static class LayoutHelperExtensions {
+ public static void RenderBody(this HtmlHelper html) {
+ var layoutContext = OrchardLayoutContext.From(html.ViewContext);
+ html.ViewContext.HttpContext.Response.Output.Write(layoutContext.BodyContent);
+ }
+ }
+}
diff --git a/src/Orchard/Mvc/ViewEngines/LayoutView.cs b/src/Orchard/Mvc/ViewEngines/LayoutView.cs
new file mode 100644
index 000000000..c2ec77bd0
--- /dev/null
+++ b/src/Orchard/Mvc/ViewEngines/LayoutView.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Web.Mvc;
+
+namespace Orchard.Mvc.ViewEngines {
+ public class LayoutView : IView {
+ private IView[] _views;
+
+ public LayoutView(IEnumerable views) {
+ _views = views.ToArray();
+ }
+
+ public void Render(ViewContext viewContext, TextWriter writer) {
+
+ var orchardViewContext = OrchardLayoutContext.From(viewContext);
+
+ for (var index = 0; index != _views.Length; ++index)
+ {
+ var view = _views[index];
+ if (index == _views.Length - 1) {
+ view.Render(viewContext, writer);
+ }
+ else {
+ //TEMP: to be replaced with an efficient spooling writer
+ var childWriter = new StringWriter();
+ view.Render(viewContext, childWriter);
+ orchardViewContext.BodyContent = childWriter.ToString();
+ }
+ }
+ }
+ }
+}
diff --git a/src/Orchard/Mvc/ViewEngines/LayoutViewEngine.cs b/src/Orchard/Mvc/ViewEngines/LayoutViewEngine.cs
new file mode 100644
index 000000000..7fd8325cf
--- /dev/null
+++ b/src/Orchard/Mvc/ViewEngines/LayoutViewEngine.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web.Mvc;
+
+namespace Orchard.Mvc.ViewEngines {
+ public class LayoutViewEngine : IViewEngine {
+ private readonly ViewEngineCollection _viewEngines;
+
+ public LayoutViewEngine(ViewEngineCollection viewEngines) {
+ _viewEngines = viewEngines;
+ }
+
+ public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) {
+ return new ViewEngineResult(Enumerable.Empty());
+ }
+
+ public ViewEngineResult FindView(
+ ControllerContext controllerContext,
+ string viewName,
+ string masterName,
+ bool useCache) {
+
+ // TODO: is there an optimization around useCache for
+ // this implementation? since IView can't re-execute, maybe not...
+
+ // if action returned a View with explicit master -
+ // this will bypass the multi-pass layout strategy
+ if (!string.IsNullOrEmpty(masterName))
+ return new ViewEngineResult(Enumerable.Empty());
+
+ var bodyView = _viewEngines.FindPartialView(controllerContext, viewName);
+ var layoutView = _viewEngines.FindPartialView(controllerContext, "layout");
+ var documentView = _viewEngines.FindPartialView(controllerContext, "document");
+
+ if (bodyView.View == null ||
+ layoutView.View == null ||
+ documentView.View == null) {
+
+ return new ViewEngineResult(
+ (bodyView.SearchedLocations ?? Enumerable.Empty())
+ .Concat((layoutView.SearchedLocations ?? Enumerable.Empty()))
+ .Concat((documentView.SearchedLocations ?? Enumerable.Empty()))
+ );
+ }
+
+ var view = new LayoutView(new[] {
+ bodyView.View,
+ layoutView.View,
+ documentView.View,
+ });
+
+ return new ViewEngineResult(view, this);
+ }
+
+ public void ReleaseView(ControllerContext controllerContext, IView view) {
+
+ }
+ }
+
+
+}
diff --git a/src/Orchard/Mvc/ViewEngines/OrchardLayoutContext.cs b/src/Orchard/Mvc/ViewEngines/OrchardLayoutContext.cs
new file mode 100644
index 000000000..c7e31c904
--- /dev/null
+++ b/src/Orchard/Mvc/ViewEngines/OrchardLayoutContext.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Web;
+using System.Web.Mvc;
+
+namespace Orchard.Mvc.ViewEngines {
+ public class OrchardLayoutContext {
+ private static readonly object _key = typeof(OrchardLayoutContext);
+
+ public string BodyContent { get; set; }
+
+ public static OrchardLayoutContext From(ControllerContext context) {
+ return From(context.HttpContext);
+ }
+
+ public static OrchardLayoutContext From(HttpContextBase context) {
+ if (context.Items.Contains(_key)) {
+ context.Items.Add(_key, new OrchardLayoutContext());
+ }
+ return (OrchardLayoutContext)context.Items[_key];
+ }
+ }
+}
diff --git a/src/Orchard/Orchard.csproj b/src/Orchard/Orchard.csproj
index 361cfd95c..41200465c 100644
--- a/src/Orchard/Orchard.csproj
+++ b/src/Orchard/Orchard.csproj
@@ -200,6 +200,7 @@
+
@@ -213,6 +214,9 @@
+
+
+