From 048480d5be9ff1fa6b6681608b5453169e8ab7ba Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 5 Jul 2013 14:12:31 +1000 Subject: [PATCH 1/2] Fixes: #U4-2460 - UmbracoHelper.RenderTemplate will now execute the complete MVC cycle when rendering MVC templates whereas before it would only execute the view which means any actionfilters, etc... applied would never have fired (as well as other things) --- src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs | 13 +++++ .../Standalone/StandaloneHttpContext.cs | 52 ++++++++++++++++++- src/Umbraco.Web/Templates/TemplateRenderer.cs | 36 ++++++++++--- 3 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs b/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs index 1ace297bfd..649ac54f27 100644 --- a/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs +++ b/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs @@ -1,5 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Web; @@ -38,6 +40,15 @@ namespace Umbraco.Web.Mvc routeDef.Controller = controller; } + /// + /// This is used internally purely to render an Umbraco MVC template to string and shouldn't be used for anything else. + /// + internal void ExecuteUmbracoRequest() + { + StoreControllerInRouteDefinition(); + base.ProcessRequest(RequestContext.HttpContext); + } + protected override void ProcessRequest(HttpContextBase httpContext) { StoreControllerInRouteDefinition(); @@ -54,4 +65,6 @@ namespace Umbraco.Web.Mvc return base.BeginProcessRequest(httpContext, callback, state); } } + + } \ No newline at end of file diff --git a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs index 4cf64a8adf..55339e97b6 100644 --- a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs +++ b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs @@ -1,5 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Web; @@ -11,11 +13,59 @@ namespace Umbraco.Web.Standalone /// internal class StandaloneHttpContext : HttpContextBase { + private readonly string _url; + private readonly HttpSessionStateBase _session = new StandaloneHttpSessionState(); + private readonly HttpResponseBase _response; + private readonly HttpRequestBase _request = new StandaloneHttpRequest(); + private readonly TextWriter _writer = new StringWriter(); + private readonly IDictionary _items = new Dictionary(); + + public StandaloneHttpContext() + { + //create a custom response with a custom writer. + _response = new HttpResponseWrapper(new HttpResponse(_writer)); + } + + public StandaloneHttpContext(string url) + : this() + { + if (url == null) throw new ArgumentNullException("url"); + _url = url; + _request = new HttpRequestWrapper(new HttpRequest("", _url, "")); + } + + // fixme - what shall we implement here? + + public override IDictionary Items + { + get { return _items; } + } + + public override HttpSessionStateBase Session + { + get { return _session; } + } public override HttpRequestBase Request { - get { return null; } + get { return _request; } } + + public override HttpResponseBase Response + { + get { return _response; } + } + + } + + internal class StandaloneHttpSessionState : HttpSessionStateBase + { + + } + + internal class StandaloneHttpRequest : HttpRequestBase + { + } } diff --git a/src/Umbraco.Web/Templates/TemplateRenderer.cs b/src/Umbraco.Web/Templates/TemplateRenderer.cs index fe60c6959e..a13ed031f8 100644 --- a/src/Umbraco.Web/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web/Templates/TemplateRenderer.cs @@ -137,12 +137,9 @@ namespace Umbraco.Web.Templates requestContext.RouteData.Values.Add("controller", routeDef.ControllerName); //add the rest of the required route data routeHandler.SetupRouteDataForRequest(renderModel, requestContext, contentRequest); - //create and assign the controller context - routeDef.Controller.ControllerContext = new ControllerContext(requestContext, routeDef.Controller); - //render as string - var stringOutput = routeDef.Controller.RenderViewToString( - routeDef.ActionName, - renderModel); + + var stringOutput = RenderUmbracoRequestToString(requestContext); + sw.Write(stringOutput); break; case RenderingEngine.WebForms: @@ -157,6 +154,33 @@ namespace Umbraco.Web.Templates } + /// + /// This will execute the UmbracoMvcHandler for the request specified and get the string output. + /// + /// + /// Assumes the RequestContext is setup specifically to render an Umbraco view. + /// + /// + /// + /// To acheive this we temporarily change the output text writer of the current HttpResponse, then + /// execute the controller via the handler which innevitably writes the result to the text writer + /// that has been assigned to the response. Then we change the response textwriter back to the original + /// before continuing . + /// + private string RenderUmbracoRequestToString(RequestContext requestContext) + { + var currentWriter = requestContext.HttpContext.Response.Output; + var newWriter = new StringWriter(); + requestContext.HttpContext.Response.Output = newWriter; + + var handler = new UmbracoMvcHandler(requestContext); + handler.ExecuteUmbracoRequest(); + + //reset it + requestContext.HttpContext.Response.Output = currentWriter; + return newWriter.ToString(); + } + private void SetNewItemsOnContextObjects(PublishedContentRequest contentRequest) { // handlers like default.aspx will want it and most macros currently need it From 60805f91d6cfe5e9854c092c15e6555da3fa7ca1 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 5 Jul 2013 16:58:51 +1000 Subject: [PATCH 2/2] bit of code cleaning. --- src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../ActionHandlers/SimilarNodeNameComparer.cs | 46 ++++++++++++++ .../ActionHandlers/umbEnsureUniqueName.cs | 41 ------------- .../umbraco/create/content.ascx.cs | 60 +++++++------------ .../umbraco/create/contentTasks.cs | 28 ++++----- .../umbraco/dialogs/create.aspx.cs | 14 ++--- src/umbraco.cms/Actions/ActionNew.cs | 6 +- 7 files changed, 90 insertions(+), 106 deletions(-) create mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/SimilarNodeNameComparer.cs diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index ab431d6c84..d99c76a624 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -367,6 +367,7 @@ + ASPXCodeBehind diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/SimilarNodeNameComparer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/SimilarNodeNameComparer.cs new file mode 100644 index 0000000000..148d395524 --- /dev/null +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/SimilarNodeNameComparer.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +namespace umbraco.ActionHandlers +{ + /// + /// Comparer that takes into account the duplicate index of a node name + /// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc. + /// + [Obsolete("This class is no longer used and will be removed from the codebase in future versions")] + public class SimilarNodeNameComparer : IComparer + { + public int Compare(string x, string y) + { + if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1) + { + if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('('))) + { + int xDuplicateIndex = ExtractDuplicateIndex(x); + int yDuplicateIndex = ExtractDuplicateIndex(y); + + if (xDuplicateIndex != 0 && yDuplicateIndex != 0) + { + return xDuplicateIndex.CompareTo(yDuplicateIndex); + } + } + } + return x.ToLower().CompareTo(y.ToLower()); + } + + private int ExtractDuplicateIndex(string text) + { + int index = 0; + + if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2) + { + int startPos = text.LastIndexOf('(') + 1; + int length = text.Length - 1 - startPos; + + int.TryParse(text.Substring(startPos, length), out index); + } + + return index; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs index baacbff4f6..d5fab83940 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/ActionHandlers/umbEnsureUniqueName.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using Umbraco.Core.Logging; using umbraco.cms.businesslogic.web; @@ -89,44 +88,4 @@ namespace umbraco.ActionHandlers #endregion } - - /// - /// Comparer that takes into account the duplicate index of a node name - /// This is needed as a normal alphabetic sort would go Page (1), Page (10), Page (2) etc. - /// - public class SimilarNodeNameComparer : IComparer - { - public int Compare(string x, string y) - { - if (x.LastIndexOf(')') == x.Length - 1 && y.LastIndexOf(')') == y.Length - 1) - { - if (x.ToLower().Substring(0, x.LastIndexOf('(')) == y.ToLower().Substring(0, y.LastIndexOf('('))) - { - int xDuplicateIndex = ExtractDuplicateIndex(x); - int yDuplicateIndex = ExtractDuplicateIndex(y); - - if (xDuplicateIndex != 0 && yDuplicateIndex != 0) - { - return xDuplicateIndex.CompareTo(yDuplicateIndex); - } - } - } - return x.ToLower().CompareTo(y.ToLower()); - } - - private int ExtractDuplicateIndex(string text) - { - int index = 0; - - if (text.LastIndexOf('(') != -1 && text.LastIndexOf('(') < text.Length - 2) - { - int startPos = text.LastIndexOf('(') + 1; - int length = text.Length - 1 - startPos; - - int.TryParse(text.Substring(startPos, length), out index); - } - - return index; - } - } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/content.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/content.ascx.cs index 14347b5c04..91b2a8c519 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/content.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/content.ascx.cs @@ -3,12 +3,12 @@ using System.Linq; using System.Text; using System.Web.UI; using System.Web.UI.WebControls; +using Umbraco.Core.IO; using umbraco.cms.businesslogic.web; using umbraco.presentation.create; using Content=umbraco.cms.businesslogic.Content; using umbraco.cms.helpers; using umbraco.BasePages; -using umbraco.IO; namespace umbraco.cms.presentation.create.controls { @@ -19,48 +19,48 @@ namespace umbraco.cms.presentation.create.controls { protected void Page_Load(object sender, EventArgs e) { - if (!IsPostBack) + if (IsPostBack == false) { sbmt.Text = ui.Text("create"); - int NodeId = int.Parse(Request["nodeID"]); + var nodeId = int.Parse(Request["nodeID"]); - int[] allowedIds = new int[0]; - if (NodeId > 0) + var allowedIds = new int[0]; + if (nodeId > 0) { - Content c = new Document(NodeId); + var c = new Document(nodeId); allowedIds = c.ContentType.AllowedChildContentTypeIDs; } nodeType.Attributes.Add("onChange", "document.getElementById('typeDescription').innerHTML = typeInfo[this.selectedIndex];"); - int counter = 0; - bool typeInited = false; - StringBuilder js = new StringBuilder(); + var counter = 0; + var typeInited = false; + var js = new StringBuilder(); var documentTypeList = DocumentType.GetAllAsList().ToList(); - foreach (DocumentType dt in documentTypeList) + foreach (var dt in documentTypeList) { string docDescription = "No description available..."; - if (dt.Description != null && dt.Description != "") + if (string.IsNullOrEmpty(dt.Description) == false) docDescription = dt.Description; docDescription = "" + dt.Text + "
" + docDescription.Replace(Environment.NewLine, "
"); docDescription = docDescription.Replace("'", "\\'"); - string docImage = (dt.Thumbnail != "") ? dt.Thumbnail : "../nada.gif"; + var docImage = (dt.Thumbnail != "") ? dt.Thumbnail : "../nada.gif"; docImage = IOHelper.ResolveUrl( SystemDirectories.Umbraco ) + "/images/thumbnails/" + docImage; - ListItem li = new ListItem(); + var li = new ListItem(); li.Text = dt.Text; li.Value = dt.Id.ToString(); - if (NodeId > 0) + if (nodeId > 0) { - foreach (int i in allowedIds) if (i == dt.Id) + foreach (var i in allowedIds) if (i == dt.Id) { nodeType.Items.Add(li); js.Append("typeInfo[" + counter + "] = '

