diff --git a/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj b/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj index 2f2bb5866d..454a6cf2ce 100644 --- a/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj +++ b/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj @@ -49,11 +49,9 @@ ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll - True ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll - True diff --git a/src/Umbraco.Core/Logging/RollingFileCleanupAppender.cs b/src/Umbraco.Core/Logging/RollingFileCleanupAppender.cs new file mode 100644 index 0000000000..6be2552296 --- /dev/null +++ b/src/Umbraco.Core/Logging/RollingFileCleanupAppender.cs @@ -0,0 +1,95 @@ +using System; +using System.IO; +using log4net.Appender; +using log4net.Util; + +namespace Umbraco.Core.Logging +{ + /// + /// This class will do the exact same thing as the RollingFileAppender that comes from log4net + /// With the extension, that it is able to do automatic cleanup of the logfiles in the directory where logging happens + /// + /// By specifying the properties MaxLogFileDays and BaseFilePattern, the files will automaticly get deleted when + /// the logger is configured(typically when the app starts). To utilize this appender swap out the type of the rollingFile appender + /// that ships with Umbraco, to be Umbraco.Core.Logging.RollingFileCleanupAppender, and add the maxLogFileDays and baseFilePattern elements + /// to the configuration i.e.: + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public class RollingFileCleanupAppender : RollingFileAppender + { + public int MaxLogFileDays { get; set; } + public string BaseFilePattern { get; set; } + + /// + /// This override will delete logs older than the specified amount of days + /// + /// + /// + protected override void OpenFile(string fileName, bool append) + { + bool cleanup = true; + // Validate settings and input + if (MaxLogFileDays <= 0) + { + LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'MaxLogFileDays' needs to be a positive integer, aborting cleanup"); + cleanup = false; + } + + if (string.IsNullOrWhiteSpace(BaseFilePattern)) + { + LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'BaseFilePattern' is empty, aborting cleanup"); + cleanup = false; + } + // grab the directory we are logging to, as this is were we will search for older logfiles + var logFolder = Path.GetDirectoryName(fileName); + if (Directory.Exists(logFolder) == false) + { + LogLog.Warn(typeof(RollingFileCleanupAppender), string.Format("Directory '{0}' for logfiles does not exist, aborting cleanup", logFolder)); + cleanup = false; + } + // If everything is validated, we can do the actual cleanup + if (cleanup) + { + Cleanup(logFolder); + } + + base.OpenFile(fileName, append); + } + + private void Cleanup(string directoryPath) + { + // only take files that matches the pattern we are using i.e. UmbracoTraceLog.*.txt.* + string[] logFiles = Directory.GetFiles(directoryPath, BaseFilePattern); + LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Found {0} files that matches the baseFilePattern: '{1}'", logFiles.Length, BaseFilePattern)); + + foreach (var logFile in logFiles) + { + DateTime lastAccessTime = System.IO.File.GetLastWriteTimeUtc(logFile); + // take the value from the config file + if (lastAccessTime < DateTime.Now.AddDays(-MaxLogFileDays)) + { + LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Deleting file {0} as its lastAccessTime is older than {1} days speficied by MaxLogFileDays", logFile, MaxLogFileDays)); + base.DeleteFile(logFile); + } + } + } + } +} diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index 7de374b140..61a34ce5f8 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -377,7 +377,7 @@ namespace Umbraco.Core.Services repo.Delete(container); uow.Commit(); deleteEventArgs.CanCancel = false; - uow.Events.Dispatch(DeletedMediaTypeContainer, this, deleteEventArgs); + uow.Events.Dispatch(DeletedMediaTypeContainer, this, deleteEventArgs, "DeletedMediaTypeContainer"); return OperationStatus.Success(evtMsgs); //TODO: Audit trail ? diff --git a/src/Umbraco.Core/UdiEntityType.cs b/src/Umbraco.Core/UdiEntityType.cs index b33e9c2ad7..8213edbfc1 100644 --- a/src/Umbraco.Core/UdiEntityType.cs +++ b/src/Umbraco.Core/UdiEntityType.cs @@ -118,7 +118,7 @@ namespace Umbraco.Core case UmbracoObjectTypes.Document: return Document; case UmbracoObjectTypes.DocumentBlueprint: - return DocumentBlueprint; + return DocumentBluePrint; case UmbracoObjectTypes.Media: return Media; case UmbracoObjectTypes.Member: @@ -163,7 +163,7 @@ namespace Umbraco.Core { case Document: return UmbracoObjectTypes.Document; - case DocumentBlueprint: + case DocumentBluePrint: return UmbracoObjectTypes.DocumentBlueprint; case Media: return UmbracoObjectTypes.Media; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index c2d90cb383..345ee8da8d 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -39,18 +39,15 @@ ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll - True ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll - True ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll - True ..\packages\ImageProcessor.2.5.6\lib\net45\ImageProcessor.dll @@ -63,11 +60,9 @@ ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll - True ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll - True ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll @@ -83,17 +78,16 @@ ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - True ..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll + True ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll ..\packages\Owin.1.0\lib\net40\Owin.dll - True ..\packages\semver.1.1.2\lib\net45\Semver.dll @@ -105,11 +99,9 @@ ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll - True ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll - True @@ -368,6 +360,7 @@ + diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index 64fef90ffa..6cad6893f5 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -40,34 +40,27 @@ ..\packages\BenchmarkDotNet.0.9.9\lib\net45\BenchmarkDotNet.dll - True ..\packages\BenchmarkDotNet.Core.0.9.9\lib\net45\BenchmarkDotNet.Core.dll - True ..\packages\BenchmarkDotNet.Diagnostics.Windows.0.9.9\lib\net45\BenchmarkDotNet.Diagnostics.Windows.dll - True ..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.9.9\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll - True ..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll ..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - True ..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll - True ..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll - True ..\packages\Moq.4.1.1309.0919\lib\net40\Moq.dll @@ -75,27 +68,22 @@ ..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - True ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll - True ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll - True ..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - True ..\packages\System.Threading.Tasks.Extensions.4.0.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll - True @@ -116,6 +104,7 @@ + @@ -132,8 +121,8 @@ - - + + diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index f669416643..db0b5c7c85 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -62,8 +62,8 @@ ..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll diff --git a/src/Umbraco.Tests/packages.config b/src/Umbraco.Tests/packages.config index 921ac155c7..6075f6da6d 100644 --- a/src/Umbraco.Tests/packages.config +++ b/src/Umbraco.Tests/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js index e3a50b482c..0b2853a174 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js @@ -366,6 +366,9 @@ angular.module("umbraco.directives") // element might still be there even after the modal has been hidden. scope.$on('$destroy', function () { unsubscribe(); + if (tinyMceEditor !== undefined && tinyMceEditor != null) { + tinyMceEditor.destroy() + } }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/embed/embed.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/embed/embed.html index 8c2e5d6bc6..6a829e6be4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/embed/embed.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/embed/embed.html @@ -2,7 +2,7 @@ - + @@ -12,15 +12,15 @@
- + - + - +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index d17310d65a..a11a4dae9f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -374,6 +374,9 @@ angular.module("umbraco") // element might still be there even after the modal has been hidden. $scope.$on('$destroy', function () { unsubscribe(); + if (tinyMceEditor !== undefined && tinyMceEditor != null) { + tinyMceEditor.destroy() + } }); }); }); diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 6f96590bf2..4b35b30753 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -127,11 +127,10 @@ ..\packages\dotless.1.5.2\lib\dotless.Core.dll - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll - False ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll @@ -144,7 +143,6 @@ ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll - False ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml index 06c8eb017f..a7cc7cad39 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml @@ -422,7 +422,7 @@ Hvilken side skal vises etter at skjemaet er sendt Størrelse Sorter - Submit + Send Type Søk... Opp @@ -439,6 +439,17 @@ Ja Mappe Søkeresultater + Sorter + Avslutt sortering + Eksempel + Bytt passord + til + Listevisning + Lagrer... + nåværende + Innbygging + Hent + valgt Bakgrunnsfarge diff --git a/src/Umbraco.Web.UI/packages.config b/src/Umbraco.Web.UI/packages.config index 13b0d501eb..783b4eaa18 100644 --- a/src/Umbraco.Web.UI/packages.config +++ b/src/Umbraco.Web.UI/packages.config @@ -4,7 +4,7 @@ - + diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 76989945e0..1c1f03f140 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -590,7 +590,6 @@ Sortér Status Indsend - Type Skriv for at søge... Op @@ -616,6 +615,7 @@ Gemmer... nuværende Indlejring + Hent valgt diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 0674e81066..c0ba47e470 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -638,6 +638,7 @@ Saving... current Embed + Retrieve selected diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index b765116090..777e5ee378 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -649,6 +649,7 @@ Saving... current Embed + Retrieve selected diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml index 2fae24db21..aad6f440f9 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml @@ -411,7 +411,7 @@ Vilken sida skall visas när formuläret är skickat Storlek Sortera - Submit + Skicka Skriv Skriv för att söka... Upp @@ -426,8 +426,17 @@ Bredd Titta på Ja - Reorder - I am done reordering + Sortera + Avsluta sortering + Förhandsvisning + Ändra lösenord + till + Listvy + Sparar... + nuvarande + Inbäddning + Hämta + valgt Bakgrundsfärg diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index 5e246c0d59..5921b9c61c 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -555,7 +555,7 @@ namespace Umbraco.Web.Editors var builtInAliases = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray(); foreach (var p in contentItem.PersistedContent.Properties) { - var valueMapped = currProps.SingleOrDefault(x => x.Alias == p.Alias); + var valueMapped = currProps.FirstOrDefault(x => x.Alias == p.Alias); if (builtInAliases.Contains(p.Alias) == false && valueMapped != null) { p.Value = valueMapped.Value; diff --git a/src/Umbraco.Web/ExamineStartup.cs b/src/Umbraco.Web/ExamineStartup.cs new file mode 100644 index 0000000000..e149caabb3 --- /dev/null +++ b/src/Umbraco.Web/ExamineStartup.cs @@ -0,0 +1,176 @@ +using System.Collections.Generic; +using System.Linq; +using Examine; +using Examine.Config; +using Examine.LuceneEngine; +using Examine.LuceneEngine.Providers; +using Examine.Providers; +using Lucene.Net.Index; +using Lucene.Net.Store; +using Umbraco.Core; +using Umbraco.Core.Logging; +using UmbracoExamine; + +namespace Umbraco.Web +{ + /// + /// Used to configure Examine during startup for the web application + /// + internal class ExamineStartup + { + private readonly List _indexesToRebuild = new List(); + private readonly ApplicationContext _appCtx; + private readonly ProfilingLogger _profilingLogger; + + //this is used if we are not the MainDom, in which case we need to ensure that if indexes need rebuilding that this + //doesn't occur since that should only occur when we are MainDom + private bool _disableExamineIndexing = false; + + public ExamineStartup(ApplicationContext appCtx) + { + _appCtx = appCtx; + _profilingLogger = appCtx.ProfilingLogger; + } + + /// + /// Called during the initialize operation of the boot manager process + /// + public void Initialize() + { + //We want to manage Examine's appdomain shutdown sequence ourselves so first we'll disable Examine's default behavior + //and then we'll use MainDom to control Examine's shutdown + ExamineManager.DisableDefaultHostingEnvironmentRegistration(); + + //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain + //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock + //which simply checks the existence of the lock file + DirectoryTracker.DefaultLockFactory = d => + { + var simpleFsLockFactory = new NoPrefixSimpleFsLockFactory(d); + return simpleFsLockFactory; + }; + + //This is basically a hack for this item: http://issues.umbraco.org/issue/U4-5976 + // when Examine initializes it will try to rebuild if the indexes are empty, however in many cases not all of Examine's + // event handlers will be assigned during bootup when the rebuilding starts which is a problem. So with the examine 0.1.58.2941 build + // it has an event we can subscribe to in order to cancel this rebuilding process, but what we'll do is cancel it and postpone the rebuilding until the + // boot process has completed. It's a hack but it works. + ExamineManager.Instance.BuildingEmptyIndexOnStartup += OnInstanceOnBuildingEmptyIndexOnStartup; + + //let's deal with shutting down Examine with MainDom + var examineShutdownRegistered = _appCtx.MainDom.Register(() => + { + using (_profilingLogger.TraceDuration("Examine shutting down")) + { + //Due to the way Examine's own IRegisteredObject works, we'll first run it with immediate=false and then true so that + //it's correct subroutines are executed (otherwise we'd have to run this logic manually ourselves) + ExamineManager.Instance.Stop(false); + ExamineManager.Instance.Stop(true); + } + }); + if (examineShutdownRegistered) + { + _profilingLogger.Logger.Debug("Examine shutdown registered with MainDom"); + } + else + { + _profilingLogger.Logger.Debug("Examine shutdown not registered, this appdomain is not the MainDom"); + + //if we could not register the shutdown examine ourselves, it means we are not maindom! in this case all of examine should be disabled + //from indexing anything on startup!! + _disableExamineIndexing = true; + Suspendable.ExamineEvents.SuspendIndexers(); + } + } + + /// + /// Called during the Complete operation of the boot manager process + /// + public void Complete() + { + //We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending + //indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because + //that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems. + foreach (var luceneIndexer in ExamineManager.Instance.IndexProviderCollection.OfType()) + { + luceneIndexer.WaitForIndexQueueOnShutdown = false; + } + + //Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them + // (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually + // initialize during startup, in which case we want it to rebuild the indexes itself. + ExamineManager.Instance.BuildingEmptyIndexOnStartup -= OnInstanceOnBuildingEmptyIndexOnStartup; + + //don't do anything if we have disabled this + if (_disableExamineIndexing == false) + { + foreach (var indexer in _indexesToRebuild) + { + indexer.RebuildIndex(); + } + } + } + + /// + /// Called to perform the rebuilding indexes on startup if the indexes don't exist + /// + public void RebuildIndexes() + { + //don't do anything if we have disabled this + if (_disableExamineIndexing) return; + + //If the developer has explicitly opted out of rebuilding indexes on startup then we + // should adhere to that and not do it, this means that if they are load balancing things will be + // out of sync if they are auto-scaling but there's not much we can do about that. + if (ExamineSettings.Instance.RebuildOnAppStart == false) return; + + foreach (var indexer in GetIndexesForColdBoot()) + { + indexer.RebuildIndex(); + } + } + + /// + /// The method used to create indexes on a cold boot + /// + /// + /// A cold boot is when the server determines it will not (or cannot) process instructions in the cache table and + /// will rebuild it's own caches itself. + /// + public IEnumerable GetIndexesForColdBoot() + { + // NOTE: This is IMPORTANT! ... we don't want to rebuild any index that is already flagged to be re-indexed + // on startup based on our _indexesToRebuild variable and how Examine auto-rebuilds when indexes are empty. + // This callback is used above for the DatabaseServerMessenger startup options. + + // all indexes + IEnumerable indexes = ExamineManager.Instance.IndexProviderCollection; + + // except those that are already flagged + // and are processed in Complete() + if (_indexesToRebuild.Any()) + indexes = indexes.Except(_indexesToRebuild); + + // return + foreach (var index in indexes) + yield return index; + } + + private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args) + { + //store the indexer that needs rebuilding because it's empty for when the boot process + // is complete and cancel this current event so the rebuild process doesn't start right now. + args.Cancel = true; + _indexesToRebuild.Add((BaseIndexProvider)args.Indexer); + + //check if the index is rebuilding due to an error and log it + if (args.IsHealthy == false) + { + var baseIndex = args.Indexer as BaseIndexProvider; + var name = baseIndex != null ? baseIndex.Name : "[UKNOWN]"; + + _profilingLogger.Logger.Error(string.Format("The index {0} is rebuilding due to being unreadable/corrupt", name), args.UnhealthyException); + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs index 919a531549..52cca003b7 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs @@ -86,7 +86,16 @@ namespace Umbraco.Web.Scheduling finally { if (tempContext != null) + { + // because we created an http context and assigned it to UmbracoContext, + // the batched messenger does batch instructions, but since there is no + // request, we need to explicitely tell it to flush the batch of instrs. + var batchedMessenger = ServerMessengerResolver.Current.Messenger as BatchedDatabaseServerMessenger; + if (batchedMessenger != null) + batchedMessenger.FlushBatch(); + tempContext.Dispose(); // nulls the ThreadStatic context + } } return true; // repeat diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 82bc790eb0..99a1582f19 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -112,8 +112,8 @@ ..\packages\dotless.1.5.2\lib\dotless.Core.dll - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll @@ -121,11 +121,9 @@ ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - True ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - True ..\packages\Markdown.1.14.7\lib\net45\MarkdownSharp.dll @@ -335,6 +333,7 @@ + diff --git a/src/Umbraco.Web/WebApi/Binders/MemberBinder.cs b/src/Umbraco.Web/WebApi/Binders/MemberBinder.cs index 49669fd427..7a1913ce1a 100644 --- a/src/Umbraco.Web/WebApi/Binders/MemberBinder.cs +++ b/src/Umbraco.Web/WebApi/Binders/MemberBinder.cs @@ -97,17 +97,8 @@ namespace Umbraco.Web.WebApi.Binders if (member == null) { throw new InvalidOperationException("Could not find member with key " + key); - } + } - var standardProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); - - //remove all membership properties, these values are set with the membership provider. - var exclude = standardProps.Select(x => x.Value.Alias).ToArray(); - - foreach (var remove in exclude) - { - member.Properties.Remove(remove); - } return member; } diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 2f6b81820f..c38540b6a2 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.Linq; -using System.Reflection; using System.Web; using System.Web.Configuration; using System.Web.Http; @@ -11,10 +10,7 @@ using System.Web.Http.Dispatcher; using System.Web.Mvc; using System.Web.Routing; using ClientDependency.Core.Config; -using Examine; -using Examine.Config; using Examine.Providers; -using umbraco; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; @@ -27,25 +23,18 @@ using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Sync; using Umbraco.Web.Dictionary; using Umbraco.Web.Install; -using Umbraco.Web.Macros; using Umbraco.Web.Media; using Umbraco.Web.Media.ThumbnailProviders; -using Umbraco.Web.Models; using Umbraco.Web.Mvc; -using Umbraco.Web.PropertyEditors; -using Umbraco.Web.PropertyEditors.ValueConverters; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Security; -using Umbraco.Web.Scheduling; using Umbraco.Web.UI.JavaScript; using Umbraco.Web.WebApi; -using umbraco.BusinessLogic; using Umbraco.Core.Cache; using Umbraco.Core.Events; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.UnitOfWork; -using Umbraco.Core.Publishing; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Web.Editors; @@ -64,8 +53,9 @@ namespace Umbraco.Web public class WebBootManager : CoreBootManager { private readonly bool _isForTesting; - //NOTE: see the Initialize method for what this is used for - private static readonly List IndexesToRebuild = new List(); + + //needs to be static because we have the public static method GetIndexesForColdBoot + private static ExamineStartup _examineStartup; public WebBootManager(UmbracoApplicationBase umbracoApplication) : base(umbracoApplication) @@ -109,15 +99,11 @@ namespace Umbraco.Web /// public override IBootManager Initialize() { - //This is basically a hack for this item: http://issues.umbraco.org/issue/U4-5976 - // when Examine initializes it will try to rebuild if the indexes are empty, however in many cases not all of Examine's - // event handlers will be assigned during bootup when the rebuilding starts which is a problem. So with the examine 0.1.58.2941 build - // it has an event we can subscribe to in order to cancel this rebuilding process, but what we'll do is cancel it and postpone the rebuilding until the - // boot process has completed. It's a hack but it works. - ExamineManager.Instance.BuildingEmptyIndexOnStartup += OnInstanceOnBuildingEmptyIndexOnStartup; - base.Initialize(); + _examineStartup = new ExamineStartup(ApplicationContext); + _examineStartup.Initialize(); + // 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; @@ -214,25 +200,15 @@ namespace Umbraco.Web //Now, startup all of our legacy startup handler ApplicationEventsResolver.Current.InstantiateLegacyStartupHandlers(); - //Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them - // (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually - // initialize during startup, in which case we want it to rebuild the indexes itself. - ExamineManager.Instance.BuildingEmptyIndexOnStartup -= OnInstanceOnBuildingEmptyIndexOnStartup; - if (IndexesToRebuild.Any()) - { - foreach (var indexer in IndexesToRebuild) - { - indexer.RebuildIndex(); - } - } + _examineStartup.Complete(); //Now ensure webapi is initialized after everything GlobalConfiguration.Configuration.EnsureInitialized(); - + return this; } - + internal static void ConfigureGlobalFilters() { @@ -377,11 +353,11 @@ namespace Umbraco.Web { base.InitializeResolvers(); - SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees()); + SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees()); XsltExtensionsResolver.Current = new XsltExtensionsResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveXsltExtensions()); - EditorValidationResolver.Current= new EditorValidationResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveTypes()); + EditorValidationResolver.Current = new EditorValidationResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveTypes()); //set the default RenderMvcController DefaultRenderMvcControllerResolver.Current = new DefaultRenderMvcControllerResolver(typeof(RenderMvcController)); @@ -421,23 +397,6 @@ namespace Umbraco.Web } else { - - //We are using a custom action here so we can check the examine settings value first, we don't want to - // put that check into the CreateIndexesOnColdBoot method because developers may choose to use this - // method directly and they will be in charge of this check if they need it - Action rebuildIndexes = () => - { - //If the developer has explicitly opted out of rebuilding indexes on startup then we - // should adhere to that and not do it, this means that if they are load balancing things will be - // out of sync if they are auto-scaling but there's not much we can do about that. - if (ExamineSettings.Instance.RebuildOnAppStart == false) return; - - foreach (var indexer in GetIndexesForColdBoot()) - { - indexer.RebuildIndex(); - } - }; - ServerMessengerResolver.Current.SetServerMessenger(new BatchedDatabaseServerMessenger( ApplicationContext, true, @@ -453,7 +412,7 @@ namespace Umbraco.Web //rebuild indexes if the server is not synced // NOTE: This will rebuild ALL indexes including the members, if developers want to target specific // indexes then they can adjust this logic themselves. - rebuildIndexes + () => _examineStartup.RebuildIndexes() } })); } @@ -489,9 +448,9 @@ namespace Umbraco.Web // 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) - }); + { + typeof (RenderControllerFactory) + }); UrlProviderResolver.Current = new UrlProviderResolver( ServiceProvider, LoggerResolver.Current.Logger, @@ -559,42 +518,11 @@ namespace Umbraco.Web /// /// A cold boot is when the server determines it will not (or cannot) process instructions in the cache table and /// will rebuild it's own caches itself. + /// TODO: Does this method need to exist? Is it used publicly elsewhere (i.e. outside of core?) /// public static IEnumerable GetIndexesForColdBoot() { - // NOTE: This is IMPORTANT! ... we don't want to rebuild any index that is already flagged to be re-indexed - // on startup based on our _indexesToRebuild variable and how Examine auto-rebuilds when indexes are empty. - // This callback is used above for the DatabaseServerMessenger startup options. - - // all indexes - IEnumerable indexes = ExamineManager.Instance.IndexProviderCollection; - - // except those that are already flagged - // and are processed in Complete() - if (IndexesToRebuild.Any()) - indexes = indexes.Except(IndexesToRebuild); - - // return - foreach (var index in indexes) - yield return index; - } - - - private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args) - { - //store the indexer that needs rebuilding because it's empty for when the boot process - // is complete and cancel this current event so the rebuild process doesn't start right now. - args.Cancel = true; - IndexesToRebuild.Add((BaseIndexProvider)args.Indexer); - - //check if the index is rebuilding due to an error and log it - if (args.IsHealthy == false) - { - var baseIndex = args.Indexer as BaseIndexProvider; - var name = baseIndex != null ? baseIndex.Name : "[UKNOWN]"; - - ProfilingLogger.Logger.Error(string.Format("The index {0} is rebuilding due to being unreadable/corrupt", name), args.UnhealthyException); - } + return _examineStartup.GetIndexesForColdBoot(); } } } diff --git a/src/Umbraco.Web/WebServices/ExamineManagementApiController.cs b/src/Umbraco.Web/WebServices/ExamineManagementApiController.cs index ca49f7a9f7..1218ddc2da 100644 --- a/src/Umbraco.Web/WebServices/ExamineManagementApiController.cs +++ b/src/Umbraco.Web/WebServices/ExamineManagementApiController.cs @@ -8,7 +8,9 @@ using Examine; using Examine.LuceneEngine; using Examine.LuceneEngine.Providers; using Examine.Providers; +using Lucene.Net.Index; using Lucene.Net.Search; +using Lucene.Net.Store; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Web.Search; @@ -189,20 +191,39 @@ namespace Umbraco.Web.WebServices { indexer.RebuildIndex(); } + catch (LockObtainFailedException) + { + //this will occur if the index is locked (which it should defo not be!) so in this case we'll forcibly unlock it and try again + + try + { + IndexWriter.Unlock(indexer.GetLuceneDirectory()); + indexer.RebuildIndex(); + } + catch (Exception e) + { + return HandleException(e, indexer); + } + } catch (Exception ex) { - //ensure it's not listening - indexer.IndexOperationComplete -= Indexer_IndexOperationComplete; - LogHelper.Error("An error occurred rebuilding index", ex); - var response = Request.CreateResponse(HttpStatusCode.Conflict); - response.Content = new StringContent(string.Format("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {0}", ex)); - response.ReasonPhrase = "Could Not Rebuild"; - return response; + return HandleException(ex, indexer); } } return msg; } + private HttpResponseMessage HandleException(Exception ex, LuceneIndexer indexer) + { + //ensure it's not listening + indexer.IndexOperationComplete -= Indexer_IndexOperationComplete; + LogHelper.Error("An error occurred rebuilding index", ex); + var response = Request.CreateResponse(HttpStatusCode.Conflict); + response.Content = new StringContent(string.Format("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {0}", ex)); + response.ReasonPhrase = "Could Not Rebuild"; + return response; + } + //static listener so it's not GC'd private static void Indexer_IndexOperationComplete(object sender, EventArgs e) { diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index 88482b4022..66a5495249 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -3,7 +3,7 @@ - + diff --git a/src/UmbracoExamine/BaseUmbracoIndexer.cs b/src/UmbracoExamine/BaseUmbracoIndexer.cs index 1d87b0dfff..bd480b88f1 100644 --- a/src/UmbracoExamine/BaseUmbracoIndexer.cs +++ b/src/UmbracoExamine/BaseUmbracoIndexer.cs @@ -150,7 +150,7 @@ namespace UmbracoExamine { //By default, we will be using the UmbracoDataService //generally this would only need to be set differently for unit testing - DataService = new UmbracoDataService(); + DataService = CreateDefaultUmbracoDataService(); } DataService.LogService.LogLevel = LoggingLevel.Normal; @@ -206,10 +206,15 @@ namespace UmbracoExamine } } - } - + } + #endregion + protected virtual IDataService CreateDefaultUmbracoDataService() + { + return new UmbracoDataService(); + } + /// /// Used to aquire the internal searcher /// diff --git a/src/UmbracoExamine/Config/IndexSetExtensions.cs b/src/UmbracoExamine/Config/IndexSetExtensions.cs index f4bd2e24b2..9c087694b7 100644 --- a/src/UmbracoExamine/Config/IndexSetExtensions.cs +++ b/src/UmbracoExamine/Config/IndexSetExtensions.cs @@ -13,10 +13,12 @@ namespace UmbracoExamine.Config /// public static class IndexSetExtensions { - internal static IIndexCriteria ToIndexCriteria(this IndexSet set, IDataService svc, - StaticFieldCollection indexFieldPolicies) + internal static IIndexCriteria ToIndexCriteria(this IndexSet set, + IDataService svc, + StaticFieldCollection indexFieldPolicies, + IEnumerable additionalUserFields = null) { - return new LazyIndexCriteria(set, svc, indexFieldPolicies); + return new LazyIndexCriteria(set, svc, indexFieldPolicies, additionalUserFields); } /// diff --git a/src/UmbracoExamine/Config/LazyIndexCriteria.cs b/src/UmbracoExamine/Config/LazyIndexCriteria.cs index ee58431930..7f7a9510f1 100644 --- a/src/UmbracoExamine/Config/LazyIndexCriteria.cs +++ b/src/UmbracoExamine/Config/LazyIndexCriteria.cs @@ -12,7 +12,8 @@ namespace UmbracoExamine.Config public LazyIndexCriteria( IndexSet set, IDataService svc, - StaticFieldCollection indexFieldPolicies) + StaticFieldCollection indexFieldPolicies, + IEnumerable additionalUserFields = null) { if (set == null) throw new ArgumentNullException("set"); if (indexFieldPolicies == null) throw new ArgumentNullException("indexFieldPolicies"); @@ -21,7 +22,7 @@ namespace UmbracoExamine.Config _lazyCriteria = new Lazy(() => { var attributeFields = set.IndexAttributeFields.Cast().ToArray(); - var userFields = set.IndexUserFields.Cast().ToArray(); + var userFields = set.IndexUserFields.Cast().ToList(); var includeNodeTypes = set.IncludeNodeTypes.Cast().Select(x => x.Name).ToArray(); var excludeNodeTypes = set.ExcludeNodeTypes.Cast().Select(x => x.Name).ToArray(); var parentId = set.IndexParentId; @@ -44,7 +45,7 @@ namespace UmbracoExamine.Config } fields.Add(field); } - userFields = fields.ToArray(); + userFields = fields.ToList(); } //if there are no attribute fields defined, we'll populate them from the data source (include them all) @@ -68,6 +69,19 @@ namespace UmbracoExamine.Config attributeFields = fields.ToArray(); } + //merge in the additional user fields if any are defined + if (additionalUserFields != null) + { + foreach (var field in additionalUserFields) + { + var f = field; //copy local + if (userFields.Any(x => x.Name == f.Name) == false) + { + userFields.Add(f); + } + } + + } return new IndexCriteria( attributeFields, diff --git a/src/UmbracoExamine/DataServices/UmbracoContentService.cs b/src/UmbracoExamine/DataServices/UmbracoContentService.cs index b52f60a2f2..5dcaabe09b 100644 --- a/src/UmbracoExamine/DataServices/UmbracoContentService.cs +++ b/src/UmbracoExamine/DataServices/UmbracoContentService.cs @@ -13,7 +13,7 @@ namespace UmbracoExamine.DataServices { public class UmbracoContentService : IContentService { - private readonly ApplicationContext _applicationContext; + protected ApplicationContext ApplicationContext { get; private set; } public UmbracoContentService() : this(ApplicationContext.Current) @@ -21,7 +21,7 @@ namespace UmbracoExamine.DataServices public UmbracoContentService(ApplicationContext applicationContext) { - _applicationContext = applicationContext; + ApplicationContext = applicationContext; } /// @@ -60,11 +60,11 @@ namespace UmbracoExamine.DataServices using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope()) { var xmlContent = XDocument.Parse(""); - var rootContent = _applicationContext.Services.ContentService.GetRootContent(); + var rootContent = ApplicationContext.Services.ContentService.GetRootContent(); foreach (var c in rootContent) { // not sure this uses the database, but better be save - xmlContent.Root.Add(c.ToDeepXml(_applicationContext.Services.PackagingService)); + xmlContent.Root.Add(c.ToDeepXml(ApplicationContext.Services.PackagingService)); } var result = ((IEnumerable)xmlContent.XPathEvaluate(xpath)).Cast(); scope.Complete(); @@ -82,7 +82,7 @@ namespace UmbracoExamine.DataServices { using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope()) { - var ret = _applicationContext.Services.PublicAccessService.IsProtected(path.EnsureEndsWith("," + nodeId)); + var ret = ApplicationContext.Services.PublicAccessService.IsProtected(path.EnsureEndsWith("," + nodeId)); scope.Complete(); return ret; } @@ -93,14 +93,26 @@ namespace UmbracoExamine.DataServices /// /// - public IEnumerable GetAllUserPropertyNames() + public virtual IEnumerable GetAllUserPropertyNames() { using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope()) { try - { - var result = _applicationContext.DatabaseContext.Database.Fetch("select distinct alias from cmsPropertyType order by alias"); - scope.Complete(); + { + //only return the property type aliases for media and content + + var result = ApplicationContext.DatabaseContext.Database.Fetch( + @"select distinct cmsPropertyType.alias from cmsPropertyType + inner join cmsContentType on cmsContentType.nodeId = cmsPropertyType.contentTypeId + inner join umbracoNode on umbracoNode.id = cmsContentType.nodeId + where umbracoNode.nodeObjectType = @contentNodeObjectType OR umbracoNode.nodeObjectType = @mediaNodeObjectType + order by alias", new + { + contentNodeObjectType = Constants.ObjectTypes.DocumentType, + mediaNodeObjectType = Constants.ObjectTypes.MediaType + }); + + scope.Complete(); return result; } catch (Exception ex) diff --git a/src/UmbracoExamine/DataServices/UmbracoMemberContentService.cs b/src/UmbracoExamine/DataServices/UmbracoMemberContentService.cs new file mode 100644 index 0000000000..2112e686a6 --- /dev/null +++ b/src/UmbracoExamine/DataServices/UmbracoMemberContentService.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core; +using Umbraco.Core.Logging; + +namespace UmbracoExamine.DataServices +{ + public class UmbracoMemberContentService : UmbracoContentService + { + public override IEnumerable GetAllUserPropertyNames() + { + using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope()) + { + try + { + //only return the property type aliases for members + + var result = ApplicationContext.DatabaseContext.Database.Fetch( + @"select distinct cmsPropertyType.alias from cmsPropertyType + inner join cmsContentType on cmsContentType.nodeId = cmsPropertyType.contentTypeId + inner join umbracoNode on umbracoNode.id = cmsContentType.nodeId + where umbracoNode.nodeObjectType = @nodeObjectType + order by alias", new {nodeObjectType = Constants.ObjectTypes.MemberType}); + + scope.Complete(); + return result; + } + catch (Exception ex) + { + LogHelper.Error("EXCEPTION OCCURRED reading GetAllUserPropertyNames", ex); + return Enumerable.Empty(); + } + } + } + } +} \ No newline at end of file diff --git a/src/UmbracoExamine/DataServices/UmbracoMemberDataService.cs b/src/UmbracoExamine/DataServices/UmbracoMemberDataService.cs new file mode 100644 index 0000000000..44aa2815fa --- /dev/null +++ b/src/UmbracoExamine/DataServices/UmbracoMemberDataService.cs @@ -0,0 +1,10 @@ +namespace UmbracoExamine.DataServices +{ + public class UmbracoMemberDataService : UmbracoDataService + { + public UmbracoMemberDataService() + { + ContentService = new UmbracoMemberContentService(); + } + } +} \ No newline at end of file diff --git a/src/UmbracoExamine/NoPrefixSimpleFsLockFactory.cs b/src/UmbracoExamine/NoPrefixSimpleFsLockFactory.cs new file mode 100644 index 0000000000..ac4210bcc0 --- /dev/null +++ b/src/UmbracoExamine/NoPrefixSimpleFsLockFactory.cs @@ -0,0 +1,26 @@ +using System.IO; +using Examine; +using Examine.LuceneEngine; +using Lucene.Net.Store; + +namespace UmbracoExamine +{ + /// + /// A custom that ensures a prefixless lock prefix + /// + /// + /// This is a work around for the Lucene APIs. By default Lucene will use a null prefix however when we set a custom + /// lock factory the null prefix is overwritten. + /// + public class NoPrefixSimpleFsLockFactory : SimpleFSLockFactory + { + public NoPrefixSimpleFsLockFactory(DirectoryInfo lockDir) : base(lockDir) + { + } + + public override void SetLockPrefix(string lockPrefix) + { + base.SetLockPrefix(null); + } + } +} \ No newline at end of file diff --git a/src/UmbracoExamine/UmbracoContentIndexer.cs b/src/UmbracoExamine/UmbracoContentIndexer.cs index 2a2e2ce98c..649c18df47 100644 --- a/src/UmbracoExamine/UmbracoContentIndexer.cs +++ b/src/UmbracoExamine/UmbracoContentIndexer.cs @@ -410,7 +410,11 @@ namespace UmbracoExamine { if (SupportedTypes.Contains(type) == false) return; - + + //if the app is shutting down do not continue + if (IsCancellationRequested) + return; + var pageIndex = 0; DataService.LogService.AddInfoLog(-1, string.Format("PerformIndexAll - Start data queries - {0}", type)); @@ -530,7 +534,7 @@ namespace UmbracoExamine content, notPublished).WhereNotNull(), type); pageIndex++; - } while (currentPageSize == PageSize); + } while (currentPageSize == PageSize && IsCancellationRequested == false); //do not continue if app is shutting down } break; @@ -628,7 +632,7 @@ namespace UmbracoExamine AddNodesToIndex(xElements, type); pageIndex++; - } while (more); + } while (more && IsCancellationRequested == false); //don't continue if the app is shutting down } internal static IEnumerable GetSerializedContent( diff --git a/src/UmbracoExamine/UmbracoExamine.csproj b/src/UmbracoExamine/UmbracoExamine.csproj index f3dd301a8c..2c46c156ef 100644 --- a/src/UmbracoExamine/UmbracoExamine.csproj +++ b/src/UmbracoExamine/UmbracoExamine.csproj @@ -82,15 +82,14 @@ ..\Solution Items\TheFARM-Public.snk - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - True @@ -118,6 +117,8 @@ + + @@ -133,6 +134,7 @@ + diff --git a/src/UmbracoExamine/UmbracoMemberIndexer.cs b/src/UmbracoExamine/UmbracoMemberIndexer.cs index 1a3c9befd2..f3ee7a4a89 100644 --- a/src/UmbracoExamine/UmbracoMemberIndexer.cs +++ b/src/UmbracoExamine/UmbracoMemberIndexer.cs @@ -19,6 +19,8 @@ using Lucene.Net.Analysis; namespace UmbracoExamine { + + /// /// Custom indexer for members /// @@ -101,6 +103,11 @@ namespace UmbracoExamine _memberTypeService = memberTypeService; } + protected override IDataService CreateDefaultUmbracoDataService() + { + return new UmbracoMemberDataService(); + } + /// /// Ensures that the'_searchEmail' is added to the user fields so that it is indexed - without having to modify the config /// @@ -108,34 +115,26 @@ namespace UmbracoExamine /// protected override IIndexCriteria GetIndexerData(IndexSet indexSet) { - var indexerData = base.GetIndexerData(indexSet); - if (CanInitialize()) { - //If the fields are missing a custom _searchEmail, then add it - - if (indexerData.UserFields.Any(x => x.Name == "_searchEmail") == false) + //Add a custom _searchEmail to the index criteria no matter what is in config + var field = new IndexField { Name = "_searchEmail" }; + StaticField policy; + if (IndexFieldPolicies.TryGetValue("_searchEmail", out policy)) { - var field = new IndexField { Name = "_searchEmail" }; - - StaticField policy; - if (IndexFieldPolicies.TryGetValue("_searchEmail", out policy)) - { - field.Type = policy.Type; - field.EnableSorting = policy.EnableSorting; - } - - return new IndexCriteria( - indexerData.StandardFields, - indexerData.UserFields.Concat(new[] { field }), - indexerData.IncludeNodeTypes, - indexerData.ExcludeNodeTypes, - indexerData.ParentNodeId - ); + field.Type = policy.Type; + field.EnableSorting = policy.EnableSorting; } - } - return indexerData; + return indexSet.ToIndexCriteria(DataService, IndexFieldPolicies, + //add additional explicit fields + new []{field}); + } + else + { + return base.GetIndexerData(indexSet); + } + } /// @@ -198,7 +197,7 @@ namespace UmbracoExamine AddNodesToIndex(GetSerializedMembers(members), type); pageIndex++; - } while (members.Length == pageSize); + } while (members.Length == pageSize && IsCancellationRequested == false); //don't continue if the app is shutting down } } else @@ -212,7 +211,7 @@ namespace UmbracoExamine AddNodesToIndex(GetSerializedMembers(members), type); pageIndex++; - } while (members.Length == pageSize); + } while (members.Length == pageSize && IsCancellationRequested == false); //don't continue if the app is shutting down } } } @@ -233,8 +232,8 @@ namespace UmbracoExamine protected override XDocument GetXDocument(string xPath, string type) { throw new NotSupportedException(); - } - + } + /// /// Add the special __key and _searchEmail fields /// diff --git a/src/UmbracoExamine/packages.config b/src/UmbracoExamine/packages.config index 40bdd28e84..74b8cbb907 100644 --- a/src/UmbracoExamine/packages.config +++ b/src/UmbracoExamine/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/umbraco.MacroEngines/packages.config b/src/umbraco.MacroEngines/packages.config index 6aadcba8d4..14c21a4bd4 100644 --- a/src/umbraco.MacroEngines/packages.config +++ b/src/umbraco.MacroEngines/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj index 46c2b1ed2c..bde18c31dd 100644 --- a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj +++ b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj @@ -45,8 +45,8 @@ false - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll @@ -57,7 +57,6 @@ ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - True ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll diff --git a/src/umbraco.businesslogic/umbraco.businesslogic.csproj b/src/umbraco.businesslogic/umbraco.businesslogic.csproj index bbc98ca0c7..cb1e47eaf8 100644 --- a/src/umbraco.businesslogic/umbraco.businesslogic.csproj +++ b/src/umbraco.businesslogic/umbraco.businesslogic.csproj @@ -108,11 +108,9 @@ ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll - True ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll - True ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll @@ -122,11 +120,9 @@ ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True ..\packages\Owin.1.0\lib\net40\Owin.dll - True @@ -145,27 +141,21 @@ ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True System.XML diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj index 792279ad10..2b81d1fe92 100644 --- a/src/umbraco.cms/umbraco.cms.csproj +++ b/src/umbraco.cms/umbraco.cms.csproj @@ -108,11 +108,9 @@ ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll - True ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll - True @@ -166,7 +164,6 @@ ..\packages\Tidy.Net.1.0.0\lib\TidyNet.dll - True diff --git a/src/umbraco.controls/umbraco.controls.csproj b/src/umbraco.controls/umbraco.controls.csproj index e458a56213..c562fa35d1 100644 --- a/src/umbraco.controls/umbraco.controls.csproj +++ b/src/umbraco.controls/umbraco.controls.csproj @@ -70,7 +70,6 @@ ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll - True diff --git a/src/umbraco.datalayer/umbraco.datalayer.csproj b/src/umbraco.datalayer/umbraco.datalayer.csproj index e0fd450022..de34a0cfbb 100644 --- a/src/umbraco.datalayer/umbraco.datalayer.csproj +++ b/src/umbraco.datalayer/umbraco.datalayer.csproj @@ -70,10 +70,10 @@ ..\packages\Microsoft.ApplicationBlocks.Data.1.0.1559.20655\lib\Microsoft.ApplicationBlocks.Data.dll - True ..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll + True diff --git a/src/umbraco.editorControls/umbraco.editorControls.csproj b/src/umbraco.editorControls/umbraco.editorControls.csproj index 5950ac9719..602187e55a 100644 --- a/src/umbraco.editorControls/umbraco.editorControls.csproj +++ b/src/umbraco.editorControls/umbraco.editorControls.csproj @@ -116,7 +116,6 @@ ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll - True System