From 44c8c4b5b80ea5ebea217cd0eb7c95f0dc27b820 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 18 Jan 2013 08:47:38 -0100 Subject: [PATCH 01/20] Revert 024896ba7bcf as it's a breaking change --- src/Umbraco.Web/WebBootManager.cs | 350 +++++++++++++++--------------- 1 file changed, 178 insertions(+), 172 deletions(-) diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 5c6d5684e7..b4aed9339d 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -21,206 +21,212 @@ using umbraco.cms.businesslogic; namespace Umbraco.Web { - /// - /// A bootstrapper for the Umbraco application which initializes all objects including the Web portion of the application - /// - internal class WebBootManager : CoreBootManager - { - private readonly bool _isForTesting; - private readonly UmbracoApplication _umbracoApplication; + /// + /// A bootstrapper for the Umbraco application which initializes all objects including the Web portion of the application + /// + internal class WebBootManager : CoreBootManager + { + private readonly bool _isForTesting; + private readonly UmbracoApplication _umbracoApplication; - public WebBootManager(UmbracoApplication umbracoApplication) - : this(umbracoApplication, false) - { - } + public WebBootManager(UmbracoApplication umbracoApplication) + : this(umbracoApplication, false) + { + } - /// - /// Constructor for unit tests, ensures some resolvers are not initialized - /// - /// - /// - internal WebBootManager(UmbracoApplication umbracoApplication, bool isForTesting) - { - _isForTesting = isForTesting; - _umbracoApplication = umbracoApplication; - if (umbracoApplication == null) throw new ArgumentNullException("umbracoApplication"); - } - - /// - /// Initialize objects before anything during the boot cycle happens - /// - /// - public override IBootManager Initialize() - { - base.Initialize(); + /// + /// Constructor for unit tests, ensures some resolvers are not initialized + /// + /// + /// + internal WebBootManager(UmbracoApplication umbracoApplication, bool isForTesting) + { + _isForTesting = isForTesting; + _umbracoApplication = umbracoApplication; + if (umbracoApplication == null) throw new ArgumentNullException("umbracoApplication"); + } - // Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK] - ClientDependency.Core.CompositeFiles.Providers.XmlFileMapper.FileMapVirtualFolder = "~/App_Data/TEMP/ClientDependency"; - ClientDependency.Core.CompositeFiles.Providers.BaseCompositeFileProcessingProvider.UrlTypeDefault = ClientDependency.Core.CompositeFiles.Providers.CompositeUrlType.Base64QueryStrings; + [Obsolete("This method was never supposed to be here and will be removed in v6.0.0")] + public void Boot() + { + InitializeResolvers(); + } - //set master controller factory - ControllerBuilder.Current.SetControllerFactory( - new MasterControllerFactory(FilteredControllerFactoriesResolver.Current)); + /// + /// Initialize objects before anything during the boot cycle happens + /// + /// + public override IBootManager Initialize() + { + base.Initialize(); - //set the render view engine - ViewEngines.Engines.Add(new RenderViewEngine()); - //set the plugin view engine - ViewEngines.Engines.Add(new PluginViewEngine()); + // Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK] + ClientDependency.Core.CompositeFiles.Providers.XmlFileMapper.FileMapVirtualFolder = "~/App_Data/TEMP/ClientDependency"; + ClientDependency.Core.CompositeFiles.Providers.BaseCompositeFileProcessingProvider.UrlTypeDefault = ClientDependency.Core.CompositeFiles.Providers.CompositeUrlType.Base64QueryStrings; - //set model binder - ModelBinders.Binders.Add(new KeyValuePair(typeof(RenderModel), new RenderModelBinder())); + //set master controller factory + ControllerBuilder.Current.SetControllerFactory( + new MasterControllerFactory(FilteredControllerFactoriesResolver.Current)); + + //set the render view engine + ViewEngines.Engines.Add(new RenderViewEngine()); + //set the plugin view engine + ViewEngines.Engines.Add(new PluginViewEngine()); + + //set model binder + ModelBinders.Binders.Add(new KeyValuePair(typeof(RenderModel), new RenderModelBinder())); - //find and initialize the application startup handlers, we need to initialize this resolver here because - //it is a special resolver where they need to be instantiated first before any other resolvers in order to bind to - //events and to call their events during bootup. - //ApplicationStartupHandler.RegisterHandlers(); - //... and set the special flag to let us resolve before frozen resolution - ApplicationEventsResolver.Current = new ApplicationEventsResolver( - PluginManager.Current.ResolveApplicationStartupHandlers()) - { - CanResolveBeforeFrozen = true - }; - //add the internal types since we don't want to mark these public - ApplicationEventsResolver.Current.AddType(); - ApplicationEventsResolver.Current.AddType(); + //find and initialize the application startup handlers, we need to initialize this resolver here because + //it is a special resolver where they need to be instantiated first before any other resolvers in order to bind to + //events and to call their events during bootup. + //ApplicationStartupHandler.RegisterHandlers(); + //... and set the special flag to let us resolve before frozen resolution + ApplicationEventsResolver.Current = new ApplicationEventsResolver( + PluginManager.Current.ResolveApplicationStartupHandlers()) + { + CanResolveBeforeFrozen = true + }; + //add the internal types since we don't want to mark these public + ApplicationEventsResolver.Current.AddType(); + ApplicationEventsResolver.Current.AddType(); - //now we need to call the initialize methods - ApplicationEventsResolver.Current.ApplicationEventHandlers - .ForEach(x => x.OnApplicationInitialized(_umbracoApplication, ApplicationContext)); + //now we need to call the initialize methods + ApplicationEventsResolver.Current.ApplicationEventHandlers + .ForEach(x => x.OnApplicationInitialized(_umbracoApplication, ApplicationContext)); - return this; - } + return this; + } - /// - /// Ensure that the OnApplicationStarting methods of the IApplicationEvents are called - /// - /// - /// - public override IBootManager Startup(Action afterStartup) - { - base.Startup(afterStartup); + /// + /// Ensure that the OnApplicationStarting methods of the IApplicationEvents are called + /// + /// + /// + public override IBootManager Startup(Action afterStartup) + { + base.Startup(afterStartup); - //call OnApplicationStarting of each application events handler - ApplicationEventsResolver.Current.ApplicationEventHandlers - .ForEach(x => x.OnApplicationStarting(_umbracoApplication, ApplicationContext)); + //call OnApplicationStarting of each application events handler + ApplicationEventsResolver.Current.ApplicationEventHandlers + .ForEach(x => x.OnApplicationStarting(_umbracoApplication, ApplicationContext)); - return this; - } + return this; + } - /// - /// Ensure that the OnApplicationStarted methods of the IApplicationEvents are called - /// - /// - /// - public override IBootManager Complete(Action afterComplete) - { - //set routes - CreateRoutes(); + /// + /// Ensure that the OnApplicationStarted methods of the IApplicationEvents are called + /// + /// + /// + public override IBootManager Complete(Action afterComplete) + { + //set routes + CreateRoutes(); - base.Complete(afterComplete); + base.Complete(afterComplete); - //call OnApplicationStarting of each application events handler - ApplicationEventsResolver.Current.ApplicationEventHandlers - .ForEach(x => x.OnApplicationStarted(_umbracoApplication, ApplicationContext)); + //call OnApplicationStarting of each application events handler + ApplicationEventsResolver.Current.ApplicationEventHandlers + .ForEach(x => x.OnApplicationStarted(_umbracoApplication, ApplicationContext)); - // we're ready to serve content! - ApplicationContext.IsReady = true; + // we're ready to serve content! + ApplicationContext.IsReady = true; - return this; - } + return this; + } - /// - /// Creates the routes - /// - protected internal void CreateRoutes() - { - var umbracoPath = GlobalSettings.UmbracoMvcArea; + /// + /// Creates the routes + /// + protected internal void CreateRoutes() + { + var umbracoPath = GlobalSettings.UmbracoMvcArea; - //Create the front-end route - var defaultRoute = RouteTable.Routes.MapRoute( - "Umbraco_default", - "Umbraco/RenderMvc/{action}/{id}", - new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional } - ); - defaultRoute.RouteHandler = new RenderRouteHandler(ControllerBuilder.Current.GetControllerFactory()); + //Create the front-end route + var defaultRoute = RouteTable.Routes.MapRoute( + "Umbraco_default", + "Umbraco/RenderMvc/{action}/{id}", + new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional } + ); + defaultRoute.RouteHandler = new RenderRouteHandler(ControllerBuilder.Current.GetControllerFactory()); - //Create the install routes - var installPackageRoute = RouteTable.Routes.MapRoute( - "Umbraco_install_packages", - "Install/PackageInstaller/{action}/{id}", - new { controller = "InstallPackage", action = "Index", id = UrlParameter.Optional } - ); - installPackageRoute.DataTokens.Add("area", umbracoPath); + //Create the install routes + var installPackageRoute = RouteTable.Routes.MapRoute( + "Umbraco_install_packages", + "Install/PackageInstaller/{action}/{id}", + new { controller = "InstallPackage", action = "Index", id = UrlParameter.Optional } + ); + installPackageRoute.DataTokens.Add("area", umbracoPath); - //we need to find the surface controllers and route them - var surfaceControllers = SurfaceControllerResolver.Current.RegisteredSurfaceControllers.ToArray(); + //we need to find the surface controllers and route them + var surfaceControllers = SurfaceControllerResolver.Current.RegisteredSurfaceControllers.ToArray(); - //local surface controllers do not contain the attribute - var localSurfaceControlleres = surfaceControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace()); - foreach (var s in localSurfaceControlleres) - { - var meta = PluginController.GetMetadata(s); - var route = RouteTable.Routes.MapRoute( - string.Format("umbraco-{0}-{1}", "surface", meta.ControllerName), - umbracoPath + "/Surface/" + meta.ControllerName + "/{action}/{id}",//url to match - new { controller = meta.ControllerName, action = "Index", id = UrlParameter.Optional }, - new[] { meta.ControllerNamespace }); //only match this namespace - route.DataTokens.Add("umbraco", "surface"); //ensure the umbraco token is set - } - - //need to get the plugin controllers that are unique to each area (group by) - //TODO: One day when we have more plugin controllers, we will need to do a group by on ALL of them to pass into the ctor of PluginControllerArea - var pluginSurfaceControlleres = surfaceControllers.Where(x => !PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace()); - var groupedAreas = pluginSurfaceControlleres.GroupBy(controller => PluginController.GetMetadata(controller).AreaName); - //loop through each area defined amongst the controllers - foreach(var g in groupedAreas) - { - //create an area for the controllers (this will throw an exception if all controllers are not in the same area) - var pluginControllerArea = new PluginControllerArea(g.Select(PluginController.GetMetadata)); - //register it - RouteTable.Routes.RegisterArea(pluginControllerArea); - } - } + //local surface controllers do not contain the attribute + var localSurfaceControlleres = surfaceControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace()); + foreach (var s in localSurfaceControlleres) + { + var meta = PluginController.GetMetadata(s); + var route = RouteTable.Routes.MapRoute( + string.Format("umbraco-{0}-{1}", "surface", meta.ControllerName), + umbracoPath + "/Surface/" + meta.ControllerName + "/{action}/{id}",//url to match + new { controller = meta.ControllerName, action = "Index", id = UrlParameter.Optional }, + new[] { meta.ControllerNamespace }); //only match this namespace + route.DataTokens.Add("umbraco", "surface"); //ensure the umbraco token is set + } - + //need to get the plugin controllers that are unique to each area (group by) + //TODO: One day when we have more plugin controllers, we will need to do a group by on ALL of them to pass into the ctor of PluginControllerArea + var pluginSurfaceControlleres = surfaceControllers.Where(x => !PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace()); + var groupedAreas = pluginSurfaceControlleres.GroupBy(controller => PluginController.GetMetadata(controller).AreaName); + //loop through each area defined amongst the controllers + foreach (var g in groupedAreas) + { + //create an area for the controllers (this will throw an exception if all controllers are not in the same area) + var pluginControllerArea = new PluginControllerArea(g.Select(PluginController.GetMetadata)); + //register it + RouteTable.Routes.RegisterArea(pluginControllerArea); + } + } - /// - /// Initializes all web based and core resolves - /// - protected override void InitializeResolvers() - { - base.InitializeResolvers(); - //TODO: This needs to be removed in future versions (i.e. 6.0 when the PublishedContentHelper can access the business logic) - // see the TODO noted in the PublishedContentHelper. - PublishedContentHelper.GetDataTypeCallback = ContentType.GetDataType; - SurfaceControllerResolver.Current = new SurfaceControllerResolver( - PluginManager.Current.ResolveSurfaceControllers()); + /// + /// Initializes all web based and core resolves + /// + protected override void InitializeResolvers() + { + base.InitializeResolvers(); - //the base creates the PropertyEditorValueConvertersResolver but we want to modify it in the web app and replace - //the TinyMcePropertyEditorValueConverter with the RteMacroRenderingPropertyEditorValueConverter - PropertyEditorValueConvertersResolver.Current.RemoveType(); - PropertyEditorValueConvertersResolver.Current.AddType(); + //TODO: This needs to be removed in future versions (i.e. 6.0 when the PublishedContentHelper can access the business logic) + // see the TODO noted in the PublishedContentHelper. + PublishedContentHelper.GetDataTypeCallback = ContentType.GetDataType; - PublishedContentStoreResolver.Current = new PublishedContentStoreResolver(new DefaultPublishedContentStore()); - PublishedMediaStoreResolver.Current = new PublishedMediaStoreResolver(new DefaultPublishedMediaStore()); + SurfaceControllerResolver.Current = new SurfaceControllerResolver( + PluginManager.Current.ResolveSurfaceControllers()); - FilteredControllerFactoriesResolver.Current = new FilteredControllerFactoriesResolver( - //add all known factories, devs can then modify this list on application startup either by binding to events - //or in their own global.asax - new[] + //the base creates the PropertyEditorValueConvertersResolver but we want to modify it in the web app and replace + //the TinyMcePropertyEditorValueConverter with the RteMacroRenderingPropertyEditorValueConverter + PropertyEditorValueConvertersResolver.Current.RemoveType(); + PropertyEditorValueConvertersResolver.Current.AddType(); + + PublishedContentStoreResolver.Current = new PublishedContentStoreResolver(new DefaultPublishedContentStore()); + PublishedMediaStoreResolver.Current = new PublishedMediaStoreResolver(new DefaultPublishedMediaStore()); + + FilteredControllerFactoriesResolver.Current = new FilteredControllerFactoriesResolver( + //add all known factories, devs can then modify this list on application startup either by binding to events + //or in their own global.asax + new[] { typeof (RenderControllerFactory) }); - LastChanceLookupResolver.Current = new LastChanceLookupResolver(new DefaultLastChanceLookup()); + LastChanceLookupResolver.Current = new LastChanceLookupResolver(new DefaultLastChanceLookup()); - DocumentLookupsResolver.Current = new DocumentLookupsResolver( - //add all known resolvers in the correct order, devs can then modify this list on application startup either by binding to events - //or in their own global.asax - new[] + DocumentLookupsResolver.Current = new DocumentLookupsResolver( + //add all known resolvers in the correct order, devs can then modify this list on application startup either by binding to events + //or in their own global.asax + new[] { typeof (LookupByPageIdQuery), typeof (LookupByNiceUrl), @@ -230,18 +236,18 @@ namespace Umbraco.Web typeof (LookupByAlias) }); - RoutesCacheResolver.Current = new RoutesCacheResolver(new DefaultRoutesCache(_isForTesting == false)); + RoutesCacheResolver.Current = new RoutesCacheResolver(new DefaultRoutesCache(_isForTesting == false)); - ThumbnailProvidersResolver.Current = new ThumbnailProvidersResolver( - PluginManager.Current.ResolveThumbnailProviders()); + ThumbnailProvidersResolver.Current = new ThumbnailProvidersResolver( + PluginManager.Current.ResolveThumbnailProviders()); ImageUrlProviderResolver.Current = new ImageUrlProviderResolver( PluginManager.Current.ResolveImageUrlProviders()); - CultureDictionaryFactoryResolver.Current = new CultureDictionaryFactoryResolver( - new DefaultCultureDictionaryFactory()); + CultureDictionaryFactoryResolver.Current = new CultureDictionaryFactoryResolver( + new DefaultCultureDictionaryFactory()); - } + } - } + } } From e5878554bd8de41e1e802c8e1da4a2f213ded59c Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 21 Jan 2013 14:21:29 -0100 Subject: [PATCH 02/20] Fixes U4-1482 Regression - RTE unable to edit hyperlink on image --- .../tinymce3/plugins/umbracolink/js/umbracolink.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracolink/js/umbracolink.js b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracolink/js/umbracolink.js index f2c540ea60..b0cce49bc1 100644 --- a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracolink/js/umbracolink.js +++ b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracolink/js/umbracolink.js @@ -73,6 +73,7 @@ function init() { * EO UMBRACO SPECIFIC */ + elm = inst.dom.getParent(elm, "A"); if (elm != null && elm.nodeName == "A") action = "update"; From 6cb3fcf9ad7d4e844f94500ec7212419f210e9bd Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 8 Jan 2013 16:41:31 -0100 Subject: [PATCH 03/20] U4-1411 - fix post-4.9 regression in NotFoundHandler url --- .../Routing/DefaultLastChanceLookup.cs | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Routing/DefaultLastChanceLookup.cs b/src/Umbraco.Web/Routing/DefaultLastChanceLookup.cs index 4c9b4fa103..674a6e64a4 100644 --- a/src/Umbraco.Web/Routing/DefaultLastChanceLookup.cs +++ b/src/Umbraco.Web/Routing/DefaultLastChanceLookup.cs @@ -46,16 +46,66 @@ namespace Umbraco.Web.Routing //FIXME: this is temporary and should be obsoleted + string GetLegacyUrlForNotFoundHandlers(PublishedContentRequest docRequest) + { + // that's not backward-compatible because when requesting "/foo.aspx" + // 4.9 : url = "foo.aspx" + // 4.10 : url = "/foo" + //return docRequest.Uri.AbsolutePath; + + // so we have to run the legacy code for url preparation :-( + + // code from requestModule.UmbracoRewrite + string tmp = HttpContext.Current.Request.Path.ToLower(); + + // note: requestModule.UmbracoRewrite also does some confusing stuff + // with stripping &umbPage from the querystring?! ignored. + + // code from requestHandler.cleanUrl + string root = Umbraco.Core.IO.SystemDirectories.Root.ToLower(); + if (!string.IsNullOrEmpty(root) && tmp.StartsWith(root)) + tmp = tmp.Substring(root.Length); + tmp = tmp.TrimEnd('/'); + if (tmp == "/default.aspx") + tmp = string.Empty; + else if (tmp == root) + tmp = string.Empty; + + // code from UmbracoDefault.Page_PreInit + if (tmp != "" && HttpContext.Current.Request["umbPageID"] == null) + { + string tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty); + int result; + if (int.TryParse(tryIntParse, out result)) + tmp = tmp.Replace(".aspx", string.Empty); + } + else if (!string.IsNullOrEmpty(HttpContext.Current.Request["umbPageID"])) + { + int result; + if (int.TryParse(HttpContext.Current.Request["umbPageID"], out result)) + { + tmp = HttpContext.Current.Request["umbPageID"]; + } + } + + // code from requestHandler.ctor + if (tmp != "") + tmp = tmp.Substring(1); + + return tmp; + } + IPublishedContent HandlePageNotFound(PublishedContentRequest docRequest) { LogHelper.Debug("Running for url='{0}'.", () => docRequest.Uri.AbsolutePath); //XmlNode currentPage = null; IPublishedContent currentPage = null; + var url = GetLegacyUrlForNotFoundHandlers(docRequest); foreach (var handler in GetNotFoundHandlers()) { - if (handler.Execute(docRequest.Uri.AbsolutePath) && handler.redirectID > 0) + if (handler.Execute(url) && handler.redirectID > 0) { //currentPage = umbracoContent.GetElementById(handler.redirectID.ToString()); currentPage = docRequest.RoutingContext.PublishedContentStore.GetDocumentById( From dec5e8ad6ccd7ceb9d664522abbaf596d042e952 Mon Sep 17 00:00:00 2001 From: "pcw@pcw-PC.shout.local" Date: Tue, 15 Jan 2013 20:07:07 +0000 Subject: [PATCH 04/20] Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit http://issues.umbraco.org/issue/U4-1455 --- src/Umbraco.Core/StringExtensions.cs | 53 ++++++++++++++++--- src/Umbraco.Web/HtmlHelperRenderExtensions.cs | 6 +-- src/Umbraco.Web/Mvc/RenderRouteHandler.cs | 4 +- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index 3250a21d24..16fea11539 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -22,23 +22,60 @@ namespace Umbraco.Core /// /// Encrypt the string using the MachineKey in medium trust /// - /// + /// The string value to be encrypted. /// - public static string EncryptWithMachineKey(this string toEncrypt) + public static string EncryptWithMachineKey(this string value) { - var output = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(0, "temp", DateTime.Now, DateTime.MaxValue, false, toEncrypt)); - return output; + if (value == null) + return null; + + string valueToEncrypt = value; + List parts = new List(); + + const int EncrpytBlockSize = 500; + + while (valueToEncrypt.Length > EncrpytBlockSize) + { + parts.Add(valueToEncrypt.Substring(0, EncrpytBlockSize)); + valueToEncrypt = valueToEncrypt.Remove(0, EncrpytBlockSize); + } + + if (valueToEncrypt.Length > 0) + { + parts.Add(valueToEncrypt); + } + + StringBuilder encrpytedValue = new StringBuilder(); + + foreach (var part in parts) + { + var encrpytedBlock = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(1, string.Empty, DateTime.Now, DateTime.Now, false, part)); + encrpytedValue.AppendLine(encrpytedBlock); + } + + return encrpytedValue.ToString().TrimEnd(); } /// /// Decrypt the encrypted string using the Machine key in medium trust /// - /// + /// The string value to be decrypted /// - public static string DecryptWithMachineKey(this string encrypted) + public static string DecryptWithMachineKey(this string value) { - var output = FormsAuthentication.Decrypt(encrypted); - return output.UserData; + if (value == null) + return null; + + string[] parts = value.Split('\n'); + + StringBuilder decryptedValue = new StringBuilder(); + + foreach (var part in parts) + { + decryptedValue.Append(FormsAuthentication.Decrypt(part.TrimEnd()).UserData); + } + + return decryptedValue.ToString(); } //this is from SqlMetal and just makes it a bit of fun to allow pluralisation diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index cec5267497..f64282d73f 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -119,7 +119,7 @@ namespace Umbraco.Web if (!string.IsNullOrWhiteSpace(surfaceRouteParams)) { - _base64String = Convert.ToBase64String(Encoding.UTF8.GetBytes(surfaceRouteParams)); + _encryptedString = surfaceRouteParams.EncryptWithMachineKey(); } _textWriter = viewContext.Writer; @@ -127,7 +127,7 @@ namespace Umbraco.Web private bool _disposed; - private readonly string _base64String; + private readonly string _encryptedString; private readonly TextWriter _textWriter; protected override void Dispose(bool disposing) @@ -137,7 +137,7 @@ namespace Umbraco.Web this._disposed = true; //write out the hidden surface form routes - _textWriter.Write(""); + _textWriter.Write(""); base.Dispose(disposing); } diff --git a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs index 73a0916c36..fab342df7b 100644 --- a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs +++ b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs @@ -115,8 +115,8 @@ namespace Umbraco.Web.Mvc return null; var encodedVal = requestContext.HttpContext.Request["uformpostroutevals"]; - var decodedString = Encoding.UTF8.GetString(Convert.FromBase64String(encodedVal)); - var parsedQueryString = HttpUtility.ParseQueryString(decodedString); + var decryptedString = encodedVal.DecryptWithMachineKey(); + var parsedQueryString = HttpUtility.ParseQueryString(decryptedString); var decodedParts = new Dictionary(); From f4f91fba78ad539c903369fbca9e309797d2eac0 Mon Sep 17 00:00:00 2001 From: "pcw@pcw-PC.shout.local" Date: Tue, 15 Jan 2013 20:09:29 +0000 Subject: [PATCH 05/20] Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit http://issues.umbraco.org/issue/U4-1455 --- src/Umbraco.Tests/StringExtensionsTests.cs | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/StringExtensionsTests.cs b/src/Umbraco.Tests/StringExtensionsTests.cs index c00b3cebac..fe356018f2 100644 --- a/src/Umbraco.Tests/StringExtensionsTests.cs +++ b/src/Umbraco.Tests/StringExtensionsTests.cs @@ -4,6 +4,7 @@ using System.Security; using System.Text; using NUnit.Framework; using Umbraco.Core; +using System.Security.Cryptography; namespace Umbraco.Tests { @@ -11,7 +12,10 @@ namespace Umbraco.Tests public class StringExtensionsTests { - [TestCase("This is a string to encrypt")] + [TestCase("This is a string to encrypt")] + [TestCase("This is a string to encrypt\nThis is a second line")] + [TestCase(" White space is preserved ")] + [TestCase("\nWhite space is preserved\n")] public void Encrypt_And_Decrypt(string input) { var encrypted = input.EncryptWithMachineKey(); @@ -20,6 +24,25 @@ namespace Umbraco.Tests Assert.AreEqual(input, decrypted); } + [Test()] + public void Encrypt_And_Decrypt_Long_Value() + { + // Generate a really long string + char[] chars = { 'a', 'b', 'c', '1', '2', '3', '\n' }; + + string valueToTest = string.Empty; + + // Create a string 7035 chars long + for (int i = 0; i < 1005; i++) + for (int j = 0; j < chars.Length; j++) + valueToTest += chars[j].ToString(); + + var encrypted = valueToTest.ToString().EncryptWithMachineKey(); + var decrypted = encrypted.DecryptWithMachineKey(); + Assert.AreNotEqual(valueToTest, encrypted); + Assert.AreEqual(valueToTest, decrypted); + } + [TestCase("Hello this is my string", " string", "Hello this is my")] [TestCase("Hello this is my string strung", " string", "Hello this is my string strung")] [TestCase("Hello this is my string string", " string", "Hello this is my")] From 021cb817d4c2474f8fd4beb58acc2728df311ab3 Mon Sep 17 00:00:00 2001 From: "pcw@pcw-PC.shout.local" Date: Tue, 15 Jan 2013 20:17:12 +0000 Subject: [PATCH 06/20] Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit http://issues.umbraco.org/issue/U4-1455 --- src/Umbraco.Core/StringExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index 16fea11539..9413225622 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -49,7 +49,7 @@ namespace Umbraco.Core foreach (var part in parts) { - var encrpytedBlock = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(1, string.Empty, DateTime.Now, DateTime.Now, false, part)); + var encrpytedBlock = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(0, string.Empty, DateTime.Now, DateTime.MaxValue, false, part)); encrpytedValue.AppendLine(encrpytedBlock); } From 44360d83aa94d14c9552a91f6b51665ef4bb50b3 Mon Sep 17 00:00:00 2001 From: "pcw@pcw-PC.shout.local" Date: Tue, 15 Jan 2013 20:20:05 +0000 Subject: [PATCH 07/20] Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit http://issues.umbraco.org/issue/U4-1455 --- src/Umbraco.Tests/StringExtensionsTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Tests/StringExtensionsTests.cs b/src/Umbraco.Tests/StringExtensionsTests.cs index fe356018f2..c0f3634a04 100644 --- a/src/Umbraco.Tests/StringExtensionsTests.cs +++ b/src/Umbraco.Tests/StringExtensionsTests.cs @@ -4,7 +4,6 @@ using System.Security; using System.Text; using NUnit.Framework; using Umbraco.Core; -using System.Security.Cryptography; namespace Umbraco.Tests { From ac5142443a660eb2d041968b5d21bb2bc702c566 Mon Sep 17 00:00:00 2001 From: "pcw@pcw-PC.shout.local" Date: Tue, 15 Jan 2013 20:40:28 +0000 Subject: [PATCH 08/20] Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit http://issues.umbraco.org/issue/U4-1455 --- src/Umbraco.Core/StringExtensions.cs | 52 ++++++++++++++++--- src/Umbraco.Tests/StringExtensionsTests.cs | 24 ++++++++- src/Umbraco.Web/HtmlHelperRenderExtensions.cs | 6 +-- src/Umbraco.Web/Mvc/RenderRouteHandler.cs | 4 +- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index 3250a21d24..2ff10f04e8 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -23,22 +23,60 @@ namespace Umbraco.Core /// Encrypt the string using the MachineKey in medium trust /// /// + /// The string value to be encrypted. /// - public static string EncryptWithMachineKey(this string toEncrypt) + public static string EncryptWithMachineKey(this string value) { - var output = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(0, "temp", DateTime.Now, DateTime.MaxValue, false, toEncrypt)); - return output; + if (value == null) + return null; + + string valueToEncrypt = value; + List parts = new List(); + + const int EncrpytBlockSize = 500; + + while (valueToEncrypt.Length > EncrpytBlockSize) + { + parts.Add(valueToEncrypt.Substring(0, EncrpytBlockSize)); + valueToEncrypt = valueToEncrypt.Remove(0, EncrpytBlockSize); + } + + if (valueToEncrypt.Length > 0) + { + parts.Add(valueToEncrypt); + } + + StringBuilder encrpytedValue = new StringBuilder(); + + foreach (var part in parts) + { + var encrpytedBlock = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(0, string.Empty, DateTime.Now, DateTime.MaxValue, false, part)); + encrpytedValue.AppendLine(encrpytedBlock); + } + + return encrpytedValue.ToString().TrimEnd(); } /// /// Decrypt the encrypted string using the Machine key in medium trust /// - /// + /// The string value to be decrypted /// - public static string DecryptWithMachineKey(this string encrypted) + public static string DecryptWithMachineKey(this string value) { - var output = FormsAuthentication.Decrypt(encrypted); - return output.UserData; + if (value == null) + return null; + + string[] parts = value.Split('\n'); + + StringBuilder decryptedValue = new StringBuilder(); + + foreach (var part in parts) + { + decryptedValue.Append(FormsAuthentication.Decrypt(part.TrimEnd()).UserData); + } + + return decryptedValue.ToString(); } //this is from SqlMetal and just makes it a bit of fun to allow pluralisation diff --git a/src/Umbraco.Tests/StringExtensionsTests.cs b/src/Umbraco.Tests/StringExtensionsTests.cs index c00b3cebac..c0f3634a04 100644 --- a/src/Umbraco.Tests/StringExtensionsTests.cs +++ b/src/Umbraco.Tests/StringExtensionsTests.cs @@ -11,7 +11,10 @@ namespace Umbraco.Tests public class StringExtensionsTests { - [TestCase("This is a string to encrypt")] + [TestCase("This is a string to encrypt")] + [TestCase("This is a string to encrypt\nThis is a second line")] + [TestCase(" White space is preserved ")] + [TestCase("\nWhite space is preserved\n")] public void Encrypt_And_Decrypt(string input) { var encrypted = input.EncryptWithMachineKey(); @@ -20,6 +23,25 @@ namespace Umbraco.Tests Assert.AreEqual(input, decrypted); } + [Test()] + public void Encrypt_And_Decrypt_Long_Value() + { + // Generate a really long string + char[] chars = { 'a', 'b', 'c', '1', '2', '3', '\n' }; + + string valueToTest = string.Empty; + + // Create a string 7035 chars long + for (int i = 0; i < 1005; i++) + for (int j = 0; j < chars.Length; j++) + valueToTest += chars[j].ToString(); + + var encrypted = valueToTest.ToString().EncryptWithMachineKey(); + var decrypted = encrypted.DecryptWithMachineKey(); + Assert.AreNotEqual(valueToTest, encrypted); + Assert.AreEqual(valueToTest, decrypted); + } + [TestCase("Hello this is my string", " string", "Hello this is my")] [TestCase("Hello this is my string strung", " string", "Hello this is my string strung")] [TestCase("Hello this is my string string", " string", "Hello this is my")] diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index cec5267497..f64282d73f 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -119,7 +119,7 @@ namespace Umbraco.Web if (!string.IsNullOrWhiteSpace(surfaceRouteParams)) { - _base64String = Convert.ToBase64String(Encoding.UTF8.GetBytes(surfaceRouteParams)); + _encryptedString = surfaceRouteParams.EncryptWithMachineKey(); } _textWriter = viewContext.Writer; @@ -127,7 +127,7 @@ namespace Umbraco.Web private bool _disposed; - private readonly string _base64String; + private readonly string _encryptedString; private readonly TextWriter _textWriter; protected override void Dispose(bool disposing) @@ -137,7 +137,7 @@ namespace Umbraco.Web this._disposed = true; //write out the hidden surface form routes - _textWriter.Write(""); + _textWriter.Write(""); base.Dispose(disposing); } diff --git a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs index 73a0916c36..fab342df7b 100644 --- a/src/Umbraco.Web/Mvc/RenderRouteHandler.cs +++ b/src/Umbraco.Web/Mvc/RenderRouteHandler.cs @@ -115,8 +115,8 @@ namespace Umbraco.Web.Mvc return null; var encodedVal = requestContext.HttpContext.Request["uformpostroutevals"]; - var decodedString = Encoding.UTF8.GetString(Convert.FromBase64String(encodedVal)); - var parsedQueryString = HttpUtility.ParseQueryString(decodedString); + var decryptedString = encodedVal.DecryptWithMachineKey(); + var parsedQueryString = HttpUtility.ParseQueryString(decryptedString); var decodedParts = new Dictionary(); From 1568e5f19c0ed29a20a61e0c3b7afced56f15651 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 23 Jan 2013 01:44:01 +0300 Subject: [PATCH 09/20] updated comments. --- src/Umbraco.Core/StringExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index 3d7bf8d504..9413225622 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -23,7 +23,6 @@ namespace Umbraco.Core /// Encrypt the string using the MachineKey in medium trust /// /// The string value to be encrypted. - /// The string value to be encrypted. /// public static string EncryptWithMachineKey(this string value) { From aea1a03453241f9a4ee0c9cd44f35e881c5ec7d1 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 23 Jan 2013 07:45:00 +0300 Subject: [PATCH 10/20] Updates ManyObjectsResolverBase to properly check for resolution freezing and fixes a few issues found regarding inheritance in complex situations like the new LazyManyObjectsResolverBase. Creates the new LazyManyObjectsResolverBase to lazily resolve types in order to create them. This is for work item : #U4-1522 Adds unit test to support. --- .../LazyManyObjectsResolverbase.cs | 148 ++++++++++++++++++ .../MacroFieldEditorsResolver.cs | 3 +- .../ManyObjectsResolverBase.cs | 148 +++++++++++++----- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Resolvers/LazyManyObjectResolverTests.cs | 84 ++++++++++ .../Resolvers/ManyObjectResolverTests.cs | 2 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 7 files changed, 343 insertions(+), 44 deletions(-) create mode 100644 src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs create mode 100644 src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs diff --git a/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs b/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs new file mode 100644 index 0000000000..a71d0a3f1e --- /dev/null +++ b/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Umbraco.Core.ObjectResolution +{ + internal abstract class LazyManyObjectsResolverBase : ManyObjectsResolverBase + where TResolved : class + where TResolver : class + { + #region Constructors + + protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application) + : base(scope) + { + } + + protected LazyManyObjectsResolverBase(HttpContextBase httpContext) + : base(httpContext) + { + } + + protected LazyManyObjectsResolverBase(IEnumerable> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) + : this(scope) + { + AddTypes(value); + } + + protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable> value) + : this(httpContext) + { + + } + #endregion + + private readonly List> _lazyTypes = new List>(); + private bool _hasResolvedTypes = false; + + /// + /// Used for unit tests + /// + internal bool HasResolvedTypes + { + get { return _hasResolvedTypes; } + } + + /// + /// Once this is called this will resolve all types registered in the lazy list + /// + protected override IEnumerable InstanceTypes + { + get + { + var list = _lazyTypes.Select(x => x.Value).ToArray(); + + //we need to validate each resolved type now since we could not do it before when inserting the lazy delegates + if (!_hasResolvedTypes) + { + var uniqueList = new List(); + foreach (var l in list) + { + EnsureCorrectType(l); + if (uniqueList.Contains(l)) + { + throw new InvalidOperationException("The Type " + l + " already exists in the collection"); + } + uniqueList.Add(l); + } + _hasResolvedTypes = true; + } + + return list; + } + } + + protected void AddTypes(IEnumerable> types) + { + EnsureAddSupport(); + + EnsureResolutionNotFrozen(); + + using (GetWriteLock()) + { + foreach (var t in types) + { + _lazyTypes.Add(t); + } + } + } + + /// + /// Adds a lazy type to the list + /// + /// + public void AddType(Lazy value) + { + EnsureAddSupport(); + + EnsureResolutionNotFrozen(); + + using (GetWriteLock()) + { + _lazyTypes.Add(value); + } + } + + /// + /// Converts the static type added to a lazy type and adds it to the internal list + /// + /// + public override void AddType(Type value) + { + AddType(new Lazy(() => value)); + } + + /// + /// Clears all lazy types + /// + public override void Clear() + { + EnsureClearSupport(); + + EnsureResolutionNotFrozen(); + + using (GetWriteLock()) + { + _lazyTypes.Clear(); + } + } + + /// + /// Does not support removal + /// + protected override bool SupportsRemove + { + get { return false; } + } + + /// + /// Does not support insert + /// + protected override bool SupportsInsert + { + get { return false; } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/ObjectResolution/MacroFieldEditorsResolver.cs b/src/Umbraco.Core/ObjectResolution/MacroFieldEditorsResolver.cs index 348ed699d3..9143e39f90 100644 --- a/src/Umbraco.Core/ObjectResolution/MacroFieldEditorsResolver.cs +++ b/src/Umbraco.Core/ObjectResolution/MacroFieldEditorsResolver.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Web; using System.Web.UI; using Umbraco.Core.Macros; @@ -56,7 +57,7 @@ namespace Umbraco.Core.ObjectResolution /// internal List MacroControlTypes { - get { return InstanceTypes; } + get { return InstanceTypes.ToList(); } } /// diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs index 2172fe9102..9343b1a58b 100644 --- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs @@ -6,14 +6,14 @@ using System.Web; namespace Umbraco.Core.ObjectResolution { - internal abstract class ManyObjectsResolverBase : ResolverBase where TResolved : class where TResolver : class { private List _applicationInstances = null; private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); - + private readonly List _instanceTypes = new List(); + #region Constructors @@ -34,7 +34,7 @@ namespace Umbraco.Core.ObjectResolution } LifetimeScope = scope; - InstanceTypes = new List(); + _instanceTypes = new List(); } /// @@ -48,7 +48,7 @@ namespace Umbraco.Core.ObjectResolution if (httpContext == null) throw new ArgumentNullException("httpContext"); LifetimeScope = ObjectLifetimeScope.HttpRequest; CurrentHttpContext = httpContext; - InstanceTypes = new List(); + _instanceTypes = new List(); } /// @@ -58,8 +58,8 @@ namespace Umbraco.Core.ObjectResolution /// If set to true will resolve singleton objects which will be created once for the lifetime of the application protected ManyObjectsResolverBase(IEnumerable value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) : this(scope) - { - InstanceTypes = new List(value); + { + _instanceTypes = new List(value); } /// @@ -71,7 +71,7 @@ namespace Umbraco.Core.ObjectResolution protected ManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable value) : this(httpContext) { - InstanceTypes = new List(value); + _instanceTypes = new List(value); } #endregion @@ -83,7 +83,10 @@ namespace Umbraco.Core.ObjectResolution /// /// Returns the list of Types registered that instances will be created from /// - protected List InstanceTypes { get; private set; } + protected virtual IEnumerable InstanceTypes + { + get { return _instanceTypes; } + } /// /// Returns the Current HttpContextBase used to construct this object if one exists. @@ -97,11 +100,7 @@ namespace Umbraco.Core.ObjectResolution protected ObjectLifetimeScope LifetimeScope { get; private set; } private int _defaultPluginWeight = 10; - private bool _supportsAdd = true; - private bool _supportsInsert = true; - private bool _supportsClear = true; - private bool _supportsRemove = true; - + /// /// Used in conjunction with GetSortedValues and WeightedPluginAttribute, if any of the objects /// being resolved do not contain the WeightedPluginAttribute then this will be the default weight applied @@ -189,15 +188,16 @@ namespace Umbraco.Core.ObjectResolution /// Removes a type. /// /// The type to remove. - public void RemoveType(Type value) + public virtual void RemoveType(Type value) { - if (!SupportsRemove) - throw new InvalidOperationException("This resolver does not support Removing types"); + EnsureRemoveSupport(); - using (new WriteLock(_lock)) + EnsureResolutionNotFrozen(); + + using (GetWriteLock()) { EnsureCorrectType(value); - InstanceTypes.Remove(value); + _instanceTypes.Remove(value); } } @@ -215,8 +215,12 @@ namespace Umbraco.Core.ObjectResolution /// /// protected void AddTypes(IEnumerable types) - { - using (var l = new WriteLock(_lock)) + { + EnsureAddSupport(); + + EnsureResolutionNotFrozen(); + + using (GetWriteLock()) { foreach(var t in types) { @@ -225,7 +229,7 @@ namespace Umbraco.Core.ObjectResolution { throw new InvalidOperationException("The Type " + t + " already exists in the collection"); }; - InstanceTypes.Add(t); + _instanceTypes.Add(t); } } } @@ -234,19 +238,20 @@ namespace Umbraco.Core.ObjectResolution /// Adds a Type to the end of the list. /// /// The object to be added. - public void AddType(Type value) + public virtual void AddType(Type value) { - if (!SupportsAdd) - throw new InvalidOperationException("This resolver does not support Adding new types"); + EnsureAddSupport(); - using (var l = new WriteLock(_lock)) + EnsureResolutionNotFrozen(); + + using (GetWriteLock()) { EnsureCorrectType(value); if (InstanceTypes.Contains(value)) { throw new InvalidOperationException("The Type " + value + " already exists in the collection"); }; - InstanceTypes.Add(value); + _instanceTypes.Add(value); } } @@ -262,14 +267,15 @@ namespace Umbraco.Core.ObjectResolution /// /// Clears the list. /// - public void Clear() + public virtual void Clear() { - if (!SupportsClear) - throw new InvalidOperationException("This resolver does not support Clearing types"); + EnsureClearSupport(); - using (new WriteLock(_lock)) + EnsureResolutionNotFrozen(); + + using (GetWriteLock()) { - InstanceTypes.Clear(); + _instanceTypes.Clear(); } } @@ -278,12 +284,13 @@ namespace Umbraco.Core.ObjectResolution /// /// The zero-based index at which the object should be inserted. /// The object to insert. - public void InsertType(int index, Type value) + public virtual void InsertType(int index, Type value) { - if (!SupportsInsert) - throw new InvalidOperationException("This resolver does not support Inserting new types"); + EnsureInsertSupport(); - using (var l = new UpgradeableReadLock(_lock)) + EnsureResolutionNotFrozen(); + + using (var l = GetWriteLock()) { EnsureCorrectType(value); if (InstanceTypes.Contains(value)) @@ -291,8 +298,7 @@ namespace Umbraco.Core.ObjectResolution throw new InvalidOperationException("The Type " + value + " already exists in the collection"); }; - l.UpgradeToWriteLock(); - InstanceTypes.Insert(index, value); + _instanceTypes.Insert(index, value); } } @@ -306,7 +312,65 @@ namespace Umbraco.Core.ObjectResolution InsertType(index, typeof (T)); } - private void EnsureCorrectType(Type t) + /// + /// Returns a WriteLock to use when modifying collections + /// + /// + protected WriteLock GetWriteLock() + { + return new WriteLock(_lock); + } + + /// + /// Throws an exception if resolution is frozen + /// + protected void EnsureResolutionNotFrozen() + { + if (Resolution.IsFrozen) + throw new InvalidOperationException("The type list cannot be modified after resolution has been frozen"); + } + + /// + /// Throws an exception if this does not support Remove + /// + protected void EnsureRemoveSupport() + { + if (!SupportsRemove) + throw new InvalidOperationException("This resolver does not support Removing types"); + } + + /// + /// Throws an exception if this does not support Clear + /// + protected void EnsureClearSupport() + { + if (!SupportsClear) + throw new InvalidOperationException("This resolver does not support Clearing types"); + } + + /// + /// Throws an exception if this does not support Add + /// + protected void EnsureAddSupport() + { + if (!SupportsAdd) + throw new InvalidOperationException("This resolver does not support Adding new types"); + } + + /// + /// Throws an exception if this does not support insert + /// + protected void EnsureInsertSupport() + { + if (!SupportsInsert) + throw new InvalidOperationException("This resolver does not support Inserting new types"); + } + + /// + /// Throws an exception if the type is not of the TResolved type + /// + /// + protected void EnsureCorrectType(Type t) { if (!TypeHelper.IsTypeAssignableFrom(t)) throw new InvalidOperationException("The resolver " + this.GetType() + " can only accept types of " + typeof(TResolved) + ". The Type passed in to this method is " + t); @@ -314,22 +378,22 @@ namespace Umbraco.Core.ObjectResolution protected virtual bool SupportsAdd { - get { return _supportsAdd; } + get { return true; } } protected virtual bool SupportsInsert { - get { return _supportsInsert; } + get { return true; } } protected virtual bool SupportsClear { - get { return _supportsClear; } + get { return true; } } protected virtual bool SupportsRemove { - get { return _supportsRemove; } + get { return true; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 672bed94a7..c4535c99d9 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -70,6 +70,7 @@ + diff --git a/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs b/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs new file mode 100644 index 0000000000..56ed107e68 --- /dev/null +++ b/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.ObjectResolution; + +namespace Umbraco.Tests.Resolvers +{ + [TestFixture] + public class LazyManyObjectResolverTests + { + + [SetUp] + public void Initialize() + { + + } + + [TearDown] + public void TearDown() + { + Resolution.IsFrozen = false; + } + + [Test] + public void Ensure_Lazy_Type_Resolution() + { + var resolver = new LazyResolver(new[] {new Lazy(() => typeof (TransientObject3))}); + resolver.AddType(); + resolver.AddType(new Lazy(() => typeof(TransientObject2))); + + Resolution.Freeze(); + + Assert.IsFalse(resolver.HasResolvedTypes); + + var instances1 = resolver.Objects; + + Assert.IsTrue(resolver.HasResolvedTypes); + + Assert.AreEqual(3, instances1.Count()); + Assert.IsTrue(instances1.Select(x => x.GetType()).ContainsAll(new []{typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3)})); + } + + #region Test classes + + private interface ITestInterface + { + } + + private class TransientObject1 : ITestInterface + { + } + + private class TransientObject2 : ITestInterface + { + } + + private class TransientObject3 : ITestInterface + { + } + + private sealed class LazyResolver : LazyManyObjectsResolverBase + { + public LazyResolver() + : base(ObjectLifetimeScope.Transient) + { + } + + public LazyResolver(IEnumerable> values) + :base (values, ObjectLifetimeScope.Transient) + { + + } + + public IEnumerable Objects + { + get { return Values; } + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Resolvers/ManyObjectResolverTests.cs b/src/Umbraco.Tests/Resolvers/ManyObjectResolverTests.cs index 53ca92e486..20f970384e 100644 --- a/src/Umbraco.Tests/Resolvers/ManyObjectResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/ManyObjectResolverTests.cs @@ -73,7 +73,7 @@ namespace Umbraco.Tests.Resolvers Assert.IsFalse(object.ReferenceEquals(instances1.Single(), instances3.Single())); } - #region + #region Test classes private interface ITestInterface { diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index ae497719f9..c7bfb8cba0 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -86,6 +86,7 @@ + From f467b8cb6c671870b4dc7dd831f37f24b4bccd47 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 23 Jan 2013 17:39:07 +0300 Subject: [PATCH 11/20] Adds more functionality for LazyManyObjectsResolverBase - adding type list delegates for lazy resolution. --- .../LazyManyObjectsResolverbase.cs | 139 ++++++++++++++---- .../ManyObjectsResolverBase.cs | 11 +- .../Resolvers/LazyManyObjectResolverTests.cs | 59 ++++++++ 3 files changed, 181 insertions(+), 28 deletions(-) diff --git a/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs b/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs index a71d0a3f1e..0cd5705aa5 100644 --- a/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs +++ b/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs @@ -5,6 +5,19 @@ using System.Web; namespace Umbraco.Core.ObjectResolution { + /// + /// A base class for lazily resolving types for a resolver + /// + /// + /// + /// + /// This is a special case resolver for when types get lazily resolved in order to resolve the actual types. This is useful + /// for when there is some processing overhead (i.e. Type finding in assemblies) to return the Types used to instantiate the instances. + /// In some these cases we don't want to have to type find during application startup, only when we need to resolve the instances. + /// + /// Important notes about this resolver: This does not support Insert or Remove and therefore does not support any ordering unless + /// the types are marked with the WeightedPluginAttribute. + /// internal abstract class LazyManyObjectsResolverBase : ManyObjectsResolverBase where TResolved : class where TResolver : class @@ -21,28 +34,62 @@ namespace Umbraco.Core.ObjectResolution { } - protected LazyManyObjectsResolverBase(IEnumerable> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) + /// + /// Constructor accepting a list of lazy types + /// + /// + /// + protected LazyManyObjectsResolverBase(IEnumerable> listOfLazyTypes, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) : this(scope) { - AddTypes(value); + AddTypes(listOfLazyTypes); } - protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable> value) + /// + /// Constructor accepting a delegate to return a list of types + /// + /// + /// + protected LazyManyObjectsResolverBase(Func> typeListDelegate, ObjectLifetimeScope scope = ObjectLifetimeScope.Application) + : this(scope) + { + _listOfTypeListDelegates.Add(typeListDelegate); + } + + /// + /// Constructor accepting a list of lazy types + /// + /// + /// + protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable> listOfLazyTypes) : this(httpContext) { - + AddTypes(listOfLazyTypes); + } + + /// + /// Constructor accepting a delegate to return a list of types + /// + /// + /// + protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func> typeListDelegate) + : this(httpContext) + { + _listOfTypeListDelegates.Add(typeListDelegate); } + #endregion - private readonly List> _lazyTypes = new List>(); - private bool _hasResolvedTypes = false; + private readonly List> _lazyTypeList = new List>(); + private readonly List>> _listOfTypeListDelegates = new List>>(); + private List _resolvedTypes = null; /// /// Used for unit tests /// internal bool HasResolvedTypes { - get { return _hasResolvedTypes; } + get { return _resolvedTypes != null; } } /// @@ -52,28 +99,50 @@ namespace Umbraco.Core.ObjectResolution { get { - var list = _lazyTypes.Select(x => x.Value).ToArray(); - - //we need to validate each resolved type now since we could not do it before when inserting the lazy delegates - if (!_hasResolvedTypes) + using (var lck = GetUpgradeableReadLock()) { - var uniqueList = new List(); - foreach (var l in list) - { - EnsureCorrectType(l); - if (uniqueList.Contains(l)) - { - throw new InvalidOperationException("The Type " + l + " already exists in the collection"); - } - uniqueList.Add(l); - } - _hasResolvedTypes = true; - } + var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray(); + var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray(); - return list; + //we need to validate each resolved type now since we could not do it before when inserting the lazy delegates + if (!HasResolvedTypes) + { + lck.UpgradeToWriteLock(); + + _resolvedTypes = new List(); + + //first iterate the lazy type list + foreach (var l in lazyTypeList) + { + UpdateUniqueList(_resolvedTypes, l); + } + + //next iterate the list of list type delegates + foreach (var l in listofTypeListDelegates) + { + UpdateUniqueList(_resolvedTypes, l); + } + } + + return _resolvedTypes; + } } } + private void UpdateUniqueList(List uniqueList, Type toAdd) + { + EnsureCorrectType(toAdd); + if (uniqueList.Contains(toAdd)) + { + throw new InvalidOperationException("The Type " + toAdd + " already exists in the collection"); + } + uniqueList.Add(toAdd); + } + + /// + /// Allows adding of multiple lazy types at once + /// + /// protected void AddTypes(IEnumerable> types) { EnsureAddSupport(); @@ -84,11 +153,27 @@ namespace Umbraco.Core.ObjectResolution { foreach (var t in types) { - _lazyTypes.Add(t); + _lazyTypeList.Add(t); } } } + /// + /// Adds a type list delegate to the collection + /// + /// + public void AddTypeListDelegate(Func> typeListDelegate) + { + EnsureAddSupport(); + + EnsureResolutionNotFrozen(); + + using (GetWriteLock()) + { + _listOfTypeListDelegates.Add(typeListDelegate); + } + } + /// /// Adds a lazy type to the list /// @@ -101,7 +186,7 @@ namespace Umbraco.Core.ObjectResolution using (GetWriteLock()) { - _lazyTypes.Add(value); + _lazyTypeList.Add(value); } } @@ -125,7 +210,7 @@ namespace Umbraco.Core.ObjectResolution using (GetWriteLock()) { - _lazyTypes.Clear(); + _lazyTypeList.Clear(); } } diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs index 9343b1a58b..c2fb584602 100644 --- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs @@ -320,7 +320,16 @@ namespace Umbraco.Core.ObjectResolution { return new WriteLock(_lock); } - + + /// + /// Returns an upgradeable read lock for use when reading/modifying collections + /// + /// + protected UpgradeableReadLock GetUpgradeableReadLock() + { + return new UpgradeableReadLock(_lock); + } + /// /// Throws an exception if resolution is frozen /// diff --git a/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs b/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs index 56ed107e68..977ddee355 100644 --- a/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/LazyManyObjectResolverTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -42,6 +43,58 @@ namespace Umbraco.Tests.Resolvers Assert.IsTrue(instances1.Select(x => x.GetType()).ContainsAll(new []{typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3)})); } + [Test] + public void Type_List_Delegates_Combination() + { + Func> types = () => new[] { typeof(TransientObject3), typeof(TransientObject2) }; + + var resolver = new LazyResolver(types); + resolver.AddTypeListDelegate(() => new[] { typeof(TransientObject1)}); + + Resolution.Freeze(); + + var instances1 = resolver.Objects; + + Assert.AreEqual(3, instances1.Count()); + Assert.IsTrue(instances1.Select(x => x.GetType()).ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) })); + } + + [Test] + public void Type_List_Delegates_And_Lazy_Type_Combination() + { + Func> types = () => new[] { typeof(TransientObject3) }; + + var resolver = new LazyResolver(types); + resolver.AddType(new Lazy(() => typeof(TransientObject2))); + resolver.AddType(); + + Resolution.Freeze(); + + var instances1 = resolver.Objects; + + Assert.AreEqual(3, instances1.Count()); + Assert.IsTrue(instances1.Select(x => x.GetType()).ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) })); + } + + [Test] + public void Throws_If_Duplication() + { + Func> types = () => new[] { typeof(TransientObject3), typeof(TransientObject2), typeof(TransientObject1) }; + + var resolver = new LazyResolver(types); + //duplicate, but will not throw here + resolver.AddType(); + + Resolution.Freeze(); + + Assert.Throws(() => + { + var instances = resolver.Objects; + }); + + + } + #region Test classes private interface ITestInterface @@ -73,6 +126,12 @@ namespace Umbraco.Tests.Resolvers } + public LazyResolver(Func> typeList) + : base(typeList, ObjectLifetimeScope.Transient) + { + + } + public IEnumerable Objects { get { return Values; } From 82c25608227626fb1b162d38085982687e66def0 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 23 Jan 2013 18:40:40 +0300 Subject: [PATCH 12/20] Ensures all resolvers are sealed. Changes CacheRefreshersResolver, DataTypesResolver, MacroFieldEditorsResolver, PackageActionsResolver, ActionsResolver to all be lazy resolvers as they are not needed instantly on app startup (not needed by the front-end) This will make app startup a lot quicker. Fixes ActionsResolver to not use the PluginManager to resolve the types when it is instantiating them since these are passed in the ctor. Updates all unit tests to use lazy delegate for these resolvers and they are all passing. --- src/Umbraco.Core/ActionsResolver.cs | 8 ++++---- src/Umbraco.Core/CacheRefreshersResolver.cs | 2 +- src/Umbraco.Core/CoreBootManager.cs | 10 +++++----- src/Umbraco.Core/DataTypesResolver.cs | 2 +- .../Dictionary/CultureDictionaryFactoryResolver.cs | 2 +- .../ObjectResolution/LazyManyObjectsResolverbase.cs | 4 +++- .../LegacyTransientObjectsResolver.cs | 13 ++++++------- .../ObjectResolution/MacroFieldEditorsResolver.cs | 4 ++-- .../ObjectResolution/ManyObjectsResolverBase.cs | 11 +---------- src/Umbraco.Core/PackageActionsResolver.cs | 4 ++-- .../PropertyEditorValueConvertersResolver.cs | 2 +- src/Umbraco.Tests/CacheRefresherFactoryTests.cs | 2 +- src/Umbraco.Tests/DataTypeFactoryTests.cs | 2 +- src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs | 2 +- .../Resolvers/MacroFieldEditorsResolverTests.cs | 2 +- .../Resolvers/PackageActionsResolverTests.cs | 2 +- src/Umbraco.Web/Mvc/SurfaceControllerResolver.cs | 2 +- src/Umbraco.Web/PublishedContentStoreResolver.cs | 2 +- src/Umbraco.Web/PublishedMediaStoreResolver.cs | 2 +- src/umbraco.cms/Actions/Action.cs | 2 +- 20 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/Umbraco.Core/ActionsResolver.cs b/src/Umbraco.Core/ActionsResolver.cs index cae5a4575f..083704d3bd 100644 --- a/src/Umbraco.Core/ActionsResolver.cs +++ b/src/Umbraco.Core/ActionsResolver.cs @@ -9,14 +9,14 @@ namespace Umbraco.Core /// /// A resolver to return all IAction objects /// - internal sealed class ActionsResolver : ManyObjectsResolverBase + internal sealed class ActionsResolver : LazyManyObjectsResolverBase { /// /// Constructor /// /// - internal ActionsResolver(IEnumerable packageActions) + internal ActionsResolver(Func> packageActions) : base(packageActions) { @@ -34,9 +34,9 @@ namespace Umbraco.Core } protected override IEnumerable CreateInstances() - { + { var actions = new List(); - var foundIActions = PluginManager.Current.ResolveActions(); + var foundIActions = InstanceTypes; foreach (var type in foundIActions) { IAction typeInstance; diff --git a/src/Umbraco.Core/CacheRefreshersResolver.cs b/src/Umbraco.Core/CacheRefreshersResolver.cs index 31ed877e97..51c6cfc183 100644 --- a/src/Umbraco.Core/CacheRefreshersResolver.cs +++ b/src/Umbraco.Core/CacheRefreshersResolver.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core /// Constructor /// /// - internal CacheRefreshersResolver(IEnumerable refreshers) + internal CacheRefreshersResolver(Func> refreshers) : base(refreshers) { diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index 98531f74ea..3042c962e4 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -94,19 +94,19 @@ namespace Umbraco.Core protected virtual void InitializeResolvers() { CacheRefreshersResolver.Current = new CacheRefreshersResolver( - PluginManager.Current.ResolveCacheRefreshers()); + () => PluginManager.Current.ResolveCacheRefreshers()); DataTypesResolver.Current = new DataTypesResolver( - PluginManager.Current.ResolveDataTypes()); + () => PluginManager.Current.ResolveDataTypes()); MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver( - PluginManager.Current.ResolveMacroRenderings()); + () => PluginManager.Current.ResolveMacroRenderings()); PackageActionsResolver.Current = new PackageActionsResolver( - PluginManager.Current.ResolvePackageActions()); + () => PluginManager.Current.ResolvePackageActions()); ActionsResolver.Current = new ActionsResolver( - PluginManager.Current.ResolveActions()); + () => PluginManager.Current.ResolveActions()); PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver( PluginManager.Current.ResolvePropertyEditorValueConverters()); diff --git a/src/Umbraco.Core/DataTypesResolver.cs b/src/Umbraco.Core/DataTypesResolver.cs index 024fecc1ee..65591bd917 100644 --- a/src/Umbraco.Core/DataTypesResolver.cs +++ b/src/Umbraco.Core/DataTypesResolver.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core /// Constructor /// /// - internal DataTypesResolver(IEnumerable dataTypes) + internal DataTypesResolver(Func> dataTypes) : base(dataTypes) { diff --git a/src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs b/src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs index 1d754e1970..2dd7881e08 100644 --- a/src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs +++ b/src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs @@ -5,7 +5,7 @@ namespace Umbraco.Core.Dictionary /// /// Resolves the current CultureDictionaryFactory /// - internal class CultureDictionaryFactoryResolver : SingleObjectResolverBase + internal sealed class CultureDictionaryFactoryResolver : SingleObjectResolverBase { internal CultureDictionaryFactoryResolver(ICultureDictionaryFactory factory) : base(factory) diff --git a/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs b/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs index 0cd5705aa5..21374a48f5 100644 --- a/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs +++ b/src/Umbraco.Core/ObjectResolution/LazyManyObjectsResolverbase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Web; namespace Umbraco.Core.ObjectResolution @@ -83,6 +84,7 @@ namespace Umbraco.Core.ObjectResolution private readonly List> _lazyTypeList = new List>(); private readonly List>> _listOfTypeListDelegates = new List>>(); private List _resolvedTypes = null; + private readonly ReaderWriterLockSlim _typeResolutionLock = new ReaderWriterLockSlim(); /// /// Used for unit tests @@ -99,7 +101,7 @@ namespace Umbraco.Core.ObjectResolution { get { - using (var lck = GetUpgradeableReadLock()) + using (var lck = new UpgradeableReadLock(_typeResolutionLock)) { var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray(); var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray(); diff --git a/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs b/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs index f45e7fa9df..18d67f3b41 100644 --- a/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs +++ b/src/Umbraco.Core/ObjectResolution/LegacyTransientObjectsResolver.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.ObjectResolution /// these old classes don't contain metadata, the objects need to be instantiated first to get their metadata, we then store this /// for use in the GetById method. /// - internal abstract class LegacyTransientObjectsResolver : ManyObjectsResolverBase + internal abstract class LegacyTransientObjectsResolver : LazyManyObjectsResolverBase where TResolved : class where TResolver : class { @@ -27,16 +27,15 @@ namespace Umbraco.Core.ObjectResolution /// /// Constructor /// - /// + /// /// /// We are creating Transient instances (new instances each time) because this is how the legacy code worked and /// I don't want to muck anything up by changing them to application based instances. /// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier. /// - protected LegacyTransientObjectsResolver(IEnumerable refreshers) - : base(ObjectLifetimeScope.Transient) // new objects every time - { - AddTypes(refreshers); + protected LegacyTransientObjectsResolver(Func> types) + : base(types, ObjectLifetimeScope.Transient) // new objects every time + { } #endregion @@ -55,7 +54,7 @@ namespace Umbraco.Core.ObjectResolution protected abstract Guid GetUniqueIdentifier(TResolved obj); /// - /// Returns a new ICacheRefresher instance by id + /// Returns a new TResolved instance by id /// /// /// diff --git a/src/Umbraco.Core/ObjectResolution/MacroFieldEditorsResolver.cs b/src/Umbraco.Core/ObjectResolution/MacroFieldEditorsResolver.cs index 9143e39f90..f0b6867a38 100644 --- a/src/Umbraco.Core/ObjectResolution/MacroFieldEditorsResolver.cs +++ b/src/Umbraco.Core/ObjectResolution/MacroFieldEditorsResolver.cs @@ -15,14 +15,14 @@ namespace Umbraco.Core.ObjectResolution /// Much of this classes methods are based on legacy code from umbraco.editorControls.macrocontainer.MacroControlFactory /// this code should probably be reviewed and cleaned up if necessary. /// - internal sealed class MacroFieldEditorsResolver : ManyObjectsResolverBase + internal sealed class MacroFieldEditorsResolver : LazyManyObjectsResolverBase { /// /// Constructor /// /// - internal MacroFieldEditorsResolver(IEnumerable macroEditors) + internal MacroFieldEditorsResolver(Func> macroEditors) : base(macroEditors, ObjectLifetimeScope.Transient) { diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs index c2fb584602..9343b1a58b 100644 --- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs +++ b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs @@ -320,16 +320,7 @@ namespace Umbraco.Core.ObjectResolution { return new WriteLock(_lock); } - - /// - /// Returns an upgradeable read lock for use when reading/modifying collections - /// - /// - protected UpgradeableReadLock GetUpgradeableReadLock() - { - return new UpgradeableReadLock(_lock); - } - + /// /// Throws an exception if resolution is frozen /// diff --git a/src/Umbraco.Core/PackageActionsResolver.cs b/src/Umbraco.Core/PackageActionsResolver.cs index 8c1d412374..551bf8cfa7 100644 --- a/src/Umbraco.Core/PackageActionsResolver.cs +++ b/src/Umbraco.Core/PackageActionsResolver.cs @@ -8,14 +8,14 @@ namespace Umbraco.Core /// /// A resolver to return all IPackageAction objects /// - internal sealed class PackageActionsResolver : ManyObjectsResolverBase + internal sealed class PackageActionsResolver : LazyManyObjectsResolverBase { /// /// Constructor /// /// - internal PackageActionsResolver(IEnumerable packageActions) + internal PackageActionsResolver(Func> packageActions) : base(packageActions) { diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorValueConvertersResolver.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorValueConvertersResolver.cs index aaf1c06102..f804f424a6 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditorValueConvertersResolver.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorValueConvertersResolver.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.PropertyEditors /// /// Manages the list of IPropertyEditorValueConverter's /// - internal class PropertyEditorValueConvertersResolver : ManyObjectsResolverBase + internal sealed class PropertyEditorValueConvertersResolver : ManyObjectsResolverBase { public PropertyEditorValueConvertersResolver(IEnumerable converters) : base(converters) diff --git a/src/Umbraco.Tests/CacheRefresherFactoryTests.cs b/src/Umbraco.Tests/CacheRefresherFactoryTests.cs index 8fdef3f09a..782638a1db 100644 --- a/src/Umbraco.Tests/CacheRefresherFactoryTests.cs +++ b/src/Umbraco.Tests/CacheRefresherFactoryTests.cs @@ -26,7 +26,7 @@ namespace Umbraco.Tests }; CacheRefreshersResolver.Current = new CacheRefreshersResolver( - PluginManager.Current.ResolveCacheRefreshers()); + () => PluginManager.Current.ResolveCacheRefreshers()); Resolution.Freeze(); } diff --git a/src/Umbraco.Tests/DataTypeFactoryTests.cs b/src/Umbraco.Tests/DataTypeFactoryTests.cs index e0de0a4af6..fadc45a843 100644 --- a/src/Umbraco.Tests/DataTypeFactoryTests.cs +++ b/src/Umbraco.Tests/DataTypeFactoryTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests }; DataTypesResolver.Current = new DataTypesResolver( - PluginManager.Current.ResolveDataTypes()); + () => PluginManager.Current.ResolveDataTypes()); Resolution.Freeze(); } diff --git a/src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs b/src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs index 34b834753b..391b0c6072 100644 --- a/src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/ActionsResolverTests.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Resolvers }; ActionsResolver.Current = new ActionsResolver( - PluginManager.Current.ResolveActions()); + () => PluginManager.Current.ResolveActions()); Resolution.Freeze(); } diff --git a/src/Umbraco.Tests/Resolvers/MacroFieldEditorsResolverTests.cs b/src/Umbraco.Tests/Resolvers/MacroFieldEditorsResolverTests.cs index 6f7ae14ce9..5507400091 100644 --- a/src/Umbraco.Tests/Resolvers/MacroFieldEditorsResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/MacroFieldEditorsResolverTests.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Resolvers }; MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver( - PluginManager.Current.ResolveMacroRenderings()); + () => PluginManager.Current.ResolveMacroRenderings()); Resolution.Freeze(); } diff --git a/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs b/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs index a12890a36f..b7b9d0a6fe 100644 --- a/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs +++ b/src/Umbraco.Tests/Resolvers/PackageActionsResolverTests.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Resolvers }; PackageActionsResolver.Current = new PackageActionsResolver( - PluginManager.Current.ResolvePackageActions()); + () => PluginManager.Current.ResolvePackageActions()); Resolution.Freeze(); } diff --git a/src/Umbraco.Web/Mvc/SurfaceControllerResolver.cs b/src/Umbraco.Web/Mvc/SurfaceControllerResolver.cs index e9e60e1c58..31176d282c 100644 --- a/src/Umbraco.Web/Mvc/SurfaceControllerResolver.cs +++ b/src/Umbraco.Web/Mvc/SurfaceControllerResolver.cs @@ -4,7 +4,7 @@ using Umbraco.Core.ObjectResolution; namespace Umbraco.Web.Mvc { - internal class SurfaceControllerResolver : ManyObjectsResolverBase + internal sealed class SurfaceControllerResolver : ManyObjectsResolverBase { public SurfaceControllerResolver(IEnumerable surfaceControllers) : base(surfaceControllers) diff --git a/src/Umbraco.Web/PublishedContentStoreResolver.cs b/src/Umbraco.Web/PublishedContentStoreResolver.cs index 0e0f049443..2ba6eb0ef1 100644 --- a/src/Umbraco.Web/PublishedContentStoreResolver.cs +++ b/src/Umbraco.Web/PublishedContentStoreResolver.cs @@ -5,7 +5,7 @@ namespace Umbraco.Web /// /// An object resolver to return the IPublishedContentStore /// - internal class PublishedContentStoreResolver : SingleObjectResolverBase + internal sealed class PublishedContentStoreResolver : SingleObjectResolverBase { internal PublishedContentStoreResolver(IPublishedContentStore publishedContentStore) : base(publishedContentStore) diff --git a/src/Umbraco.Web/PublishedMediaStoreResolver.cs b/src/Umbraco.Web/PublishedMediaStoreResolver.cs index e3a7dc3bac..6f741b3796 100644 --- a/src/Umbraco.Web/PublishedMediaStoreResolver.cs +++ b/src/Umbraco.Web/PublishedMediaStoreResolver.cs @@ -5,7 +5,7 @@ namespace Umbraco.Web /// /// An object resolver to return the IPublishedMediaStore /// - internal class PublishedMediaStoreResolver : SingleObjectResolverBase + internal sealed class PublishedMediaStoreResolver : SingleObjectResolverBase { internal PublishedMediaStoreResolver(IPublishedMediaStore publishedMediaStore) : base(publishedMediaStore) diff --git a/src/umbraco.cms/Actions/Action.cs b/src/umbraco.cms/Actions/Action.cs index 34ff982eb2..4a1dd6e808 100644 --- a/src/umbraco.cms/Actions/Action.cs +++ b/src/umbraco.cms/Actions/Action.cs @@ -59,7 +59,7 @@ namespace umbraco.BusinessLogic.Actions //TODO: Based on the above, this is a big hack as types should all be cleared on package install! ActionsResolver.Current = new ActionsResolver( - TypeFinder.FindClassesOfType(PluginManager.Current.AssembliesToScan)); + () => TypeFinder.FindClassesOfType(PluginManager.Current.AssembliesToScan)); RegisterIActionHandlers(); } From f9a0d91299ce05e29a3ed58ab2afa1718a74c50d Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Fri, 25 Jan 2013 06:04:10 +0300 Subject: [PATCH 13/20] Fixes: #U4-1527 - Creates a public property on UmbracoHelper to return the currently assigned IPublishedContent of the UmbracoHelper. --- src/Umbraco.Web/UmbracoHelper.cs | 38 +++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index db5323eede..27a3d93edb 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Text; using System.Web; -using System.Web.Configuration; using System.Web.Security; using System.Web.UI; using System.Xml.Linq; @@ -13,18 +12,14 @@ using HtmlAgilityPack; using Umbraco.Core; using Umbraco.Core.Dictionary; using Umbraco.Core.Dynamics; -using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.Routing; using Umbraco.Web.Templates; using umbraco; using System.Collections.Generic; using umbraco.cms.businesslogic.member; using umbraco.cms.businesslogic.web; using umbraco.presentation.templateControls; -using HtmlTagWrapper = Umbraco.Web.Mvc.HtmlTagWrapper; namespace Umbraco.Web { @@ -64,7 +59,29 @@ namespace Umbraco.Web } } - /// + /// + /// Returns the current IPublishedContent item assigned to the UmbracoHelper + /// + /// + /// Note that this is the assigned IPublishedContent item to the UmbracoHelper, this is not necessarily the Current IPublishedContent item + /// being rendered. This IPublishedContent object is contextual to the current UmbracoHelper instance. + /// + /// In some cases accessing this property will throw an exception if there is not IPublishedContent assigned to the Helper + /// this will only ever happen if the Helper is constructed with an UmbracoContext and it is not a front-end request + /// + /// Thrown if the UmbracoHelper is constructed with an UmbracoContext and it is not a front-end request + public IPublishedContent AssignedContentItem + { + get + { + if (_currentPage == null) + throw new InvalidOperationException("Cannot return the " + typeof(IPublishedContent).Name + " because the " + typeof(UmbracoHelper).Name + " was constructed with an " + typeof(UmbracoContext).Name + " and the current request is not a front-end request."); + + return _currentPage; + } + } + + /// /// Renders the template for the specified pageId and an optional altTemplateId /// /// @@ -209,12 +226,8 @@ namespace Umbraco.Web //TODO: commented out until as it is not implemented by umbraco:item yet //,string formatString = "") - { - if (_currentPage == null) - { - throw new InvalidOperationException("Cannot call this method when not rendering a front-end document"); - } - return Field(_currentPage, fieldAlias, altFieldAlias, + { + return Field(AssignedContentItem, fieldAlias, altFieldAlias, altText, insertBefore, insertAfter, recursive, convertLineBreaks, removeParagraphTags, casing, encoding, formatAsDate, formatAsDateWithTime, formatAsDateWithTimeSeparator); // formatString); } @@ -301,7 +314,6 @@ namespace Umbraco.Web var item = new Item() { - //NodeId = currentPage.Id.ToString(); Field = fieldAlias, TextIfEmpty = altText, LegacyAttributes = attributesForItem From 086a0811cba6875fcfcadc85232f499d9b58e67c Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Fri, 25 Jan 2013 07:30:25 -0100 Subject: [PATCH 14/20] Refactoring GetCreator/WriterProfile extension methods to use the service rather then repository, as it seems to cause threading issues per our threading test. --- src/Umbraco.Core/Models/ContentExtensions.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs index 9893994d4e..40c5d6110a 100644 --- a/src/Umbraco.Core/Models/ContentExtensions.cs +++ b/src/Umbraco.Core/Models/ContentExtensions.cs @@ -303,11 +303,7 @@ namespace Umbraco.Core.Models /// public static IProfile GetCreatorProfile(this IContentBase content) { - using (var repository = RepositoryResolver.Current.Factory.CreateUserRepository( - PetaPocoUnitOfWorkProvider.CreateUnitOfWork())) - { - return repository.GetProfileById(content.CreatorId); - } + return ApplicationContext.Current.Services.UserService.GetProfileById(content.CreatorId); } /// @@ -315,11 +311,7 @@ namespace Umbraco.Core.Models /// public static IProfile GetWriterProfile(this IContent content) { - using (var repository = RepositoryResolver.Current.Factory.CreateUserRepository( - PetaPocoUnitOfWorkProvider.CreateUnitOfWork())) - { - return repository.GetProfileById(content.WriterId); - } + return ApplicationContext.Current.Services.UserService.GetProfileById(content.WriterId); } /// @@ -371,9 +363,7 @@ namespace Umbraco.Core.Models var x = media.ToXml(nodeName); x.Add(new XAttribute("nodeType", media.ContentType.Id)); - //TODO Using the GetCreatorProfile extension method seems to be causing threading/connection problems because of the way the repo is used - //x.Add(new XAttribute("writerName", media.GetCreatorProfile().Name)); - x.Add(new XAttribute("writerName", string.Empty)); + x.Add(new XAttribute("writerName", media.GetCreatorProfile().Name)); x.Add(new XAttribute("writerID", media.CreatorId)); x.Add(new XAttribute("version", media.Version)); x.Add(new XAttribute("template", 0)); From a17759f7599789ef5d9992c9494ac9fc903c0a8c Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Fri, 25 Jan 2013 07:50:22 -0100 Subject: [PATCH 15/20] Fixes U4-1542 --- src/Umbraco.Tests/Models/MediaXmlTest.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Tests/Models/MediaXmlTest.cs b/src/Umbraco.Tests/Models/MediaXmlTest.cs index 8907cc4fc2..f630488e92 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -61,7 +61,6 @@ namespace Umbraco.Tests.Models Assert.AreEqual(media.Id.ToString(), (string)element.Attribute("id")); Assert.AreEqual(media.ParentId.ToString(), (string)element.Attribute("parentID")); Assert.AreEqual(media.Level.ToString(), (string)element.Attribute("level")); - //Assert.AreEqual(media.CreatorId.ToString(), (string)element.Attribute("creatorID")); Assert.AreEqual(media.SortOrder.ToString(), (string)element.Attribute("sortOrder")); Assert.AreEqual(media.CreateDate.ToString("s"), (string)element.Attribute("createDate")); Assert.AreEqual(media.UpdateDate.ToString("s"), (string)element.Attribute("updateDate")); @@ -70,7 +69,6 @@ namespace Umbraco.Tests.Models Assert.AreEqual(media.Path, (string)element.Attribute("path")); Assert.AreEqual("", (string)element.Attribute("isDoc")); Assert.AreEqual(media.ContentType.Id.ToString(), (string)element.Attribute("nodeType")); - //Assert.AreEqual(media.GetCreatorProfile().Name, (string)element.Attribute("creatorName")); Assert.AreEqual(media.GetCreatorProfile().Name, (string)element.Attribute("writerName")); Assert.AreEqual(media.CreatorId.ToString(), (string)element.Attribute("writerID")); Assert.AreEqual(media.Version.ToString(), (string)element.Attribute("version")); From 309f3374617d22cf448b9489fb853f8708e03a39 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Fri, 25 Jan 2013 08:58:21 -0100 Subject: [PATCH 16/20] Fixes U4-1549 --- src/Umbraco.Core/Services/ContentService.cs | 217 +++++------------- .../Services/ContentTypeService.cs | 93 ++------ src/Umbraco.Core/Services/DataTypeService.cs | 10 +- src/Umbraco.Core/Services/FileService.cs | 26 +-- src/Umbraco.Core/Services/IContentService.cs | 32 +-- .../Services/IContentTypeService.cs | 17 +- src/Umbraco.Core/Services/IDataTypeService.cs | 4 +- src/Umbraco.Core/Services/IFileService.cs | 12 +- .../Services/ILocalizationService.cs | 8 +- src/Umbraco.Core/Services/IMacroService.cs | 4 +- src/Umbraco.Core/Services/IMediaService.cs | 18 +- .../Services/LocalizationService.cs | 17 +- src/Umbraco.Core/Services/MacroService.cs | 8 +- src/Umbraco.Core/Services/MediaService.cs | 92 ++------ src/Umbraco.Core/Services/ServiceContext.cs | 4 +- .../Services/ContentServiceTests.cs | 70 +----- 16 files changed, 176 insertions(+), 456 deletions(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index da443413c7..38bd853e11 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -24,9 +24,7 @@ namespace Umbraco.Core.Services { private readonly IDatabaseUnitOfWorkProvider _uowProvider; private readonly IPublishingStrategy _publishingStrategy; - private readonly IUserService _userService; private readonly RepositoryFactory _repositoryFactory; - private HttpContextBase _httpContext; public ContentService() : this(new RepositoryFactory()) @@ -44,21 +42,13 @@ namespace Umbraco.Core.Services : this(provider, repositoryFactory, new PublishingStrategy()) { } - internal ContentService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IPublishingStrategy publishingStrategy) + public ContentService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IPublishingStrategy publishingStrategy) { _uowProvider = provider; _publishingStrategy = publishingStrategy; _repositoryFactory = repositoryFactory; } - internal ContentService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IPublishingStrategy publishingStrategy, IUserService userService) - { - _uowProvider = provider; - _publishingStrategy = publishingStrategy; - _userService = userService; - _repositoryFactory = repositoryFactory; - } - /// /// Creates an object using the alias of the /// that this Content is based on. @@ -68,7 +58,7 @@ namespace Umbraco.Core.Services /// Alias of the /// Optional id of the user creating the content /// - public IContent CreateContent(string name, int parentId, string contentTypeAlias, int userId = -1) + public IContent CreateContent(string name, int parentId, string contentTypeAlias, int userId = 0) { IContentType contentType = null; IContent content = null; @@ -95,8 +85,8 @@ namespace Umbraco.Core.Services if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this)) return content; - SetUser(content, userId); - SetWriter(content, userId); + content.CreatorId = userId; + content.WriterId = userId; Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this); @@ -377,7 +367,7 @@ namespace Umbraco.Core.Services /// /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - public bool RePublishAll(int userId = -1) + public bool RePublishAll(int userId = 0) { return RePublishAllDo(false, userId); } @@ -388,7 +378,7 @@ namespace Umbraco.Core.Services /// The to publish /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - public bool Publish(IContent content, int userId = -1) + public bool Publish(IContent content, int userId = 0) { return SaveAndPublishDo(content, false, userId); } @@ -399,7 +389,7 @@ namespace Umbraco.Core.Services /// The to publish along with its children /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - public bool PublishWithChildren(IContent content, int userId = -1) + public bool PublishWithChildren(IContent content, int userId = 0) { return PublishWithChildrenDo(content, false, userId); } @@ -410,7 +400,7 @@ namespace Umbraco.Core.Services /// The to publish /// Optional Id of the User issueing the publishing /// True if unpublishing succeeded, otherwise False - public bool UnPublish(IContent content, int userId = -1) + public bool UnPublish(IContent content, int userId = 0) { return UnPublishDo(content, false, userId); } @@ -421,7 +411,7 @@ namespace Umbraco.Core.Services /// The to save and publish /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - public bool SaveAndPublish(IContent content, int userId = -1) + public bool SaveAndPublish(IContent content, int userId = 0) { return SaveAndPublishDo(content, false, userId); } @@ -431,7 +421,7 @@ namespace Umbraco.Core.Services /// /// The to save /// Optional Id of the User saving the Content - public void Save(IContent content, int userId = -1) + public void Save(IContent content, int userId = 0) { Save(content, true, userId); } @@ -445,7 +435,7 @@ namespace Umbraco.Core.Services /// /// Collection of to save /// Optional Id of the User saving the Content - public void Save(IEnumerable contents, int userId = -1) + public void Save(IEnumerable contents, int userId = 0) { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(contents), this)) return; @@ -459,7 +449,7 @@ namespace Umbraco.Core.Services { foreach (var content in contents) { - SetWriter(content, userId); + content.WriterId = userId; //Only change the publish state if the "previous" version was actually published if (content.Published) @@ -473,7 +463,7 @@ namespace Umbraco.Core.Services { foreach (var content in contents) { - SetWriter(content, userId); + content.WriterId = userId; repository.AddOrUpdate(content); } uow.Commit(); @@ -491,7 +481,7 @@ namespace Umbraco.Core.Services /// This needs extra care and attention as its potentially a dangerous and extensive operation /// Id of the /// Optional Id of the user issueing the delete operation - public void DeleteContentOfType(int contentTypeId, int userId = -1) + public void DeleteContentOfType(int contentTypeId, int userId = 0) { using (var uow = _uowProvider.GetUnitOfWork()) { @@ -523,7 +513,7 @@ namespace Umbraco.Core.Services Audit.Add(AuditTypes.Delete, string.Format("Delete Content of Type {0} performed by user", contentTypeId), - userId == -1 ? 0 : userId, -1); + userId, -1); } /// @@ -535,7 +525,7 @@ namespace Umbraco.Core.Services /// Please note that this method will completely remove the Content from the database /// The to delete /// Optional Id of the User deleting the Content - public void Delete(IContent content, int userId = -1) + public void Delete(IContent content, int userId = 0) { if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(content), this)) return; @@ -556,15 +546,13 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - //TODO: Why are we setting a writer if we are just deleting the object? (I'm probably overlooking something here...?) - SetWriter(content, userId); repository.Delete(content); uow.Commit(); } Deleted.RaiseEvent(new DeleteEventArgs(content, false), this); - Audit.Add(AuditTypes.Delete, "Delete Content performed by user", userId == -1 ? 0 : userId, content.Id); + Audit.Add(AuditTypes.Delete, "Delete Content performed by user", userId, content.Id); } /// @@ -573,7 +561,7 @@ namespace Umbraco.Core.Services /// Id of the object to delete versions from /// Latest version date /// Optional Id of the User deleting versions of a Content object - public void DeleteVersions(int id, DateTime versionDate, int userId = -1) + public void DeleteVersions(int id, DateTime versionDate, int userId = 0) { //TODO: We should check if we are going to delete the most recent version because if that happens it means the // entity is completely deleted and we should raise the normal Deleting/Deleted event @@ -590,7 +578,7 @@ namespace Umbraco.Core.Services DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate), this); - Audit.Add(AuditTypes.Delete, "Delete Content by version date performed by user", userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Delete, "Delete Content by version date performed by user", userId, -1); } /// @@ -600,7 +588,7 @@ namespace Umbraco.Core.Services /// Id of the version to delete /// Boolean indicating whether to delete versions prior to the versionId /// Optional Id of the User deleting versions of a Content object - public void DeleteVersion(int id, Guid versionId, bool deletePriorVersions, int userId = -1) + public void DeleteVersion(int id, Guid versionId, bool deletePriorVersions, int userId = 0) { //TODO: We should check if we are going to delete the most recent version because if that happens it means the // entity is completely deleted and we should raise the normal Deleting/Deleted event @@ -623,7 +611,7 @@ namespace Umbraco.Core.Services DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, specificVersion:versionId), this); - Audit.Add(AuditTypes.Delete, "Delete Content by version performed by user", userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Delete, "Delete Content by version performed by user", userId, -1); } /// @@ -632,7 +620,7 @@ namespace Umbraco.Core.Services /// Move an item to the Recycle Bin will result in the item being unpublished /// The to delete /// Optional Id of the User deleting the Content - public void MoveToRecycleBin(IContent content, int userId = -1) + public void MoveToRecycleBin(IContent content, int userId = 0) { if (Trashing.IsRaisedEventCancelled(new MoveEventArgs(content, -20), this)) return; @@ -653,7 +641,7 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - SetWriter(content, userId); + content.WriterId = userId; content.ChangeTrashedState(true); repository.AddOrUpdate(content); uow.Commit(); @@ -661,8 +649,7 @@ namespace Umbraco.Core.Services Trashed.RaiseEvent(new MoveEventArgs(content, false, -20), this); - Audit.Add(AuditTypes.Move, "Move Content to Recycle Bin performed by user", userId == -1 ? 0 : userId, - content.Id); + Audit.Add(AuditTypes.Move, "Move Content to Recycle Bin performed by user", userId, content.Id); } /// @@ -676,7 +663,7 @@ namespace Umbraco.Core.Services /// The to move /// Id of the Content's new Parent /// Optional Id of the User moving the Content - public void Move(IContent content, int parentId, int userId = -1) + public void Move(IContent content, int parentId, int userId = 0) { //This ensures that the correct method is called if this method is used to Move to recycle bin. if (parentId == -20) @@ -688,7 +675,7 @@ namespace Umbraco.Core.Services if (Moving.IsRaisedEventCancelled(new MoveEventArgs(content, parentId), this)) return; - SetWriter(content, userId); + content.WriterId = userId; var parent = GetById(parentId); content.Path = string.Concat(parent.Path, ",", content.Id); content.Level = parent.Level + 1; @@ -746,7 +733,7 @@ namespace Umbraco.Core.Services Moved.RaiseEvent(new MoveEventArgs(content, false, parentId), this); - Audit.Add(AuditTypes.Move, "Move Content performed by user", userId == -1 ? 0 : userId, content.Id); + Audit.Add(AuditTypes.Move, "Move Content performed by user", userId, content.Id); } /// @@ -786,7 +773,7 @@ namespace Umbraco.Core.Services /// Boolean indicating whether the copy should be related to the original /// Optional Id of the User copying the Content /// The newly created object - public IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = -1) + public IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = 0) { var copy = ((Content)content).Clone(); copy.ParentId = parentId; @@ -800,8 +787,7 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - SetWriter(content, userId); - + content.WriterId = userId; repository.AddOrUpdate(copy); uow.Commit(); @@ -895,7 +881,7 @@ namespace Umbraco.Core.Services /// The to send to publication /// Optional Id of the User issueing the send to publication /// True if sending publication was succesfull otherwise false - internal bool SendToPublication(IContent content, int userId = -1) + internal bool SendToPublication(IContent content, int userId = 0) { if (SendingToPublish.IsRaisedEventCancelled(new SendToPublishEventArgs(content), this)) @@ -922,7 +908,7 @@ namespace Umbraco.Core.Services /// Id of the version to rollback to /// Optional Id of the User issueing the rollback of the Content /// The newly created object - public IContent Rollback(int id, Guid versionId, int userId = -1) + public IContent Rollback(int id, Guid versionId, int userId = 0) { var content = GetByVersion(versionId); @@ -932,8 +918,8 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - SetUser(content, userId); - SetWriter(content, userId); + content.WriterId = userId; + content.CreatorId = userId; repository.AddOrUpdate(content); uow.Commit(); @@ -947,22 +933,13 @@ namespace Umbraco.Core.Services } #region Internal Methods - /// - /// Internal method to set the HttpContextBase for testing. - /// - /// - internal void SetHttpContext(HttpContextBase httpContext) - { - _httpContext = httpContext; - } - /// /// Internal method to Re-Publishes all Content for legacy purposes. /// /// Optional Id of the User issueing the publishing /// Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will not update the cache. /// True if publishing succeeded, otherwise False - internal bool RePublishAll(bool omitCacheRefresh = true, int userId = -1) + internal bool RePublishAll(bool omitCacheRefresh = true, int userId = 0) { return RePublishAllDo(omitCacheRefresh, userId); } @@ -974,7 +951,7 @@ namespace Umbraco.Core.Services /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache. /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - internal bool Publish(IContent content, bool omitCacheRefresh = true, int userId = -1) + internal bool Publish(IContent content, bool omitCacheRefresh = true, int userId = 0) { return SaveAndPublishDo(content, omitCacheRefresh, userId); } @@ -986,7 +963,7 @@ namespace Umbraco.Core.Services /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache. /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - internal bool PublishWithChildren(IContent content, bool omitCacheRefresh = true, int userId = -1) + internal bool PublishWithChildren(IContent content, bool omitCacheRefresh = true, int userId = 0) { return PublishWithChildrenDo(content, omitCacheRefresh, userId); } @@ -998,7 +975,7 @@ namespace Umbraco.Core.Services /// Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will not update the cache. /// Optional Id of the User issueing the publishing /// True if unpublishing succeeded, otherwise False - internal bool UnPublish(IContent content, bool omitCacheRefresh = true, int userId = -1) + internal bool UnPublish(IContent content, bool omitCacheRefresh = true, int userId = 0) { return UnPublishDo(content, omitCacheRefresh, userId); } @@ -1010,7 +987,7 @@ namespace Umbraco.Core.Services /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache. /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - internal bool SaveAndPublish(IContent content, bool omitCacheRefresh = true, int userId = -1) + internal bool SaveAndPublish(IContent content, bool omitCacheRefresh = true, int userId = 0) { return SaveAndPublishDo(content, omitCacheRefresh, userId); } @@ -1025,7 +1002,7 @@ namespace Umbraco.Core.Services /// Optional Id of the User issueing the publishing /// Optional boolean to avoid having the cache refreshed when calling this RePublish method. By default this method will update the cache. /// True if publishing succeeded, otherwise False - private bool RePublishAllDo(bool omitCacheRefresh = false, int userId = -1) + private bool RePublishAllDo(bool omitCacheRefresh = false, int userId = 0) { var list = new List(); var updated = new List(); @@ -1039,7 +1016,7 @@ namespace Umbraco.Core.Services if (content.IsValid()) { list.Add(content); - list.AddRange(GetChildrenDeep(content.Id)); + list.AddRange(GetDescendants(content)); } } @@ -1053,7 +1030,7 @@ namespace Umbraco.Core.Services //Only loop through content where the Published property has been updated foreach (var item in list.Where(x => ((ICanBeDirty)x).IsPropertyDirty("Published"))) { - SetWriter(item, userId); + item.WriterId = userId; repository.AddOrUpdate(item); updated.Add(item); } @@ -1076,7 +1053,7 @@ namespace Umbraco.Core.Services _publishingStrategy.PublishingFinalized(updated, true); } - Audit.Add(AuditTypes.Publish, "RePublish All performed by user", userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Publish, "RePublish All performed by user", userId, -1); return published; } @@ -1088,7 +1065,7 @@ namespace Umbraco.Core.Services /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache. /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - private bool PublishWithChildrenDo(IContent content, bool omitCacheRefresh = false, int userId = -1) + private bool PublishWithChildrenDo(IContent content, bool omitCacheRefresh = false, int userId = 0) { //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false) @@ -1115,7 +1092,7 @@ namespace Umbraco.Core.Services var updated = new List(); var list = new List(); list.Add(content); - list.AddRange(GetChildrenDeep(content.Id)); + list.AddRange(GetDescendants(content)); //Publish and then update the database with new status var published = _publishingStrategy.PublishWithChildren(list, userId); @@ -1127,7 +1104,7 @@ namespace Umbraco.Core.Services //Only loop through content where the Published property has been updated foreach (var item in list.Where(x => ((ICanBeDirty)x).IsPropertyDirty("Published"))) { - SetWriter(item, userId); + item.WriterId = userId; repository.AddOrUpdate(item); updated.Add(item); } @@ -1149,8 +1126,7 @@ namespace Umbraco.Core.Services if (omitCacheRefresh == false) _publishingStrategy.PublishingFinalized(updated, false); - Audit.Add(AuditTypes.Publish, "Publish with Children performed by user", userId == -1 ? 0 : userId, - content.Id); + Audit.Add(AuditTypes.Publish, "Publish with Children performed by user", userId, content.Id); } return published; @@ -1163,7 +1139,7 @@ namespace Umbraco.Core.Services /// Optional boolean to avoid having the cache refreshed when calling this Unpublish method. By default this method will update the cache. /// Optional Id of the User issueing the publishing /// True if unpublishing succeeded, otherwise False - private bool UnPublishDo(IContent content, bool omitCacheRefresh = false, int userId = -1) + private bool UnPublishDo(IContent content, bool omitCacheRefresh = false, int userId = 0) { var unpublished = _publishingStrategy.UnPublish(content, userId); if (unpublished) @@ -1171,6 +1147,7 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { + content.WriterId = userId; repository.AddOrUpdate(content); //Remove 'published' xml from the cmsContentXml table for the unpublished content @@ -1182,7 +1159,7 @@ namespace Umbraco.Core.Services if (omitCacheRefresh == false) _publishingStrategy.UnPublishingFinalized(content); - Audit.Add(AuditTypes.UnPublish, "UnPublish performed by user", userId == -1 ? 0 : userId, content.Id); + Audit.Add(AuditTypes.UnPublish, "UnPublish performed by user", userId, content.Id); } return unpublished; @@ -1195,7 +1172,7 @@ namespace Umbraco.Core.Services /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache. /// Optional Id of the User issueing the publishing /// True if publishing succeeded, otherwise False - private bool SaveAndPublishDo(IContent content, bool omitCacheRefresh = false, int userId = -1) + private bool SaveAndPublishDo(IContent content, bool omitCacheRefresh = false, int userId = 0) { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this)) return false; @@ -1227,7 +1204,8 @@ namespace Umbraco.Core.Services using (var repository = _repositoryFactory.CreateContentRepository(uow)) { //Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed - SetWriter(content, userId); + content.WriterId = userId; + repository.AddOrUpdate(content); uow.Commit(); @@ -1259,7 +1237,7 @@ namespace Umbraco.Core.Services _publishingStrategy.PublishingFinalized(shouldBeRepublished, false); } - Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId == -1 ? 0 : userId, content.Id); + Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId, content.Id); return published; } @@ -1270,7 +1248,7 @@ namespace Umbraco.Core.Services /// The to save /// Boolean indicating whether or not to change the Published state upon saving /// Optional Id of the User saving the Content - private void Save(IContent content, bool changeState, int userId = -1) + private void Save(IContent content, bool changeState, int userId = 0) { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this)) return; @@ -1278,7 +1256,7 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - SetWriter(content, userId); + content.WriterId = userId; //Only change the publish state if the "previous" version was actually published if (changeState && content.Published) @@ -1290,33 +1268,7 @@ namespace Umbraco.Core.Services Saved.RaiseEvent(new SaveEventArgs(content, false), this); - Audit.Add(AuditTypes.Save, "Save Content performed by user", userId == -1 ? 0 : userId, content.Id); - } - - /// - /// Gets a flat list of decendents of content from parent id - /// - /// - /// Only contains valid objects, which means - /// that everything in the returned list can be published. - /// If an invalid object is found it will not - /// be added to the list neither will its children. - /// - /// Id of the parent to retrieve children from - /// A list of valid that can be published - private IEnumerable GetChildrenDeep(int parentId) - { - var list = new List(); - var children = GetChildren(parentId); - foreach (var child in children) - { - if (child.IsValid()) - { - list.Add(child); - list.AddRange(GetChildrenDeep(child.Id)); - } - } - return list; + Audit.Add(AuditTypes.Save, "Save Content performed by user", userId, content.Id); } /// @@ -1353,63 +1305,6 @@ namespace Umbraco.Core.Services return true; } - /// - /// Updates a content object with the User (id), who created the content. - /// - /// object to update - /// Optional Id of the User - private void SetUser(IContent content, int userId) - { - if (userId > -1) - { - //If a user id was passed in we use that - content.CreatorId = userId; - } - else if (UserServiceOrContext()) - { - var profile = _httpContext == null - ? _userService.GetCurrentBackOfficeUser() - : _userService.GetCurrentBackOfficeUser(_httpContext); - content.CreatorId = profile.Id.SafeCast(); - } - else - { - //Otherwise we default to Admin user, which should always exist (almost always) - content.CreatorId = 0; - } - } - - /// - /// Updates a content object with a Writer (user id), who updated the content. - /// - /// object to update - /// Optional Id of the Writer - private void SetWriter(IContent content, int userId) - { - if (userId > -1) - { - //If a user id was passed in we use that - content.WriterId = userId; - } - else if (UserServiceOrContext()) - { - var profile = _httpContext == null - ? _userService.GetCurrentBackOfficeUser() - : _userService.GetCurrentBackOfficeUser(_httpContext); - content.WriterId = profile.Id.SafeCast(); - } - else - { - //Otherwise we default to Admin user, which should always exist (almost always) - content.WriterId = 0; - } - } - - private bool UserServiceOrContext() - { - return _userService != null && (HttpContext.Current != null || _httpContext != null); - } - #endregion #region Event Handlers diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index bae66f95a5..0af521dddd 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -1,9 +1,7 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Web; using Umbraco.Core.Auditing; using Umbraco.Core.Configuration; using Umbraco.Core.Events; @@ -23,9 +21,7 @@ namespace Umbraco.Core.Services private readonly RepositoryFactory _repositoryFactory; private readonly IContentService _contentService; private readonly IMediaService _mediaService; - private readonly IUserService _userService; private readonly IDatabaseUnitOfWorkProvider _uowProvider; - private HttpContextBase _httpContext; public ContentTypeService(IContentService contentService, IMediaService mediaService) : this(new PetaPocoUnitOfWorkProvider(), new RepositoryFactory(), contentService, mediaService) @@ -43,15 +39,6 @@ namespace Umbraco.Core.Services _mediaService = mediaService; } - internal ContentTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IContentService contentService, IMediaService mediaService, IUserService userService) - { - _uowProvider = provider; - _repositoryFactory = repositoryFactory; - _contentService = contentService; - _mediaService = mediaService; - _userService = userService; - } - /// /// Gets an object by its Id /// @@ -129,7 +116,7 @@ namespace Umbraco.Core.Services /// /// to save /// Optional id of the user saving the ContentType - public void Save(IContentType contentType, int userId = -1) + public void Save(IContentType contentType, int userId = 0) { if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs(contentType), this)) return; @@ -137,7 +124,7 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) { - SetUser(contentType, userId); + contentType.CreatorId = userId; repository.AddOrUpdate(contentType); uow.Commit(); @@ -145,7 +132,7 @@ namespace Umbraco.Core.Services SavedContentType.RaiseEvent(new SaveEventArgs(contentType, false), this); } - Audit.Add(AuditTypes.Save, string.Format("Save ContentType performed by user"), userId == -1 ? 0 : userId, contentType.Id); + Audit.Add(AuditTypes.Save, string.Format("Save ContentType performed by user"), userId, contentType.Id); } /// @@ -153,7 +140,7 @@ namespace Umbraco.Core.Services /// /// Collection of to save /// Optional id of the user saving the ContentType - public void Save(IEnumerable contentTypes, int userId = -1) + public void Save(IEnumerable contentTypes, int userId = 0) { if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs(contentTypes), this)) return; @@ -163,7 +150,7 @@ namespace Umbraco.Core.Services { foreach (var contentType in contentTypes) { - SetUser(contentType, userId); + contentType.CreatorId = userId; repository.AddOrUpdate(contentType); } @@ -173,7 +160,7 @@ namespace Umbraco.Core.Services SavedContentType.RaiseEvent(new SaveEventArgs(contentTypes, false), this); } - Audit.Add(AuditTypes.Save, string.Format("Save ContentTypes performed by user"), userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Save, string.Format("Save ContentTypes performed by user"), userId, -1); } /// @@ -182,7 +169,7 @@ namespace Umbraco.Core.Services /// to delete /// Optional id of the user issueing the delete /// Deleting a will delete all the objects based on this - public void Delete(IContentType contentType, int userId = -1) + public void Delete(IContentType contentType, int userId = 0) { if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs(contentType), this)) return; @@ -198,7 +185,7 @@ namespace Umbraco.Core.Services DeletedContentType.RaiseEvent(new DeleteEventArgs(contentType, false), this); } - Audit.Add(AuditTypes.Delete, string.Format("Delete ContentType performed by user"), userId == -1 ? 0 : userId, contentType.Id); + Audit.Add(AuditTypes.Delete, string.Format("Delete ContentType performed by user"), userId, contentType.Id); } /// @@ -209,7 +196,7 @@ namespace Umbraco.Core.Services /// /// Deleting a will delete all the objects based on this /// - public void Delete(IEnumerable contentTypes, int userId = -1) + public void Delete(IEnumerable contentTypes, int userId = 0) { if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs(contentTypes), this)) return; @@ -233,7 +220,7 @@ namespace Umbraco.Core.Services DeletedContentType.RaiseEvent(new DeleteEventArgs(contentTypes, false), this); } - Audit.Add(AuditTypes.Delete, string.Format("Delete ContentTypes performed by user"), userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1); } /// @@ -313,7 +300,7 @@ namespace Umbraco.Core.Services /// /// to save /// Optional Id of the user saving the MediaType - public void Save(IMediaType mediaType, int userId = -1) + public void Save(IMediaType mediaType, int userId = 0) { if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs(mediaType), this)) return; @@ -321,14 +308,14 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) { - SetUser(mediaType, userId); + mediaType.CreatorId = userId; repository.AddOrUpdate(mediaType); uow.Commit(); SavedMediaType.RaiseEvent(new SaveEventArgs(mediaType, false), this); } - Audit.Add(AuditTypes.Save, string.Format("Save MediaType performed by user"), userId == -1 ? 0 : userId, mediaType.Id); + Audit.Add(AuditTypes.Save, string.Format("Save MediaType performed by user"), userId, mediaType.Id); } /// @@ -336,7 +323,7 @@ namespace Umbraco.Core.Services /// /// Collection of to save /// Optional Id of the user savging the MediaTypes - public void Save(IEnumerable mediaTypes, int userId = -1) + public void Save(IEnumerable mediaTypes, int userId = 0) { if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs(mediaTypes), this)) return; @@ -347,7 +334,7 @@ namespace Umbraco.Core.Services foreach (var mediaType in mediaTypes) { - SetUser(mediaType, userId); + mediaType.CreatorId = userId; repository.AddOrUpdate(mediaType); } @@ -357,7 +344,7 @@ namespace Umbraco.Core.Services SavedMediaType.RaiseEvent(new SaveEventArgs(mediaTypes, false), this); } - Audit.Add(AuditTypes.Save, string.Format("Save MediaTypes performed by user"), userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Save, string.Format("Save MediaTypes performed by user"), userId, -1); } /// @@ -366,7 +353,7 @@ namespace Umbraco.Core.Services /// to delete /// Optional Id of the user deleting the MediaType /// Deleting a will delete all the objects based on this - public void Delete(IMediaType mediaType, int userId = -1) + public void Delete(IMediaType mediaType, int userId = 0) { if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs(mediaType), this)) return; @@ -383,7 +370,7 @@ namespace Umbraco.Core.Services DeletedMediaType.RaiseEvent(new DeleteEventArgs(mediaType, false), this); } - Audit.Add(AuditTypes.Delete, string.Format("Delete MediaType performed by user"), userId == -1 ? 0 : userId, mediaType.Id); + Audit.Add(AuditTypes.Delete, string.Format("Delete MediaType performed by user"), userId, mediaType.Id); } /// @@ -392,7 +379,7 @@ namespace Umbraco.Core.Services /// Collection of to delete /// /// Deleting a will delete all the objects based on this - public void Delete(IEnumerable mediaTypes, int userId = -1) + public void Delete(IEnumerable mediaTypes, int userId = 0) { if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs(mediaTypes), this)) return; @@ -415,7 +402,7 @@ namespace Umbraco.Core.Services DeletedMediaType.RaiseEvent(new DeleteEventArgs(mediaTypes, false), this); } - Audit.Add(AuditTypes.Delete, string.Format("Delete MediaTypes performed by user"), userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Delete, string.Format("Delete MediaTypes performed by user"), userId, -1); } /// @@ -473,46 +460,6 @@ namespace Umbraco.Core.Services return dtd.ToString(); } - /// - /// Internal method to set the HttpContextBase for testing. - /// - /// - internal void SetHttpContext(HttpContextBase httpContext) - { - _httpContext = httpContext; - } - - /// - /// Updates a content object with the User (id), who created the content. - /// - /// ContentType object to update - /// Optional Id of the User - private void SetUser(IContentTypeBase contentType, int userId) - { - if (userId > -1) - { - //If a user id was passed in we use that - contentType.CreatorId = userId; - } - else if (UserServiceOrContext()) - { - var profile = _httpContext == null - ? _userService.GetCurrentBackOfficeUser() - : _userService.GetCurrentBackOfficeUser(_httpContext); - contentType.CreatorId = profile.Id.SafeCast(); - } - else - { - //Otherwise we default to Admin user, which should always exist (almost always) - contentType.CreatorId = 0; - } - } - - private bool UserServiceOrContext() - { - return _userService != null && (HttpContext.Current != null || _httpContext != null); - } - #region Event Handlers /// diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 49ad5953a4..50ef680d1c 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -117,7 +117,7 @@ namespace Umbraco.Core.Services /// /// to save /// Id of the user issueing the save - public void Save(IDataTypeDefinition dataTypeDefinition, int userId = -1) + public void Save(IDataTypeDefinition dataTypeDefinition, int userId = 0) { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(dataTypeDefinition), this)) return; @@ -125,14 +125,14 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow)) { - dataTypeDefinition.CreatorId = userId > -1 ? userId : 0; + dataTypeDefinition.CreatorId = userId; repository.AddOrUpdate(dataTypeDefinition); uow.Commit(); Saved.RaiseEvent(new SaveEventArgs(dataTypeDefinition, false), this); } - Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId == -1 ? 0 : userId, dataTypeDefinition.Id); + Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id); } /// @@ -144,7 +144,7 @@ namespace Umbraco.Core.Services /// /// to delete /// Optional Id of the user issueing the deletion - public void Delete(IDataTypeDefinition dataTypeDefinition, int userId = -1) + public void Delete(IDataTypeDefinition dataTypeDefinition, int userId = 0) { if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(dataTypeDefinition), this)) return; @@ -181,7 +181,7 @@ namespace Umbraco.Core.Services Deleted.RaiseEvent(new DeleteEventArgs(dataTypeDefinition, false), this); } - Audit.Add(AuditTypes.Delete, string.Format("Delete DataTypeDefinition performed by user"), userId == -1 ? 0 : userId, dataTypeDefinition.Id); + Audit.Add(AuditTypes.Delete, string.Format("Delete DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id); } /// diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs index 4130da307a..ace5d1d612 100644 --- a/src/Umbraco.Core/Services/FileService.cs +++ b/src/Umbraco.Core/Services/FileService.cs @@ -63,7 +63,7 @@ namespace Umbraco.Core.Services /// /// to save /// - public void SaveStylesheet(Stylesheet stylesheet, int userId = -1) + public void SaveStylesheet(Stylesheet stylesheet, int userId = 0) { if (SavingStylesheet.IsRaisedEventCancelled(new SaveEventArgs(stylesheet), this)) return; @@ -77,7 +77,7 @@ namespace Umbraco.Core.Services SavedStylesheet.RaiseEvent(new SaveEventArgs(stylesheet, false), this); } - Audit.Add(AuditTypes.Save, string.Format("Save Stylesheet performed by user"), userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Save, string.Format("Save Stylesheet performed by user"), userId, -1); } /// @@ -85,7 +85,7 @@ namespace Umbraco.Core.Services /// /// Name incl. extension of the Stylesheet to delete /// - public void DeleteStylesheet(string name, int userId = -1) + public void DeleteStylesheet(string name, int userId = 0) { var uow = _fileUowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateStylesheetRepository(uow)) @@ -100,7 +100,7 @@ namespace Umbraco.Core.Services DeletedStylesheet.RaiseEvent(new DeleteEventArgs(stylesheet, false), this); - Audit.Add(AuditTypes.Delete, string.Format("Delete Stylesheet performed by user"), userId == -1 ? 0 : userId, -1); + Audit.Add(AuditTypes.Delete, string.Format("Delete Stylesheet performed by user"), userId, -1); } } @@ -144,7 +144,7 @@ namespace Umbraco.Core.Services /// /// to save /// - public void SaveScript(Script script, int userId = -1) + public void SaveScript(Script script, int userId = 0) { if (SavingScript.IsRaisedEventCancelled(new SaveEventArgs