Fixed issue: #U4-1726

This commit is contained in:
Floris Robbemont
2013-02-16 16:00:28 -01:00
parent e921dca9d6
commit 55f06a7ca6
7 changed files with 142 additions and 46 deletions

View File

@@ -1,3 +1,4 @@
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
@@ -13,5 +14,13 @@ namespace Umbraco.Web.Mvc
/// <returns><c>true</c> if this instance can handle the specified request; otherwise, <c>false</c>.</returns>
/// <remarks></remarks>
bool CanHandle(RequestContext request);
/// <summary>
/// Returns the controller type for the controller name otherwise null if not found
/// </summary>
/// <param name="requestContext"></param>
/// <param name="controllerName"></param>
/// <returns></returns>
Type GetControllerType(RequestContext requestContext, string controllerName);
}
}

View File

@@ -45,6 +45,23 @@ namespace Umbraco.Web.Mvc
: base.CreateController(requestContext, controllerName);
}
/// <summary>
/// Retrieves the controller type for the specified name and request context.
/// </summary>
///
/// <returns>
/// The controller type.
/// </returns>
/// <param name="requestContext">The context of the HTTP request, which includes the HTTP context and route data.</param>
/// <param name="controllerName">The name of the controller.</param>
internal Type GetControllerTypeInternal(RequestContext requestContext, string controllerName)
{
var factory = _slaveFactories.Factories.FirstOrDefault(x => x.CanHandle(requestContext));
return factory != null
? factory.GetControllerType(requestContext, controllerName)
: base.GetControllerType(requestContext, controllerName);
}
/// <summary>
/// Releases the specified controller.
/// </summary>

View File

@@ -42,7 +42,7 @@ namespace Umbraco.Web.Mvc
/// <param name="requestContext"></param>
/// <param name="controllerName"></param>
/// <returns></returns>
protected Type GetControllerType(RequestContext requestContext, string controllerName)
public Type GetControllerType(RequestContext requestContext, string controllerName)
{
return _innerFactory.GetControllerType(requestContext, controllerName);
}

View File

