Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for DisplayModes for all .Net based templates and functions #4

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
33 changes: 33 additions & 0 deletions Composite/AspNet/DisplayModesFileResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.IO;
using System.Web;
using System.Web.Hosting;
using System.Web.WebPages;

namespace Composite.AspNet
{
/// <exclude />
public static class DisplayModesFileResolver
{
/// <exclude />
public static string ResolveFileInInDirectory(string directory, string file, string extension, HttpContextBase context)
{
var pathProvider = HostingEnvironment.VirtualPathProvider;
var modes = DisplayModeProvider.Instance.GetAvailableDisplayModesForContext(context, null);

foreach (var mode in modes)
{
var specialFile = Path.Combine(directory, $"{file}{extension}");

var displayInfo = mode.GetDisplayInfo(context, specialFile, pathProvider.FileExists);
if (displayInfo != null)
{
return displayInfo.FilePath;
}
}

file = Path.Combine(directory, file + extension);

return pathProvider.FileExists(file) ? file : null;
}
}
}
10 changes: 9 additions & 1 deletion Composite/AspNet/Razor/RazorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
//using System.Web.Instrumentation;
using System.Web.WebPages;
using System.Xml;
using System.Xml.Linq;
//using Composite.Core.Extensions;
//using Composite.Core.IO;
using Composite.Core.Types;
Expand Down Expand Up @@ -38,6 +37,15 @@ public static object ExecuteRazorPage(
WebPageBase webPage = null;
try
{
var currentContext = HttpContext.Current;
if (currentContext != null)
{
var directory = Path.GetDirectoryName(virtualPath);
var function = Path.GetFileNameWithoutExtension(virtualPath);

virtualPath = DisplayModesFileResolver.ResolveFileInInDirectory(directory, function, ".cshtml", new HttpContextWrapper(currentContext));
}

webPage = WebPageBase.CreateInstanceFromVirtualPath(virtualPath);

return ExecuteRazorPage(webPage, setParameters, resultType, functionContextContainer);
Expand Down
1 change: 1 addition & 0 deletions Composite/Composite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
<Compile Include="C1Console\Trees\SortDirection.cs" />
<Compile Include="Core\Application\ServiceLocator.cs" />
<Compile Include="Core\Application\Job.cs" />
<Compile Include="AspNet\DisplayModesFileResolver.cs" />
<Compile Include="Core\Caching\FileRelatedDataCache.cs" />
<Compile Include="Core\Extensions\StackTraceExtensionMethods.cs" />
<Compile Include="Core\Instrumentation\LogExecutionTime.cs" />
Expand Down
2 changes: 1 addition & 1 deletion Composite/Core/PageTemplates/TemplateDefinitionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static DescriptorType BuildPageTemplateDescriptor<DescriptorType>(IPageTe
/// <param name="pageContentToRender">The page rendering job.</param>
/// <param name="placeholderProperties">The placeholder properties.</param>
/// <param name="functionContextContainer">The function context container, if not null, nested functions fill be evaluated.</param>
public static void BindPlaceholders(IPageTemplate template,
public static void BindPlaceholders(object template,
PageContentToRender pageContentToRender,
IDictionary<string, PropertyInfo> placeholderProperties,
FunctionContextContainer functionContextContainer)
Expand Down
6 changes: 3 additions & 3 deletions Composite/Core/WebClient/ApplicationLevelEventHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public static void Application_Start(object sender, EventArgs e)

SystemSetupFacade.SetFirstTimeStart();

InitializeServices();

if (!SystemSetupFacade.IsSystemFirstTimeInitialized)
{
return;
Expand All @@ -67,12 +69,10 @@ public static void Application_Start(object sender, EventArgs e)
{
throw new InvalidOperationException("Windows limitation problem detected! You have installed the website at a place where the total path length of the file with the longest filename exceeds the maximum allowed in Windows. See http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#paths");
}


AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload;

InitializeServices();

lock (_syncRoot)
{
if (_systemIsInitialized) return;
Expand Down
44 changes: 32 additions & 12 deletions Composite/Core/WebClient/Renderings/RenderingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.WebPages;
using System.Xml.Linq;
using Composite.C1Console.Security;
using Composite.Core.Extensions;
Expand All @@ -20,10 +21,10 @@ namespace Composite.Core.WebClient.Renderings
/// Rendering context
/// </summary>
/// <exclude />
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public sealed class RenderingContext: IDisposable
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public sealed class RenderingContext : IDisposable
{
private static readonly string LogTitle = typeof (RenderingContext).Name;
private static readonly string LogTitle = typeof(RenderingContext).Name;

/// <summary>
/// Indicates whether performance profiling is enabled.
Expand Down Expand Up @@ -193,11 +194,11 @@ public string BuildProfilerReport()

private void InitializeFromHttpContextInternal()
{
HttpContext httpContext = HttpContext.Current;
var httpContext = new HttpContextWrapper(HttpContext.Current);
var request = httpContext.Request;
var response = httpContext.Response;

ProfilingEnabled = request.Url.OriginalString.Contains("c1mode=perf");
ProfilingEnabled = request.Url.OriginalString.Contains("c1mode=perf");
if (ProfilingEnabled)
{
if (!UserValidationFacade.IsLoggedIn())
Expand All @@ -220,17 +221,17 @@ private void InitializeFromHttpContextInternal()
Page = (IPage)HttpRuntime.Cache.Get(_previewKey + "_SelectedPage");
C1PageRoute.PageUrlData = new PageUrlData(Page);

PageRenderer.RenderingReason = (RenderingReason) HttpRuntime.Cache.Get(_previewKey + "_RenderingReason");
PageRenderer.RenderingReason = (RenderingReason)HttpRuntime.Cache.Get(_previewKey + "_RenderingReason");
}
else
{
PageUrlData pageUrl = C1PageRoute.PageUrlData ?? PageUrls.UrlProvider.ParseInternalUrl(request.Url.OriginalString);
PageUrlData pageUrl = C1PageRoute.PageUrlData ?? PageUrls.UrlProvider.ParseInternalUrl(request.Url.OriginalString);
Page = pageUrl.GetPage();

_cachedUrl = request.Url.PathAndQuery;

PageRenderer.RenderingReason = new UrlSpace(httpContext).ForceRelativeUrls
? RenderingReason.C1ConsoleBrowserPageView
PageRenderer.RenderingReason = new UrlSpace(httpContext).ForceRelativeUrls
? RenderingReason.C1ConsoleBrowserPageView
: RenderingReason.PageView;
}

Expand All @@ -257,12 +258,31 @@ private void InitializeFromHttpContextInternal()
Verify.IsNotNull(httpContext.Handler, "HttpHandler isn't defined");

var aspnetPage = (System.Web.UI.Page)httpContext.Handler;


OverrideDisplayMode(httpContext);

var pageRenderer = PageTemplateFacade.BuildPageRenderer(Page.TemplateId);
pageRenderer.AttachToPage(aspnetPage, pageRenderingJob);
}

private void ValidateViewUnpublishedRequest(HttpContext httpContext)
private static void OverrideDisplayMode(HttpContextBase httpContext)
{
var displayMode = httpContext.Request.QueryString["c1displaymode"];
if (!String.IsNullOrEmpty(displayMode))
{
if (displayMode.Equals("mobile", StringComparison.OrdinalIgnoreCase))
{
httpContext.SetOverriddenBrowser(BrowserOverride.Mobile);
}

if (displayMode.Equals("desktop", StringComparison.OrdinalIgnoreCase))
{
httpContext.SetOverriddenBrowser(BrowserOverride.Desktop);
}
}
}

private void ValidateViewUnpublishedRequest(HttpContextBase httpContext)
{
bool isPreviewingUrl = httpContext.Request.Url.OriginalString.Contains(DefaultPageUrlProvider.UrlMarker_RelativeUrl);
bool isUnpublishedPage = Page != null && Page.DataSourceId.PublicationScope != PublicationScope.Published;
Expand Down Expand Up @@ -306,7 +326,7 @@ public bool PreRenderRedirectCheck()

return false;
}

private static string GetLoginRedirectUrl(string url)
{
return UrlUtils.PublicRootPath + "/Composite/Login.aspx?ReturnUrl=" +
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.UI;
using Composite.AspNet;
Expand Down Expand Up @@ -52,7 +53,11 @@ public override object Execute(Composite.Functions.ParameterList parameters,
Page currentPage = httpContext.Handler as Page;
Verify.IsNotNull(currentPage, "The Current HttpContext Handler must be a " + typeof (Page).FullName);

var userControl = currentPage.LoadControl(VirtualPath);
var directory = Path.GetDirectoryName(VirtualPath);
var function = Path.GetFileNameWithoutExtension(VirtualPath);
var virtualPath = DisplayModesFileResolver.ResolveFileInInDirectory(directory, function, ".ascx", new HttpContextWrapper(httpContext));

var userControl = currentPage.LoadControl(virtualPath);


foreach (var param in parameters.AllParameterNames)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using System.Linq;
using System.Web;
using Composite.AspNet;
using Composite.C1Console.Security;
using Composite.Core.Collections.Generic;
using Composite.Core.Extensions;
Expand All @@ -11,10 +13,9 @@
using Composite.Core.Xml;
using Composite.Data.Types;


namespace Composite.Plugins.PageTemplates.MasterPages
{
internal class MasterPagePageRenderer: IPageRenderer
internal class MasterPagePageRenderer : IPageRenderer
{
private static readonly string PageRenderingJob_Key = "MasterPages.PageRenderingJob";

Expand All @@ -41,21 +42,25 @@ public void AttachToPage(Page aspnetPage, PageContentToRender contentToRender)
Guid templateId = contentToRender.Page.TemplateId;
var rendering = _renderingInfo[templateId];

if(rendering == null)
if (rendering == null)
{
Exception loadingException = _loadingExceptions[templateId];
if(loadingException != null)
if (loadingException != null)
{
throw loadingException;
}

Verify.ThrowInvalidOperationException("Failed to get master page by template ID '{0}'. Check for compilation errors".FormatWith(templateId));
}

aspnetPage.MasterPageFile = rendering.VirtualPath;
var dir = Path.GetDirectoryName(rendering.VirtualPath);
var template = Path.GetFileNameWithoutExtension(rendering.VirtualPath);
var file = DisplayModesFileResolver.ResolveFileInInDirectory(dir, template, ".master", new HttpContextWrapper(HttpContext.Current));

aspnetPage.MasterPageFile = file;
aspnetPage.PreRender += (e, args) => PageOnPreRender(aspnetPage, contentToRender.Page);

var master = aspnetPage.Master as MasterPagePageTemplate;
var master = aspnetPage.Master;
TemplateDefinitionHelper.BindPlaceholders(master, contentToRender, rendering.PlaceholderProperties, null);
}

Expand All @@ -76,7 +81,7 @@ private void PageOnPreRender(Page aspnetPage, IPage page)
{
string xml = string.Join(string.Empty, xhtmlDocument.Head.Nodes().Select(node => node.ToString()));

aspnetPage.Header.Controls.Add(new Literal {Text = xml});
aspnetPage.Header.Controls.Add(new Literal { Text = xml });
}
}
}
Expand Down
31 changes: 20 additions & 11 deletions Composite/Plugins/PageTemplates/Razor/RazorPageRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Web.UI;
using System.Web.WebPages;
using System.Xml.Linq;
using Composite.AspNet;
using Composite.AspNet.Razor;
using Composite.Core.Collections.Generic;
using Composite.Core.Extensions;
Expand Down Expand Up @@ -58,26 +59,33 @@ private void RendererPage(object sender, EventArgs e)
string output;
FunctionContextContainer functionContextContainer;

RazorPageTemplate webPage = null;
WebPageBase webPage = null;
try
{
webPage = WebPageBase.CreateInstanceFromVirtualPath(renderingInfo.ControlVirtualPath) as AspNet.Razor.RazorPageTemplate;
Verify.IsNotNull(webPage, "Razor compilation failed or base type does not inherit '{0}'",
typeof (AspNet.Razor.RazorPageTemplate).FullName);
var directory = Path.GetDirectoryName(renderingInfo.ControlVirtualPath);
var template = Path.GetFileNameWithoutExtension(renderingInfo.ControlVirtualPath);
var file = DisplayModesFileResolver.ResolveFileInInDirectory(directory, template, ".cshtml", new HttpContextWrapper(HttpContext.Current));

webPage.Configure();
webPage = WebPageBase.CreateInstanceFromVirtualPath(file);

var razorTemplate = webPage as RazorPageTemplate;
if (razorTemplate != null)
{
razorTemplate.Configure();
}

Verify.IsNotNull(webPage, "Razor compilation failed or base type does not inherit '{0}'", typeof(RazorPageTemplate).FullName);

functionContextContainer = PageRenderer.GetPageRenderFunctionContextContainer();

using (Profiler.Measure("Evaluating placeholders"))
{
TemplateDefinitionHelper.BindPlaceholders(webPage, _job, renderingInfo.PlaceholderProperties,
functionContextContainer);
TemplateDefinitionHelper.BindPlaceholders(webPage, _job, renderingInfo.PlaceholderProperties, functionContextContainer);
}

// Executing razor code
var httpContext = new HttpContextWrapper(HttpContext.Current);
var startPage = StartPage.GetStartPage(webPage, "_PageStart", new[] {"cshtml"});
var startPage = StartPage.GetStartPage(webPage, "_PageStart", new[] { "cshtml" });
var pageContext = new WebPageContext(httpContext, webPage, startPage);
pageContext.PageData.Add(RazorHelper.PageContext_FunctionContextContainer, functionContextContainer);

Expand All @@ -94,14 +102,15 @@ private void RendererPage(object sender, EventArgs e)
}
finally
{
if (webPage != null)
var razorTemplate = webPage as RazorPageTemplate;
if (razorTemplate != null)
{
webPage.Dispose();
razorTemplate.Dispose();
}
}

XDocument resultDocument = XDocument.Parse(output);

var controlMapper = (IXElementToControlMapper)functionContextContainer.XEmbedableMapper;
Control control = PageRenderer.Render(resultDocument, functionContextContainer, controlMapper, _job.Page);

Expand Down