2013-01-18 13:13:06 -01:00
using System ;
using System.Linq ;
using System.Threading ;
using System.Globalization ;
using System.IO ;
using Umbraco.Core ;
using Umbraco.Core.IO ;
using Umbraco.Core.Logging ;
2013-03-01 13:56:12 -01:00
using UmbracoSettings = Umbraco . Core . Configuration . UmbracoSettings ;
using Umbraco.Web.Configuration ;
2013-01-18 13:13:06 -01:00
using umbraco ;
using umbraco.cms.businesslogic.web ;
using umbraco.cms.businesslogic.language ;
using umbraco.cms.businesslogic.member ;
namespace Umbraco.Web.Routing
{
internal class PublishedContentRequestEngine
{
2013-02-28 20:20:40 -01:00
private readonly PublishedContentRequest _pcr ;
private readonly RoutingContext _routingContext ;
2013-01-18 13:13:06 -01:00
/// <summary>
/// Initializes a new instance of the <see cref="PublishedContentRequestEngine"/> class with a content request.
/// </summary>
/// <param name="pcr">The content request.</param>
public PublishedContentRequestEngine ( PublishedContentRequest pcr )
{
_pcr = pcr ;
_routingContext = pcr . RoutingContext ;
var umbracoContext = _routingContext . UmbracoContext ;
if ( _routingContext = = null ) throw new ArgumentException ( "pcr.RoutingContext is null." ) ;
if ( umbracoContext = = null ) throw new ArgumentException ( "pcr.RoutingContext.UmbracoContext is null." ) ;
if ( umbracoContext . RoutingContext ! = _routingContext ) throw new ArgumentException ( "RoutingContext confusion." ) ;
// no! not set yet.
//if (umbracoContext.PublishedContentRequest != _pcr) throw new ArgumentException("PublishedContentRequest confusion.");
}
#region Public
/// <summary>
/// Prepares the request.
/// </summary>
public void PrepareRequest ( )
{
// note - at that point the original legacy module did something do handle IIS custom 404 errors
// ie pages looking like /anything.aspx?404;/path/to/document - I guess the reason was to support
// "directory urls" without having to do wildcard mapping to ASP.NET on old IIS. This is a pain
// to maintain and probably not used anymore - removed as of 06/2012. @zpqrtbnk.
//
// to trigger Umbraco's not-found, one should configure IIS and/or ASP.NET custom 404 errors
// so that they point to a non-existing page eg /redirect-404.aspx
// TODO: SD: We need more information on this for when we release 4.10.0 as I'm not sure what this means.
//find domain
FindDomain ( ) ;
// if request has been flagged to redirect then return
// whoever called us is in charge of actually redirecting
if ( _pcr . IsRedirect )
return ;
// set the culture on the thread - once, so it's set when running document lookups
Thread . CurrentThread . CurrentUICulture = Thread . CurrentThread . CurrentCulture = _pcr . Culture ;
// find the document & template
FindPublishedContentAndTemplate ( ) ;
// set the culture on the thread -- again, 'cos it might have changed due to a wildcard domain
Thread . CurrentThread . CurrentUICulture = Thread . CurrentThread . CurrentCulture = _pcr . Culture ;
// trigger the Prepared event - at that point it is still possible to change about anything
2013-02-26 16:52:42 -01:00
// even though the request might be flagged for redirection - we'll redirect _after_ the event
2013-01-18 13:13:06 -01:00
_pcr . OnPrepared ( ) ;
2013-01-24 08:51:27 -01:00
// we don't take care of anything xcept finding the rendering engine again
// so if the content has changed, it's up to the user to find out the template
// set the culture on the thread -- again, 'cos it might have changed in the event handler
2013-01-18 13:13:06 -01:00
Thread . CurrentThread . CurrentUICulture = Thread . CurrentThread . CurrentCulture = _pcr . Culture ;
// if request has been flagged to redirect then return
// whoever called us is in charge of actually redirecting
if ( _pcr . IsRedirect )
return ;
// safety
if ( ! _pcr . HasPublishedContent )
_pcr . Is404 = true ;
// handle 404 : return
// whoever called us is in charge of doing what's appropriate
if ( _pcr . Is404 )
return ;
// can't go beyond that point without a PublishedContent to render
// it's ok not to have a template, in order to give MVC a chance to hijack routes
// assign the legacy page back to the docrequest
// handlers like default.aspx will want it and most macros currently need it
_pcr . UmbracoPage = new page ( _pcr ) ;
// these two are used by many legacy objects
2013-01-23 14:08:17 -01:00
_routingContext . UmbracoContext . HttpContext . Items [ "pageID" ] = _pcr . PublishedContent . Id ;
2013-01-18 13:13:06 -01:00
_routingContext . UmbracoContext . HttpContext . Items [ "pageElements" ] = _pcr . UmbracoPage . Elements ;
}
/// <summary>
/// Updates the request when there is no template to render the content.
/// </summary>
/// <remarks>This is called from Mvc when there's a document to render but no template.</remarks>
public void UpdateRequestOnMissingTemplate ( )
{
// clear content
var content = _pcr . PublishedContent ;
_pcr . PublishedContent = null ;
HandlePublishedContent ( ) ; // will go 404
FindTemplate ( ) ;
// if request has been flagged to redirect then return
// whoever called us is in charge of redirecting
if ( _pcr . IsRedirect )
return ;
if ( ! _pcr . HasPublishedContent )
{
// means the engine could not find a proper document to handle 404
// restore the saved content so we know it exists
_pcr . PublishedContent = content ;
return ;
}
if ( ! _pcr . HasTemplate )
{
// means we may have a document, but we have no template
// at that point there isn't much we can do and there is no point returning
// to Mvc since Mvc can't do much either
return ;
}
// assign the legacy page back to the docrequest
// handlers like default.aspx will want it and most macros currently need it
_pcr . UmbracoPage = new page ( _pcr ) ;
// these two are used by many legacy objects
2013-01-23 14:08:17 -01:00
_routingContext . UmbracoContext . HttpContext . Items [ "pageID" ] = _pcr . PublishedContent . Id ;
2013-01-18 13:13:06 -01:00
_routingContext . UmbracoContext . HttpContext . Items [ "pageElements" ] = _pcr . UmbracoPage . Elements ;
}
#endregion
#region Domain
/// <summary>
/// Finds the site root (if any) matching the http request, and updates the PublishedContentRequest accordingly.
/// </summary>
/// <returns>A value indicating whether a domain was found.</returns>
internal bool FindDomain ( )
{
const string tracePrefix = "FindDomain: " ;
// note - we are not handling schemes nor ports here.
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Uri=\"{1}\"" , ( ) = > tracePrefix , ( ) = > _pcr . Uri ) ;
// try to find a domain matching the current request
2013-03-12 15:16:12 -01:00
var domainAndUri = DomainHelper . DomainForUri ( DomainHelper . GetAllDomains ( false ) , _pcr . Uri ) ;
2013-01-18 13:13:06 -01:00
// handle domain
if ( domainAndUri ! = null )
{
// matching an existing domain
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Matches domain=\"{1}\", rootId={2}, culture=\"{3}\"" ,
( ) = > tracePrefix ,
( ) = > domainAndUri . Domain . Name ,
( ) = > domainAndUri . Domain . RootNodeId ,
( ) = > domainAndUri . Domain . Language . CultureAlias ) ;
_pcr . Domain = domainAndUri . Domain ;
_pcr . DomainUri = domainAndUri . Uri ;
_pcr . Culture = new CultureInfo ( domainAndUri . Domain . Language . CultureAlias ) ;
// canonical? not implemented at the moment
// if (...)
// {
// _pcr.RedirectUrl = "...";
// return true;
// }
}
else
{
// not matching any existing domain
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Matches no domain" , ( ) = > tracePrefix ) ;
var defaultLanguage = Language . GetAllAsList ( ) . FirstOrDefault ( ) ;
_pcr . Culture = defaultLanguage = = null ? CultureInfo . CurrentUICulture : new CultureInfo ( defaultLanguage . CultureAlias ) ;
}
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Culture=\"{1}\"" , ( ) = > tracePrefix , ( ) = > _pcr . Culture . Name ) ;
return _pcr . Domain ! = null ;
}
/// <summary>
/// Looks for wildcard domains in the path and updates <c>Culture</c> accordingly.
/// </summary>
2013-02-20 08:12:48 -01:00
internal void HandleWildcardDomains ( )
2013-01-18 13:13:06 -01:00
{
const string tracePrefix = "HandleWildcardDomains: " ;
if ( ! _pcr . HasPublishedContent )
return ;
var nodePath = _pcr . PublishedContent . Path ;
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Path=\"{1}\"" , ( ) = > tracePrefix , ( ) = > nodePath ) ;
var rootNodeId = _pcr . HasDomain ? _pcr . Domain . RootNodeId : ( int? ) null ;
2013-03-12 15:16:12 -01:00
var domain = DomainHelper . FindWildcardDomainInPath ( DomainHelper . GetAllDomains ( true ) , nodePath , rootNodeId ) ;
2013-01-18 13:13:06 -01:00
if ( domain ! = null )
{
_pcr . Culture = new CultureInfo ( domain . Language . CultureAlias ) ;
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Got domain on node {1}, set culture to \"{2}\"." , ( ) = > tracePrefix ,
( ) = > domain . RootNodeId , ( ) = > _pcr . Culture . Name ) ;
}
else
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}No match." , ( ) = > tracePrefix ) ;
}
}
#endregion
#region Rendering engine
2013-01-23 14:08:15 -01:00
/// <summary>
/// Finds the rendering engine to use to render a template specified by its alias.
/// </summary>
/// <param name="alias">The alias of the template.</param>
/// <returns>The rendering engine, or Unknown if the template was not found.</returns>
internal RenderingEngine FindTemplateRenderingEngine ( string alias )
{
if ( string . IsNullOrWhiteSpace ( alias ) )
return RenderingEngine . Unknown ;
alias = alias . Replace ( '\\' , '/' ) ; // forward slashes only
// NOTE: we could start with what's the current default?
if ( FindTemplateRenderingEngineInDirectory ( new DirectoryInfo ( IOHelper . MapPath ( SystemDirectories . MvcViews ) ) ,
alias , new [ ] { ".cshtml" , ".vbhtml" } ) )
return RenderingEngine . Mvc ;
if ( FindTemplateRenderingEngineInDirectory ( new DirectoryInfo ( IOHelper . MapPath ( SystemDirectories . Masterpages ) ) ,
alias , new [ ] { ".master" } ) )
return RenderingEngine . WebForms ;
return RenderingEngine . Unknown ;
}
internal bool FindTemplateRenderingEngineInDirectory ( DirectoryInfo directory , string alias , string [ ] extensions )
{
if ( directory = = null | | ! directory . Exists )
return false ;
var pos = alias . IndexOf ( '/' ) ;
if ( pos > 0 )
{
// recurse
var subdir = directory . GetDirectories ( alias . Substring ( 0 , pos ) ) . FirstOrDefault ( ) ;
alias = alias . Substring ( pos + 1 ) ;
2013-02-19 06:37:25 -01:00
return subdir ! = null & & FindTemplateRenderingEngineInDirectory ( subdir , alias , extensions ) ;
2013-01-23 14:08:15 -01:00
}
2013-02-19 06:37:25 -01:00
// look here
return directory . GetFiles ( ) . Any ( f = > extensions . Any ( e = > f . Name . InvariantEquals ( alias + e ) ) ) ;
2013-01-23 14:08:15 -01:00
}
2013-01-18 13:13:06 -01:00
#endregion
#region Document and template
2013-02-19 06:37:25 -01:00
/// <summary>
/// Finds the Umbraco document (if any) matching the request, and updates the PublishedContentRequest accordingly.
/// </summary>
/// <returns>A value indicating whether a document and template were found.</returns>
private void FindPublishedContentAndTemplate ( )
2013-01-18 13:13:06 -01:00
{
const string tracePrefix = "FindPublishedContentAndTemplate: " ;
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Path=\"{1}\"" , ( ) = > tracePrefix , ( ) = > _pcr . Uri . AbsolutePath ) ;
// run the document finders
FindPublishedContent ( ) ;
2013-02-26 16:52:42 -01:00
// if request has been flagged to redirect then return
// whoever called us is in charge of actually redirecting
// -- do not process anything any further --
if ( _pcr . IsRedirect )
2013-02-19 06:37:25 -01:00
return ;
2013-02-26 16:52:42 -01:00
2013-01-18 13:13:06 -01:00
// not handling umbracoRedirect here but after LookupDocument2
// so internal redirect, 404, etc has precedence over redirect
// handle not-found, redirects, access...
HandlePublishedContent ( ) ;
// find a template
FindTemplate ( ) ;
// handle umbracoRedirect
FollowExternalRedirect ( ) ;
// handle wildcard domains
HandleWildcardDomains ( ) ;
}
2013-02-19 06:37:25 -01:00
/// <summary>
/// Tries to find the document matching the request, by running the IPublishedContentFinder instances.
/// </summary>
/// <exception cref="InvalidOperationException">There is no finder collection.</exception>
internal void FindPublishedContent ( )
2013-01-18 13:13:06 -01:00
{
const string tracePrefix = "FindPublishedContent: " ;
// look for the document
// the first successful finder, if any, will set this.PublishedContent, and may also set this.Template
// some finders may implement caching
using ( DisposableTimer . DebugDuration < PluginManager > (
( ) = > string . Format ( "{0}Begin finders" , tracePrefix ) ,
( ) = > string . Format ( "{0}End finders, {1}" , tracePrefix , ( _pcr . HasPublishedContent ? "a document was found" : "no document was found" ) ) ) )
{
2013-02-19 06:37:25 -01:00
if ( _routingContext . PublishedContentFinders = = null )
throw new InvalidOperationException ( "There is no finder collection." ) ;
_routingContext . PublishedContentFinders . Any ( finder = > finder . TryFindDocument ( _pcr ) ) ;
2013-01-18 13:13:06 -01:00
}
2013-02-19 06:37:25 -01:00
// indicate that the published content (if any) we have at the moment is the
2013-01-18 13:13:06 -01:00
// one that was found by the standard finders before anything else took place.
2013-02-28 20:20:40 -01:00
_pcr . SetIsInitialPublishedContent ( ) ;
2013-01-18 13:13:06 -01:00
}
/// <summary>
/// Handles the published content (if any).
/// </summary>
/// <remarks>
/// Handles "not found", internal redirects, access validation...
/// things that must be handled in one place because they can create loops
/// </remarks>
private void HandlePublishedContent ( )
{
const string tracePrefix = "HandlePublishedContent: " ;
// because these might loop, we have to have some sort of infinite loop detection
int i = 0 , j = 0 ;
const int maxLoop = 8 ;
do
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}{1}" , ( ) = > tracePrefix , ( ) = > ( i = = 0 ? "Begin" : "Loop" ) ) ;
// handle not found
if ( ! _pcr . HasPublishedContent )
{
_pcr . Is404 = true ;
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}No document, try last chance lookup" , ( ) = > tracePrefix ) ;
// if it fails then give up, there isn't much more that we can do
var lastChance = _routingContext . PublishedContentLastChanceFinder ;
if ( lastChance = = null | | ! lastChance . TryFindDocument ( _pcr ) )
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Failed to find a document, give up" , ( ) = > tracePrefix ) ;
break ;
}
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Found a document" , ( ) = > tracePrefix ) ;
}
// follow internal redirects as long as it's not running out of control ie infinite loop of some sort
j = 0 ;
2013-02-28 20:20:40 -01:00
while ( FollowInternalRedirects ( ) & & j + + < maxLoop )
{ }
if ( j = = maxLoop ) // we're running out of control
2013-01-18 13:13:06 -01:00
break ;
// ensure access
if ( _pcr . HasPublishedContent )
EnsurePublishedContentAccess ( ) ;
// loop while we don't have page, ie the redirect or access
// got us to nowhere and now we need to run the notFoundLookup again
// as long as it's not running out of control ie infinite loop of some sort
} while ( ! _pcr . HasPublishedContent & & i + + < maxLoop ) ;
if ( i = = maxLoop | | j = = maxLoop )
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Looks like we're running into an infinite loop, abort" , ( ) = > tracePrefix ) ;
_pcr . PublishedContent = null ;
}
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}End" , ( ) = > tracePrefix ) ;
}
/// <summary>
/// Follows internal redirections through the <c>umbracoInternalRedirectId</c> document property.
/// </summary>
/// <returns>A value indicating whether redirection took place and led to a new published document.</returns>
/// <remarks>
/// <para>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</para>
/// <para>As per legacy, if the redirect does not work, we just ignore it.</para>
/// </remarks>
private bool FollowInternalRedirects ( )
{
const string tracePrefix = "FollowInternalRedirects: " ;
if ( _pcr . PublishedContent = = null )
throw new InvalidOperationException ( "There is no PublishedContent." ) ;
bool redirect = false ;
2013-03-18 17:55:02 +00:00
var internalRedirect = _pcr . PublishedContent . GetPropertyValue < string > ( Constants . Conventions . Content . InternalRedirectId ) ;
2013-01-18 13:13:06 -01:00
if ( ! string . IsNullOrWhiteSpace ( internalRedirect ) )
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Found umbracoInternalRedirectId={1}" , ( ) = > tracePrefix , ( ) = > internalRedirect ) ;
int internalRedirectId ;
if ( ! int . TryParse ( internalRedirect , out internalRedirectId ) )
internalRedirectId = - 1 ;
if ( internalRedirectId < = 0 )
{
// bad redirect - log and display the current page (legacy behavior)
//_pcr.Document = null; // no! that would be to force a 404
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Failed to redirect to id={1}: invalid value" , ( ) = > tracePrefix , ( ) = > internalRedirect ) ;
}
2013-01-23 14:08:17 -01:00
else if ( internalRedirectId = = _pcr . PublishedContent . Id )
2013-01-18 13:13:06 -01:00
{
// redirect to self
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Redirecting to self, ignore" , ( ) = > tracePrefix ) ;
}
else
{
// redirect to another page
2013-03-19 17:51:55 -01:00
var node = _routingContext . UmbracoContext . ContentCache . GetById ( internalRedirectId ) ;
2013-01-18 13:13:06 -01:00
2013-03-01 13:56:12 -01:00
_pcr . SetInternalRedirectPublishedContent ( node ) ; // don't use .PublishedContent here
2013-02-28 20:20:40 -01:00
if ( node ! = null )
2013-01-18 13:13:06 -01:00
{
redirect = true ;
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Redirecting to id={1}" , ( ) = > tracePrefix , ( ) = > internalRedirectId ) ;
}
else
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Failed to redirect to id={1}: no such published document" , ( ) = > tracePrefix , ( ) = > internalRedirectId ) ;
}
}
}
return redirect ;
}
/// <summary>
/// Ensures that access to current node is permitted.
/// </summary>
/// <remarks>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</remarks>
private void EnsurePublishedContentAccess ( )
{
const string tracePrefix = "EnsurePublishedContentAccess: " ;
if ( _pcr . PublishedContent = = null )
throw new InvalidOperationException ( "There is no PublishedContent." ) ;
var path = _pcr . PublishedContent . Path ;
2013-01-23 14:08:17 -01:00
if ( Access . IsProtected ( _pcr . PublishedContent . Id , path ) )
2013-01-18 13:13:06 -01:00
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Page is protected, check for access" , ( ) = > tracePrefix ) ;
System . Web . Security . MembershipUser user = null ;
try
{
user = System . Web . Security . Membership . GetUser ( ) ;
}
catch ( ArgumentException )
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Membership.GetUser returned ArgumentException" , ( ) = > tracePrefix ) ;
}
if ( user = = null | | ! Member . IsLoggedOn ( ) )
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Not logged in, redirect to login page" , ( ) = > tracePrefix ) ;
var loginPageId = Access . GetLoginPage ( path ) ;
2013-01-23 14:08:17 -01:00
if ( loginPageId ! = _pcr . PublishedContent . Id )
2013-03-19 17:51:55 -01:00
_pcr . PublishedContent = _routingContext . UmbracoContext . ContentCache . GetById ( loginPageId ) ;
2013-01-18 13:13:06 -01:00
}
2013-01-23 14:08:17 -01:00
else if ( ! Access . HasAccces ( _pcr . PublishedContent . Id , user . ProviderUserKey ) )
2013-01-18 13:13:06 -01:00
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Current member has not access, redirect to error page" , ( ) = > tracePrefix ) ;
var errorPageId = Access . GetErrorPage ( path ) ;
2013-01-23 14:08:17 -01:00
if ( errorPageId ! = _pcr . PublishedContent . Id )
2013-03-19 17:51:55 -01:00
_pcr . PublishedContent = _routingContext . UmbracoContext . ContentCache . GetById ( errorPageId ) ;
2013-01-18 13:13:06 -01:00
}
else
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Current member has access" , ( ) = > tracePrefix ) ;
}
}
else
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Page is not protected" , ( ) = > tracePrefix ) ;
}
}
/// <summary>
2013-01-23 14:08:14 -01:00
/// Finds a template for the current node, if any.
2013-01-18 13:13:06 -01:00
/// </summary>
private void FindTemplate ( )
{
// NOTE: at the moment there is only 1 way to find a template, and then ppl must
// use the Prepared event to change the template if they wish. Should we also
// implement an ITemplateFinder logic?
const string tracePrefix = "FindTemplate: " ;
2013-01-23 14:08:14 -01:00
if ( _pcr . PublishedContent = = null )
{
2013-01-24 08:51:27 -01:00
_pcr . TemplateModel = null ;
2013-01-23 14:08:14 -01:00
return ;
}
2013-01-18 13:13:06 -01:00
// read the alternate template alias, from querystring, form, cookie or server vars,
// only if the published content is the initial once, else the alternate template
// does not apply
2013-03-01 13:56:12 -01:00
// + optionnally, apply the alternate template on internal redirects
var useAltTemplate = _pcr . IsInitialPublishedContent
| | ( UmbracoSettings . For < WebRouting > ( ) . InternalRedirectPreservesTemplate & & _pcr . IsInternalRedirectPublishedContent ) ;
string altTemplate = useAltTemplate
2013-03-18 17:55:02 +00:00
? _routingContext . UmbracoContext . HttpContext . Request [ Constants . Conventions . Url . AltTemplate ]
2013-01-18 13:13:06 -01:00
: null ;
if ( string . IsNullOrWhiteSpace ( altTemplate ) )
{
// we don't have an alternate template specified. use the current one if there's one already,
// which can happen if a content lookup also set the template (LookupByNiceUrlAndTemplate...),
// else lookup the template id on the document then lookup the template with that id.
if ( _pcr . HasTemplate )
{
LogHelper . Debug < PublishedContentRequest > ( "{0}Has a template already, and no alternate template." , ( ) = > tracePrefix ) ;
return ;
}
// TODO: When we remove the need for a database for templates, then this id should be irrelavent,
// not sure how were going to do this nicely.
var templateId = _pcr . PublishedContent . TemplateId ;
if ( templateId > 0 )
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Look for template id={1}" , ( ) = > tracePrefix , ( ) = > templateId ) ;
2013-01-28 18:36:58 -01:00
var template = ApplicationContext . Current . Services . FileService . GetTemplate ( templateId ) ;
2013-01-18 13:13:06 -01:00
if ( template = = null )
throw new InvalidOperationException ( "The template with Id " + templateId + " does not exist, the page cannot render" ) ;
2013-01-24 08:51:27 -01:00
_pcr . TemplateModel = template ;
2013-01-18 13:13:06 -01:00
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Got template id={1} alias=\"{2}\"" , ( ) = > tracePrefix , ( ) = > template . Id , ( ) = > template . Alias ) ;
}
else
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}No specified template." , ( ) = > tracePrefix ) ;
}
}
else
{
// we have an alternate template specified. lookup the template with that alias
// this means the we override any template that a content lookup might have set
// so /path/to/page/template1?altTemplate=template2 will use template2
// ignore if the alias does not match - just trace
if ( _pcr . HasTemplate )
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Has a template already, but also an alternate template." , ( ) = > tracePrefix ) ;
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Look for alternate template alias=\"{1}\"" , ( ) = > tracePrefix , ( ) = > altTemplate ) ;
2013-01-28 18:36:58 -01:00
var template = ApplicationContext . Current . Services . FileService . GetTemplate ( altTemplate ) ;
2013-01-18 13:13:06 -01:00
if ( template ! = null )
{
2013-01-24 08:51:27 -01:00
_pcr . TemplateModel = template ;
2013-01-18 13:13:06 -01:00
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Got template id={1} alias=\"{2}\"" , ( ) = > tracePrefix , ( ) = > template . Id , ( ) = > template . Alias ) ;
}
else
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}The template with alias=\"{1}\" does not exist, ignoring." , ( ) = > tracePrefix , ( ) = > altTemplate ) ;
}
}
if ( ! _pcr . HasTemplate )
{
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}No template was found." , ( ) = > tracePrefix ) ;
// initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true
// then reset _pcr.Document to null to force a 404.
//
// but: because we want to let MVC hijack routes even though no template is defined, we decide that
// a missing template is OK but the request will then be forwarded to MVC, which will need to take
// care of everything.
//
// so, don't set _pcr.Document to null here
}
else
{
2013-01-24 08:51:27 -01:00
LogHelper . Debug < PublishedContentRequestEngine > ( "{0}Running with template id={1} alias=\"{2}\"" , ( ) = > tracePrefix , ( ) = > _pcr . TemplateModel . Id , ( ) = > _pcr . TemplateModel . Alias ) ;
2013-01-18 13:13:06 -01:00
}
}
/// <summary>
/// Follows external redirection through <c>umbracoRedirect</c> document property.
/// </summary>
/// <remarks>As per legacy, if the redirect does not work, we just ignore it.</remarks>
private void FollowExternalRedirect ( )
{
2013-02-26 16:52:42 -01:00
if ( ! _pcr . HasPublishedContent ) return ;
2013-03-18 17:55:02 +00:00
var redirectId = _pcr . PublishedContent . GetPropertyValue ( Constants . Conventions . Content . Redirect , - 1 ) ;
2013-02-26 16:52:42 -01:00
var redirectUrl = "#" ;
if ( redirectId > 0 )
2013-01-31 10:06:25 -01:00
redirectUrl = _routingContext . UrlProvider . GetUrl ( redirectId ) ;
2013-02-26 16:52:42 -01:00
if ( redirectUrl ! = "#" )
_pcr . SetRedirect ( redirectUrl ) ;
2013-01-18 13:13:06 -01:00
}
#endregion
}
}