@@ -4,6 +4,7 @@ using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Configuration;
@@ -184,7 +185,7 @@ namespace Umbraco.Web.Mvc
requestContext.RouteData.Values["action"] = postedInfo.ActionName;
requestContext.RouteData.DataTokens["area"] = postedInfo.Area;
IHttpHandler handler = new MvcHandler(requestContext);
IHttpHandler handler = new UmbracoMvcHandler(requestContext);
//ensure the controllerType is set if found, meaning it is a plugin, not locally declared
if (postedInfo.Area != standardArea)
@@ -232,57 +233,53 @@ namespace Umbraco.Web.Mvc
var def = new RouteDefinition
{
ControllerName = defaultControllerName,
Controller = new RenderMvcController(UmbracoContext),
ControllerType = typeof(RenderMvcController),
PublishedContentRequest = publishedContentRequest,
ActionName = ((Route)requestContext.RouteData.Route).Defaults["action"].ToString(),
HasHijackedRoute = false
};
//check that a template is defined), if it doesn't and there is a hijacked route it will just route
// to the index Action
if (publishedContentRequest.HasTemplate)
{
//the template Alias should always be already saved with a safe name.
//if there are hyphens in the name and there is a hijacked route, then the Action will need to be attributed
// with the action name attribute.
var templateName = publishedContentRequest.TemplateAlias.Split('.')[0].ToSafeAlias();
def.ActionName = templateName;
}
//check if there's a custom controller assigned, base on the document type alias.
var controller = _controllerFactory.CreateController(requestContext, publishedContentRequest.PublishedContent.DocumentTypeAlias);
var controllerType = ((MasterControllerFactory)_controllerFactory).GetControllerTypeInternal(requestContext, publishedContentRequest.PublishedContent.DocumentTypeAlias);
//check if that controller exists
if (controller != null)
{
if (controllerType != null)
{
//ensure the controller is of type 'RenderMvcController'
if (controllerType.IsSubclassOf(typeof (RenderMvcController)))
{
//set the controller and name to the custom one
def.ControllerType = controllerType;
def.ControllerName = ControllerExtensions.GetControllerName(controllerType);
if (def.ControllerName != defaultControllerName)
{
def.HasHijackedRoute = true;
}
}
else
{
LogHelper.Warn<RenderRouteHandler>(
"The current Document Type {0} matches a locally declared controller of type {1}. Custom Controllers for Umbraco routing must inherit from '{2}'.",
() => publishedContentRequest.PublishedContent.DocumentTypeAlias,
() => controllerType.FullName,
() => typeof (RenderMvcController).FullName);
//exit as we cannnot route to the custom controller, just route to the standard one.
return def;
}
}
//ensure the controller is of type 'RenderMvcController'
if (controller is RenderMvcController)
{
//set the controller and name to the custom one
def.Controller = (ControllerBase)controller;
def.ControllerName = ControllerExtensions.GetControllerName(controller.GetType());
if (def.ControllerName != defaultControllerName)
{
def.HasHijackedRoute = true;
}
}
else
{
LogHelper.Warn<RenderRouteHandler>(
"The current Document Type {0} matches a locally declared controller of type {1}. Custom Controllers for Umbraco routing must inherit from '{2}'.",
() => publishedContentRequest.PublishedContent.DocumentTypeAlias,
() => controller.GetType().FullName,
() => typeof(RenderMvcController).FullName);
//exit as we cannnot route to the custom controller, just route to the standard one.
return def;
}
//check that a template is defined), if it doesn't and there is a hijacked route it will just route
// to the index Action
if (publishedContentRequest.HasTemplate)
{
//the template Alias should always be already saved with a safe name.
//if there are hyphens in the name and there is a hijacked route, then the Action will need to be attributed
// with the action name attribute.
var templateName = publishedContentRequest.TemplateAlias.Split('.')[0].ToSafeAlias();
def.ActionName = templateName;
}
}
return def;
return def;
}
internal IHttpHandler GetHandlerOnMissingTemplate(PublishedContentRequest pcr)
@@ -365,11 +362,19 @@ namespace Umbraco.Web.Mvc
requestContext.RouteData.Values["action"] = routeDef.ActionName;
}
// Set the session state requirements
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext, routeDef.ControllerName));
// reset the friendly path so in the controllers and anything occuring after this point in time,
//the URL is reset back to the original request.
requestContext.HttpContext.RewritePath(UmbracoContext.OriginalRequestUrl.PathAndQuery);
return new MvcHandler(requestContext);
return new UmbracoMvcHandler(requestContext);
}
private SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext, string controllerName)
{
return _controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Web.Mvc;
using Umbraco.Web.Routing;
@@ -16,6 +17,12 @@ namespace Umbraco.Web.Mvc
/// </summary>
public ControllerBase Controller { get; set; }
/// <summary>
/// The Controller type found for routing to
/// </summary>
public Type ControllerType { get; set; }
/// <summary>
/// The current RenderModel found for the request
/// </summary>

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace Umbraco.Web.Mvc
{
/// <summary>
/// Mvc handler class to intercept creation of controller and store it for later use.
/// This means we create two instances of the same controller to support some features later on.
///
/// The alternate option for this is to completely rewrite all MvcHandler methods.
///
/// This is currently needed for the 'return CurrentUmbracoPage()' surface controller functionality
/// because it needs to send data back to the page controller.
/// </summary>
internal class UmbracoMvcHandler : MvcHandler
{
public UmbracoMvcHandler(RequestContext requestContext)
: base(requestContext)
{
}
private void StoreControllerInRouteDefinition()
{
var routeDef = (RouteDefinition)RequestContext.RouteData.DataTokens["umbraco-route-def"];
if (routeDef == null) return;
// Get the factory and controller and create a new instance of the controller
var factory = ControllerBuilder.Current.GetControllerFactory();
var controller = factory.CreateController(RequestContext, routeDef.ControllerName) as ControllerBase;
// Store the controller
routeDef.Controller = controller;
}
protected override void ProcessRequest(HttpContextBase httpContext)
{
StoreControllerInRouteDefinition();
// Let MVC do its magic and continue the request
base.ProcessRequest(httpContext);
}
protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback,
object state)
{
StoreControllerInRouteDefinition();
return base.BeginProcessRequest(httpContext, callback, state);
}
}
}

View File

@@ -303,6 +303,7 @@
<Compile Include="Mvc\UmbracoAuthorizeAttribute.cs" />
<Compile Include="Mvc\UmbracoAuthorizedController.cs" />
<Compile Include="Mvc\UmbracoController.cs" />
<Compile Include="Mvc\UmbracoMvcHandler.cs" />
<Compile Include="Mvc\UmbracoViewPage.cs" />
<Compile Include="PublishedContentExtensions.cs" />
<Compile Include="ExamineExtensions.cs" />