" + docDescription + "

'\n"); - if (!typeInited) + if (typeInited == false) { descr.Text = "

" + docDescription + "

"; @@ -76,7 +76,7 @@ namespace umbraco.cms.presentation.create.controls nodeType.Items.Add(li); js.Append("typeInfo[" + counter + "] = '

" + docDescription + "

'\n"); - if (!typeInited) + if (typeInited == false) { descr.Text = "

" + docDescription + "

'"; @@ -94,34 +94,14 @@ namespace umbraco.cms.presentation.create.controls } } - #region Web Form Designer generated code - - protected override void OnInit(EventArgs e) - { - // - // CODEGEN: This call is required by the ASP.NET Web Form Designer. - // - InitializeComponent(); - base.OnInit(e); - } - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - } - - #endregion - + protected void sbmt_Click(object sender, EventArgs e) { - doCreation(); + DoCreation(); } - private void doCreation() + private void DoCreation() { if (Page.IsValid) { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/contentTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/contentTasks.cs index a0c6c616fb..45cc4a737c 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/contentTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/contentTasks.cs @@ -13,14 +13,14 @@ namespace umbraco { private string _alias; - private int _parentID; - private int _typeID; - private int _userID; + private int _parentId; + private int _typeId; + private int _userId; private string _returnUrl = ""; public int UserId { - set { _userID = value; } + set { _userId = value; } } public string ReturnUrl @@ -30,8 +30,8 @@ namespace umbraco public int TypeID { - set { _typeID = value; } - get { return _typeID; } + set { _typeId = value; } + get { return _typeId; } } public string Alias @@ -44,18 +44,18 @@ namespace umbraco { set { - _parentID = value; + _parentId = value; } get { - return _parentID; + return _parentId; } } public bool Save() { - cms.businesslogic.web.DocumentType dt = new cms.businesslogic.web.DocumentType(TypeID); - cms.businesslogic.web.Document d = cms.businesslogic.web.Document.MakeNew(Alias, dt, BusinessLogic.User.GetUser(_userID), ParentID); + var dt = new cms.businesslogic.web.DocumentType(TypeID); + var d = cms.businesslogic.web.Document.MakeNew(Alias, dt, User.GetUser(_userId), ParentID); if (d == null) { //TODO: Slace - Fix this to use the language files @@ -71,13 +71,13 @@ namespace umbraco public bool Delete() { - cms.businesslogic.web.Document d = new cms.businesslogic.web.Document(ParentID); - - // Log - BusinessLogic.Log.Add(BusinessLogic.LogTypes.Delete, User.GetCurrent(), d.Id, ""); + var d = new cms.businesslogic.web.Document(ParentID); d.delete(); + // Log + Log.Add(LogTypes.Delete, User.GetCurrent(), d.Id, ""); + return true; } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/create.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/create.aspx.cs index ca384bd3af..7bc9354816 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/create.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/create.aspx.cs @@ -9,8 +9,8 @@ using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; using System.Xml; +using Umbraco.Core.IO; using umbraco.cms.businesslogic; -using umbraco.IO; using umbraco.presentation; using umbraco.BusinessLogic.Actions; using umbraco.BasePages; @@ -44,19 +44,19 @@ namespace umbraco.dialogs if (helper.Request("app") == Constants.Applications.Media || CheckCreatePermissions(nodeId)) { //pane_chooseName.Text = ui.Text("create", "updateData", this.getUser()); - cms.businesslogic.CMSNode c = new cms.businesslogic.CMSNode(nodeId); + var c = new CMSNode(nodeId); path.Value = c.Path; pane_chooseNode.Visible = false; panel_buttons.Visible = false; pane_chooseName.Visible = true; - XmlDocument createDef = new XmlDocument(); - XmlTextReader defReader = new XmlTextReader(Server.MapPath(umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + "/config/create/UI.xml")); + var createDef = new XmlDocument(); + var defReader = new XmlTextReader(Server.MapPath(IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/config/create/UI.xml")); createDef.Load(defReader); defReader.Close(); // Find definition for current nodeType XmlNode def = createDef.SelectSingleNode("//nodeType [@alias = '" + Request.QueryString["app"] + "']"); - phCreate.Controls.Add(new UserControl().LoadControl(umbraco.IO.IOHelper.ResolveUrl(umbraco.IO.SystemDirectories.Umbraco) + def.SelectSingleNode("./usercontrol").FirstChild.Value)); + phCreate.Controls.Add(new UserControl().LoadControl(IOHelper.ResolveUrl(SystemDirectories.Umbraco) + def.SelectSingleNode("./usercontrol").FirstChild.Value)); } else { @@ -71,8 +71,8 @@ namespace umbraco.dialogs protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); - ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference( IOHelper.ResolveUrl( SystemDirectories.Webservices) +"/cmsnode.asmx")); - ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference( IOHelper.ResolveUrl( SystemDirectories.Webservices) +"/legacyAjaxCalls.asmx")); + ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference( IOHelper.ResolveUrl( SystemDirectories.WebServices) +"/cmsnode.asmx")); + ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference( IOHelper.ResolveUrl( SystemDirectories.WebServices) +"/legacyAjaxCalls.asmx")); } private bool CheckCreatePermissions(int nodeId) diff --git a/src/umbraco.cms/Actions/ActionNew.cs b/src/umbraco.cms/Actions/ActionNew.cs index ec07d8096a..ff17c91a0b 100644 --- a/src/umbraco.cms/Actions/ActionNew.cs +++ b/src/umbraco.cms/Actions/ActionNew.cs @@ -10,9 +10,7 @@ namespace umbraco.BusinessLogic.Actions public class ActionNew : IAction { //create singleton -#pragma warning disable 612,618 - private static readonly ActionNew m_instance = new ActionNew(); -#pragma warning restore 612,618 + private static readonly ActionNew InnerInstance = new ActionNew(); /// /// A public constructor exists ONLY for backwards compatibility in regards to 3rd party add-ons. @@ -24,7 +22,7 @@ namespace umbraco.BusinessLogic.Actions public static ActionNew Instance { - get { return m_instance; } + get { return InnerInstance; } } #region IAction Members