From f3fbae7173fb032c4dfd68319b01fe164e03c198 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Fri, 31 May 2013 17:20:56 -1000 Subject: [PATCH] Updated trees to get children nodes from the server... nearly working and also works with proxying to legacy trees. In fact there are not new trees created yet, just focusing on adapting for legacy trees which so far seems to be good. --- .../common/resources/tree.resource.js | 27 ++- .../umbraco/js/umbraco.controllers.js | 13 +- .../umbraco/js/umbraco.resources.js | 26 ++- .../umbraco/js/umbraco.services.js | 156 ++++++++++-------- .../Trees/ApplicationTreeApiController.cs | 57 +------ .../Trees/ApplicationTreeExtensions.cs | 75 +++++++++ .../Trees/LegacyTreeApiController.cs | 47 ++++++ .../Trees/LegacyTreeDataAdapter.cs | 17 +- src/Umbraco.Web/Umbraco.Web.csproj | 6 +- 9 files changed, 294 insertions(+), 130 deletions(-) create mode 100644 src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs create mode 100644 src/Umbraco.Web/Trees/LegacyTreeApiController.cs diff --git a/src/Umbraco.Web.UI.Client/common/resources/tree.resource.js b/src/Umbraco.Web.UI.Client/common/resources/tree.resource.js index 672f052666..1172ae9df9 100644 --- a/src/Umbraco.Web.UI.Client/common/resources/tree.resource.js +++ b/src/Umbraco.Web.UI.Client/common/resources/tree.resource.js @@ -8,13 +8,21 @@ define(['angular'], function(angular) { **/ function umbTreeResource($q, $http) { - //internal method to get the tree app url + /** internal method to get the tree app url */ function getTreeAppUrl(section) { return Umbraco.Sys.ServerVariables.treeApplicationApiBaseUrl + "GetApplicationTrees?application=" + section; } + /** internal method to get the tree node's children url */ + function getTreeNodesUrl(node) { + if (!node.childNodesUrl) + throw "No childNodesUrl property found on the tree node, cannot load child nodes"; + return node.childNodesUrl; + } //the factory object returned return { + + /** Loads in the data to display the nodes for an application */ loadApplication: function (section) { var deferred = $q.defer(); @@ -29,6 +37,23 @@ define(['angular'], function(angular) { }); return deferred.promise; + }, + /** Loads in the data to display the child nodes for a given node */ + loadNodes: function(section, node) { + + var deferred = $q.defer(); + + //go and get the tree data + $http.get(getTreeNodesUrl(node)). + success(function (data, status, headers, config) { + deferred.resolve(data); + }). + error(function (data, status, headers, config) { + deferred.reject('Failed to retreive data for child nodes ' + node.nodeId); + }); + + return deferred.promise; + } }; } diff --git a/src/Umbraco.Web.UI/umbraco/js/umbraco.controllers.js b/src/Umbraco.Web.UI/umbraco/js/umbraco.controllers.js index c7a56ac65c..b77424fade 100644 --- a/src/Umbraco.Web.UI/umbraco/js/umbraco.controllers.js +++ b/src/Umbraco.Web.UI/umbraco/js/umbraco.controllers.js @@ -106,9 +106,16 @@ define(['angular'], function (angular) { if (node.expanded) { node.expanded = false; node.children = []; - } else { - node.children = tree.getChildren(node, $scope.currentSection); - node.expanded = true; + } + else { + tree.getChildren(node, $scope.currentSection) + .then(function (data) { + node.children = data; + node.expanded = true; + }, function (reason) { + alert(reason); + return; + }); } }; diff --git a/src/Umbraco.Web.UI/umbraco/js/umbraco.resources.js b/src/Umbraco.Web.UI/umbraco/js/umbraco.resources.js index 682ce8695e..83aa11617b 100644 --- a/src/Umbraco.Web.UI/umbraco/js/umbraco.resources.js +++ b/src/Umbraco.Web.UI/umbraco/js/umbraco.resources.js @@ -12,13 +12,20 @@ define(['angular'], function (angular) { **/ function umbTreeResource($q, $http) { - //internal method to get the tree app url + /** internal method to get the tree app url */ function getTreeAppUrl(section) { return Umbraco.Sys.ServerVariables.treeApplicationApiBaseUrl + "GetApplicationTrees?application=" + section; } + /** internal method to get the tree node's children url */ + function getTreeNodesUrl(node) { + if (!node.childNodesUrl) + throw "No childNodesUrl property found on the tree node, cannot load child nodes"; + return node.childNodesUrl; + } //the factory object returned return { + /** Loads in the data to display the nodes for an application */ loadApplication: function (section) { var deferred = $q.defer(); @@ -33,6 +40,23 @@ define(['angular'], function (angular) { }); return deferred.promise; + }, + /** Loads in the data to display the child nodes for a given node */ + loadNodes: function (section, node) { + + var deferred = $q.defer(); + + //go and get the tree data + $http.get(getTreeNodesUrl(node)). + success(function (data, status, headers, config) { + deferred.resolve(data); + }). + error(function (data, status, headers, config) { + deferred.reject('Failed to retreive data for child nodes ' + node.nodeId); + }); + + return deferred.promise; + } }; } diff --git a/src/Umbraco.Web.UI/umbraco/js/umbraco.services.js b/src/Umbraco.Web.UI/umbraco/js/umbraco.services.js index 610355dacc..120e224d76 100644 --- a/src/Umbraco.Web.UI/umbraco/js/umbraco.services.js +++ b/src/Umbraco.Web.UI/umbraco/js/umbraco.services.js @@ -290,68 +290,68 @@ angular.module('umbraco.services.tree', ["umbraco.resources.trees"]) //NOTE: The below will never be hit, it is legacy code from the mock data services - var t; - switch(section){ + //var t; + //switch(section){ - case "content": - t = { - name: section, - alias: section, + // case "content": + // t = { + // name: section, + // alias: section, - nodes: [ - { name: "My website", id: 1234, icon: "icon-home", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1, defaultAction: "create" }, - { name: "Components", id: 1235, icon: "icon-cogs", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1, defaultAction: "create" }, - { name: "Archieve", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1, defaultAction: "create" }, - { name: "Recycle Bin", id: 1237, icon: "icon-trash", view: section + "/trash/view/", children: [], expanded: false, level: 1, defaultAction: "create" } - ] - }; - break; + // nodes: [ + // { name: "My website", id: 1234, icon: "icon-home", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1, defaultAction: "create" }, + // { name: "Components", id: 1235, icon: "icon-cogs", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1, defaultAction: "create" }, + // { name: "Archieve", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1, defaultAction: "create" }, + // { name: "Recycle Bin", id: 1237, icon: "icon-trash", view: section + "/trash/view/", children: [], expanded: false, level: 1, defaultAction: "create" } + // ] + // }; + // break; - case "developer": - t = { - name: section, - alias: section, + // case "developer": + // t = { + // name: section, + // alias: section, - nodes: [ - { name: "Data types", id: 1234, icon: "icon-folder-close", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, - { name: "Macros", id: 1235, icon: "icon-folder-close", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, - { name: "Pacakges", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, - { name: "XSLT Files", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 }, - { name: "Razor Files", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } - ] - }; - break; - case "settings": - t = { - name: section, - alias: section, + // nodes: [ + // { name: "Data types", id: 1234, icon: "icon-folder-close", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, + // { name: "Macros", id: 1235, icon: "icon-folder-close", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, + // { name: "Pacakges", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, + // { name: "XSLT Files", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 }, + // { name: "Razor Files", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } + // ] + // }; + // break; + // case "settings": + // t = { + // name: section, + // alias: section, - nodes: [ - { name: "Stylesheets", id: 1234, icon: "icon-folder-close", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, - { name: "Templates", id: 1235, icon: "icon-folder-close", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, - { name: "Dictionary", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, - { name: "Media types", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 }, - { name: "Document types", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } - ] - }; - break; - default: - t = { - name: section, - alias: section, + // nodes: [ + // { name: "Stylesheets", id: 1234, icon: "icon-folder-close", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, + // { name: "Templates", id: 1235, icon: "icon-folder-close", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, + // { name: "Dictionary", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, + // { name: "Media types", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 }, + // { name: "Document types", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } + // ] + // }; + // break; + // default: + // t = { + // name: section, + // alias: section, - nodes: [ - { name: "random-name-" + section, id: 1234, icon: "icon-home", defaultAction: "create", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, - { name: "random-name-" + section, id: 1235, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, - { name: "random-name-" + section, id: 1236, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, - { name: "random-name-" + section, id: 1237, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } - ] - }; - break; - } + // nodes: [ + // { name: "random-name-" + section, id: 1234, icon: "icon-home", defaultAction: "create", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, + // { name: "random-name-" + section, id: 1235, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, + // { name: "random-name-" + section, id: 1236, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, + // { name: "random-name-" + section, id: 1237, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } + // ] + // }; + // break; + //} - treeArray[section] = t; - return treeArray[section]; + //treeArray[section] = t; + //return treeArray[section]; }, getActions: function(treeItem, section){ @@ -401,20 +401,42 @@ angular.module('umbraco.services.tree', ["umbraco.resources.trees"]) }, getChildren: function (treeItem, section) { - var iLevel = treeItem.level + 1; - //hack to have create as default content action - var action; - if(section === "content"){ - action = "create"; - } + if (!treeItem) { + throw "No treeItem defined"; + } + if (!section) { + throw "No section defined"; + } - return [ - { name: "child-of-" + treeItem.name, id: iLevel + "" + 1234, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1234, children: [], expanded: false, level: iLevel, defaultAction: action }, - { name: "random-name-" + section, id: iLevel + "" + 1235, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1235, children: [], expanded: false, level: iLevel, defaultAction: action }, - { name: "random-name-" + section, id: iLevel + "" + 1236, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1236, children: [], expanded: false, level: iLevel, defaultAction: action }, - { name: "random-name-" + section, id: iLevel + "" + 1237, icon: "icon-file-alt", view: "common/legacy/1237?p=" + encodeURI("developer/contentType.aspx?idequal1234"), children: [], expanded: false, level: iLevel, defaultAction: action } - ]; + var deferred = $q.defer(); + + umbTreeResource.loadNodes(section, treeItem) + .then(function (data) { + deferred.resolve(data); + }, function (reason) { + //bubble up the rejection + deferred.reject(reason); + return; + }); + + return deferred.promise; + + //NOTE: The below will never get hit it is legacy mock data + //var iLevel = treeItem.level + 1; + + ////hack to have create as default content action + //var action; + //if(section === "content"){ + // action = "create"; + //} + + //return [ + // { name: "child-of-" + treeItem.name, id: iLevel + "" + 1234, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1234, children: [], expanded: false, level: iLevel, defaultAction: action }, + // { name: "random-name-" + section, id: iLevel + "" + 1235, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1235, children: [], expanded: false, level: iLevel, defaultAction: action }, + // { name: "random-name-" + section, id: iLevel + "" + 1236, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1236, children: [], expanded: false, level: iLevel, defaultAction: action }, + // { name: "random-name-" + section, id: iLevel + "" + 1237, icon: "icon-file-alt", view: "common/legacy/1237?p=" + encodeURI("developer/contentType.aspx?idequal1234"), children: [], expanded: false, level: iLevel, defaultAction: action } + //]; } }; }); diff --git a/src/Umbraco.Web/Trees/ApplicationTreeApiController.cs b/src/Umbraco.Web/Trees/ApplicationTreeApiController.cs index 41c7742bcb..16b33c86dd 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeApiController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeApiController.cs @@ -88,12 +88,12 @@ namespace Umbraco.Web.Trees private TreeNodeCollection GetNodeCollection(ApplicationTree configTree, string id, FormDataCollection queryStrings) { if (configTree == null) throw new ArgumentNullException("configTree"); - var byControllerAttempt = TryLoadFromControllerTree(configTree, id, queryStrings); + var byControllerAttempt = configTree.TryLoadFromControllerTree(id, queryStrings, ControllerContext, Request); if (byControllerAttempt.Success) { return byControllerAttempt.Result; } - var legacyAttempt = TryLoadFromLegacyTree(configTree, id, queryStrings); + var legacyAttempt = configTree.TryLoadFromLegacyTree(id, queryStrings, Url); if (legacyAttempt.Success) { return legacyAttempt.Result; @@ -101,58 +101,7 @@ namespace Umbraco.Web.Trees throw new ApplicationException("Could not render a tree for type " + configTree.Alias); } - - private Attempt TryLoadFromControllerTree(ApplicationTree appTree, string id, FormDataCollection formCollection) - { - //get reference to all TreeApiControllers - var controllerTrees = UmbracoApiControllerResolver.Current.RegisteredUmbracoApiControllers - .Where(TypeHelper.IsTypeAssignableFrom) - .ToArray(); - - //find the one we're looking for - var foundControllerTree = controllerTrees.FirstOrDefault(x => x.GetFullNameWithAssembly() == appTree.Type); - if (foundControllerTree == null) - { - return new Attempt(new InstanceNotFoundException("Could not find tree of type " + appTree.Type + " in any loaded DLLs")); - } - - //instantiate it, since we are proxying, we need to setup the instance with our current context - var instance = (TreeApiController)DependencyResolver.Current.GetService(foundControllerTree); - instance.ControllerContext = ControllerContext; - instance.Request = Request; - //return it's data - return new Attempt(true, instance.GetNodes(id, formCollection)); - } - - private Attempt TryLoadFromLegacyTree(ApplicationTree appTree, string id, FormDataCollection formCollection) - { - //This is how the legacy trees worked.... - var treeDef = TreeDefinitionCollection.Instance.FindTree(appTree.Alias); - if (treeDef == null) - { - return new Attempt(new InstanceNotFoundException("Could not find tree of type " + appTree.Alias)); - } - - var bTree = treeDef.CreateInstance(); - var treeParams = new TreeParams(); - - //we currently only support an integer id or a string id, we'll refactor how this works - //later but we'll get this working first - int startId; - if (int.TryParse(id, out startId)) - { - treeParams.StartNodeID = startId; - } - else - { - treeParams.NodeKey = id; - } - var xTree = new XmlTree(); - bTree.SetTreeParameters(treeParams); - bTree.Render(ref xTree); - - return new Attempt(true, LegacyTreeDataAdapter.ConvertFromLegacy(xTree)); - } + //Temporary, but necessary until we refactor trees in general internal class TreeParams : ITreeService diff --git a/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs b/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs new file mode 100644 index 0000000000..36a9aa0b69 --- /dev/null +++ b/src/Umbraco.Web/Trees/ApplicationTreeExtensions.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Instrumentation; +using System.Net.Http; +using System.Net.Http.Formatting; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http.Controllers; +using System.Web.Mvc; +using Umbraco.Core; +using Umbraco.Web.WebApi; +using umbraco.BusinessLogic; +using umbraco.cms.presentation.Trees; +using UrlHelper = System.Web.Http.Routing.UrlHelper; + +namespace Umbraco.Web.Trees +{ + internal static class ApplicationTreeExtensions + { + + internal static Attempt TryLoadFromControllerTree(this ApplicationTree appTree, string id, FormDataCollection formCollection, HttpControllerContext controllerContext, HttpRequestMessage request) + { + //get reference to all TreeApiControllers + var controllerTrees = UmbracoApiControllerResolver.Current.RegisteredUmbracoApiControllers + .Where(TypeHelper.IsTypeAssignableFrom) + .ToArray(); + + //find the one we're looking for + var foundControllerTree = controllerTrees.FirstOrDefault(x => x.GetFullNameWithAssembly() == appTree.Type); + if (foundControllerTree == null) + { + return new Attempt(new InstanceNotFoundException("Could not find tree of type " + appTree.Type + " in any loaded DLLs")); + } + + //instantiate it, since we are proxying, we need to setup the instance with our current context + var instance = (TreeApiController)DependencyResolver.Current.GetService(foundControllerTree); + instance.ControllerContext = controllerContext; + instance.Request = request; + //return it's data + return new Attempt(true, instance.GetNodes(id, formCollection)); + } + + internal static Attempt TryLoadFromLegacyTree(this ApplicationTree appTree, string id, FormDataCollection formCollection, UrlHelper urlHelper) + { + //This is how the legacy trees worked.... + var treeDef = TreeDefinitionCollection.Instance.FindTree(appTree.Alias); + if (treeDef == null) + { + return new Attempt(new InstanceNotFoundException("Could not find tree of type " + appTree.Alias)); + } + + var bTree = treeDef.CreateInstance(); + var treeParams = new ApplicationTreeApiController.TreeParams(); + + //we currently only support an integer id or a string id, we'll refactor how this works + //later but we'll get this working first + int startId; + if (int.TryParse(id, out startId)) + { + treeParams.StartNodeID = startId; + } + else + { + treeParams.NodeKey = id; + } + var xTree = new XmlTree(); + bTree.SetTreeParameters(treeParams); + bTree.Render(ref xTree); + + return new Attempt(true, LegacyTreeDataAdapter.ConvertFromLegacy(xTree, urlHelper)); + } + + } +} diff --git a/src/Umbraco.Web/Trees/LegacyTreeApiController.cs b/src/Umbraco.Web/Trees/LegacyTreeApiController.cs new file mode 100644 index 0000000000..4d5b2a4c14 --- /dev/null +++ b/src/Umbraco.Web/Trees/LegacyTreeApiController.cs @@ -0,0 +1,47 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Net.Http.Formatting; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; +using Umbraco.Web.WebApi.Filters; +using umbraco.BusinessLogic; +using umbraco.businesslogic; + +namespace Umbraco.Web.Trees +{ + //NOTE: We will of course have to authorized this but changing the base class once integrated + + /// + /// This is used to output JSON from legacy trees + /// + [PluginController("UmbracoTrees")] + public class LegacyTreeApiController : UmbracoApiController //UmbracoAuthorizedApiController + { + /// + /// Convert a legacy tree to a new tree result + /// + /// + /// + /// + [HttpQueryStringFilter("queryStrings")] + public TreeNodeCollection GetNodes(string id, FormDataCollection queryStrings) + { + //need to ensure we have a tree type + var treeType = queryStrings.GetRequiredString("treeType"); + //now we'll look up that tree + var tree = ApplicationTree.getByAlias(treeType); + if (tree == null) + throw new InvalidOperationException("No tree found with alias " + treeType); + + var attempt = tree.TryLoadFromLegacyTree(id, queryStrings, Url); + if (attempt.Success == false) + { + throw new ApplicationException("Could not render tree " + treeType + " for node id " + id); + } + + return attempt.Result; + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Trees/LegacyTreeDataAdapter.cs b/src/Umbraco.Web/Trees/LegacyTreeDataAdapter.cs index da34634d93..7b70d52a45 100644 --- a/src/Umbraco.Web/Trees/LegacyTreeDataAdapter.cs +++ b/src/Umbraco.Web/Trees/LegacyTreeDataAdapter.cs @@ -1,4 +1,7 @@ -using umbraco.cms.presentation.Trees; +using System; +using System.Web.Http.Routing; +using Umbraco.Core; +using umbraco.cms.presentation.Trees; namespace Umbraco.Web.Trees { @@ -8,7 +11,7 @@ namespace Umbraco.Web.Trees internal class LegacyTreeDataAdapter { - internal static TreeNodeCollection ConvertFromLegacy(XmlTree xmlTree) + internal static TreeNodeCollection ConvertFromLegacy(XmlTree xmlTree, UrlHelper urlHelper) { //TODO: Once we get the editor URL stuff working we'll need to figure out how to convert // that over to use the old school ui.xml stuff for these old trees and however the old menu items worked. @@ -16,7 +19,15 @@ namespace Umbraco.Web.Trees var collection = new TreeNodeCollection(); foreach (var x in xmlTree.treeCollection) { - var node = new TreeNode(x.NodeID, x.Source) + // /umbraco/tree.aspx?rnd=d0d0ff11a1c347dabfaa0fc75effcc2a&id=1046&treeType=content&contextMenu=false&isDialog=false + + //we need to convert the node source to our legacy tree controller + var source = urlHelper.GetUmbracoApiService("GetNodes"); + //append the query strings + var query = x.Source.Split(new[] {'?'}, StringSplitOptions.RemoveEmptyEntries); + source += query.Length > 1 ? query[1].EnsureStartsWith('?') : ""; + + var node = new TreeNode(x.NodeID, source) { HasChildren = x.HasChildren, Icon = x.Icon, diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 919337c88f..e41f527696 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -295,10 +295,12 @@ + + @@ -1870,7 +1872,9 @@ ASPXCodeBehind - + + ASPXCodeBehind +