Merge remote-tracking branch 'origin/7.4.0' into dev-v8
Conflicts: build/UmbracoVersion.txt src/Umbraco.Core/ApplicationContext.cs src/Umbraco.Core/Configuration/UmbracoConfig.cs src/Umbraco.Core/Configuration/UmbracoVersion.cs src/Umbraco.Core/CoreBootManager.cs src/Umbraco.Core/DatabaseContext.cs src/Umbraco.Core/Dictionary/CultureDictionaryFactoryResolver.cs src/Umbraco.Core/Manifest/ManifestParser.cs src/Umbraco.Core/Models/DataTypeDefinition.cs src/Umbraco.Core/ObjectResolution/ApplicationEventsResolver.cs src/Umbraco.Core/Persistence/DatabaseSchemaHelper.cs src/Umbraco.Core/Persistence/Factories/MemberTypeFactory.cs src/Umbraco.Core/Persistence/Migrations/MigrationBase.cs src/Umbraco.Core/Persistence/Migrations/MigrationExpressionBase.cs src/Umbraco.Core/Persistence/Migrations/MigrationResolver.cs src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/AlterSyntaxBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Column/AlterColumnBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Table/AlterTableBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Column/CreateColumnBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Create/CreateBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Table/CreateTableBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/DeleteBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/ExecuteBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteCodeStatementExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Execute/Expressions/ExecuteSqlStatementExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/Expressions/InsertDataExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Insert/InsertBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/RenameBuilder.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Update/UpdateBuilder.cs src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/AddIndexToCmsMacroTable.cs src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/MigrateAndRemoveTemplateMasterColumn.cs src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs src/Umbraco.Core/Persistence/Repositories/DictionaryRepository.cs src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs src/Umbraco.Core/Persistence/Repositories/RecycleBinRepository.cs src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs src/Umbraco.Core/Persistence/Repositories/TagRepository.cs src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs src/Umbraco.Core/Persistence/RepositoryFactory.cs src/Umbraco.Core/Persistence/UmbracoDatabase.cs src/Umbraco.Core/PropertyEditors/IPropertyEditorValueConverter.cs src/Umbraco.Core/PropertyEditors/PropertyEditor.cs src/Umbraco.Core/PropertyEditors/PropertyEditorResolver.cs src/Umbraco.Core/Services/ContentService.cs src/Umbraco.Core/Services/ContentTypeService.cs src/Umbraco.Core/Services/DataTypeService.cs src/Umbraco.Core/Services/EntityService.cs src/Umbraco.Core/Services/LocalizationService.cs src/Umbraco.Core/Services/MacroService.cs src/Umbraco.Core/Services/MediaService.cs src/Umbraco.Core/Services/MemberGroupService.cs src/Umbraco.Core/Services/MemberService.cs src/Umbraco.Core/Services/MemberTypeService.cs src/Umbraco.Core/Services/PackagingService.cs src/Umbraco.Core/Services/ServerRegistrationService.cs src/Umbraco.Core/Services/ServiceContext.cs src/Umbraco.Core/Services/TagService.cs src/Umbraco.Core/Services/UserService.cs src/Umbraco.Core/Strings/DefaultShortStringHelper.cs src/Umbraco.Core/Sync/ConfigServerRegistrar.cs src/Umbraco.Core/Sync/DatabaseServerMessenger.cs src/Umbraco.Core/Umbraco.Core.csproj src/Umbraco.Core/UmbracoApplicationBase.cs src/Umbraco.Core/packages.config src/Umbraco.Tests/BootManagers/CoreBootManagerTests.cs src/Umbraco.Tests/Macros/MacroTests.cs src/Umbraco.Tests/Manifest/ManifestParserTests.cs src/Umbraco.Tests/Migrations/FindingMigrationsTest.cs src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs src/Umbraco.Tests/Migrations/Stubs/FiveZeroMigration.cs src/Umbraco.Tests/Migrations/Stubs/FourElevenMigration.cs src/Umbraco.Tests/Migrations/Stubs/SixZeroMigration1.cs src/Umbraco.Tests/Migrations/Stubs/SixZeroMigration2.cs src/Umbraco.Tests/Migrations/TargetVersionSixthMigrationsTest.cs src/Umbraco.Tests/Migrations/Upgrades/BaseUpgradeTest.cs src/Umbraco.Tests/Migrations/Upgrades/SqlCeDataUpgradeTest.cs src/Umbraco.Tests/Mvc/UmbracoViewPageTests.cs src/Umbraco.Tests/Persistence/BaseTableByTableTest.cs src/Umbraco.Tests/Persistence/DatabaseContextTests.cs src/Umbraco.Tests/Persistence/Mappers/PropertyGroupMapperTest.cs src/Umbraco.Tests/Persistence/MySqlDatabaseCreationTest.cs src/Umbraco.Tests/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs src/Umbraco.Tests/Persistence/Querying/ContentTypeSqlMappingTests.cs src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/ServerRegistrationRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs src/Umbraco.Tests/Services/ContentServiceTests.cs src/Umbraco.Tests/Services/ThreadSafetyServiceTest.cs src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs src/Umbraco.Tests/TestHelpers/BaseDatabaseTest.cs src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs src/Umbraco.Tests/Umbraco.Tests.csproj src/Umbraco.Web.UI/Umbraco.Web.UI.csproj src/Umbraco.Web.UI/config/ClientDependency.config src/Umbraco.Web.UI/packages.config src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs src/Umbraco.Web.UI/umbraco/plugins/tinymce3/insertImage.aspx src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.cs src/Umbraco.Web/BatchedDatabaseServerMessenger.cs src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs src/Umbraco.Web/Cache/DistributedCacheExtensions.cs src/Umbraco.Web/Editors/AuthenticationController.cs src/Umbraco.Web/Editors/BackOfficeController.cs src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs src/Umbraco.Web/Media/ThumbnailProviders/ThumbnailProvidersResolver.cs src/Umbraco.Web/Mvc/DefaultRenderMvcControllerResolver.cs src/Umbraco.Web/PropertyEditors/FileUploadPropertyEditor.cs src/Umbraco.Web/PropertyEditors/FolderBrowserPropertyEditor.cs src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs src/Umbraco.Web/Trees/MediaTreeController.cs src/Umbraco.Web/Trees/MemberTreeController.cs src/Umbraco.Web/Umbraco.Web.csproj src/Umbraco.Web/UmbracoApplication.cs src/Umbraco.Web/UmbracoModule.cs src/Umbraco.Web/WebBootManager.cs src/Umbraco.Web/packages.config src/Umbraco.Web/umbraco.presentation/content.cs src/Umbraco.Web/umbraco.presentation/keepAliveService.cs src/Umbraco.Web/umbraco.presentation/macro.cs src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadDictionary.cs src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentControl.cs src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs src/Umbraco.Web/umbraco.presentation/umbraco/controls/Images/ImageViewer.ascx.cs src/Umbraco.Web/umbraco.presentation/umbraco/controls/Images/UploadMediaImage.ascx.cs src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/imageViewer.aspx.cs src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/rollBack.aspx.cs src/Umbraco.Web/umbraco.presentation/umbraco/members/EditMemberType.aspx.cs src/Umbraco.Web/umbraco.presentation/umbraco/plugins/tinymce3/insertImage.aspx src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/MediaExtensions.cs src/Umbraco.Web/umbraco.presentation/umbraco/uQuery/uQuery.cs src/Umbraco.Web/umbraco.presentation/umbraco/users/EditUser.aspx.cs src/Umbraco.Web/umbraco.presentation/umbraco/webService.asmx.cs src/Umbraco.Web/umbraco.presentation/umbraco/webservices/MediaUploader.ashx.cs src/UmbracoExamine/UmbracoContentIndexer.cs src/UmbracoExamine/UmbracoMemberIndexer.cs src/umbraco.MacroEngines/RazorCore/UmbracoCultureDictionary.cs src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs src/umbraco.MacroEngines/RazorDynamicNode/ExtensionMethods.cs src/umbraco.MacroEngines/app.config src/umbraco.MacroEngines/packages.config src/umbraco.MacroEngines/umbraco.MacroEngines.csproj src/umbraco.businesslogic/UmbracoSettings.cs src/umbraco.cms/businesslogic/Content.cs src/umbraco.cms/businesslogic/datatype/DataTypeDefinition.cs src/umbraco.cms/businesslogic/datatype/DefaultPreValueEditor.cs src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs src/umbraco.cms/businesslogic/translation/Translation.cs src/umbraco.cms/businesslogic/web/Document.cs src/umbraco.cms/packages.config src/umbraco.editorControls/DefaultPrevalueEditor.cs src/umbraco.editorControls/MultiNodeTreePicker/MNTPResources.Designer.cs src/umbraco.editorControls/MultiNodeTreePicker/MNTPResources.resx src/umbraco.editorControls/MultiNodeTreePicker/MNTP_DataType.cs src/umbraco.editorControls/app.config src/umbraco.editorControls/macrocontainer/PrevalueEditor.cs src/umbraco.editorControls/packages.config src/umbraco.editorControls/textfieldmultiple/textfieldMultipleDataType.cs src/umbraco.editorControls/umbraco.editorControls.csproj src/umbraco.editorControls/uploadfield/uploadField.cs src/umbraco.editorControls/userControlWrapper/usercontrolPrevalueEditor.cs src/umbraco.providers/app.config
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.XPath;
|
||||
@@ -18,6 +19,9 @@ using Umbraco.Core.Xml;
|
||||
using Umbraco.Web.Models;
|
||||
using UmbracoExamine;
|
||||
using umbraco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Web.Cache;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
{
|
||||
@@ -52,6 +56,11 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
_indexProvider = indexProvider;
|
||||
}
|
||||
|
||||
static PublishedMediaCache()
|
||||
{
|
||||
InitializeCacheConfig();
|
||||
}
|
||||
|
||||
private readonly ApplicationContext _applicationContext;
|
||||
private readonly BaseSearchProvider _searchProvider;
|
||||
private readonly BaseIndexProvider _indexProvider;
|
||||
@@ -167,9 +176,20 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
return null;
|
||||
}
|
||||
|
||||
private IPublishedContent GetUmbracoMedia(int id)
|
||||
{
|
||||
var searchProvider = GetSearchProviderSafe();
|
||||
private IPublishedContent GetUmbracoMedia(int id)
|
||||
{
|
||||
// this recreates an IPublishedContent and model each time
|
||||
// it is called, but at least it should NOT hit the database
|
||||
// nor Lucene each time, relying on the memory cache instead
|
||||
|
||||
var cacheValues = GetCacheValues(id, GetUmbracoMediaCacheValues);
|
||||
|
||||
return cacheValues == null ? null : CreateFromCacheValues(cacheValues);
|
||||
}
|
||||
|
||||
private CacheValues GetUmbracoMediaCacheValues(int id)
|
||||
{
|
||||
var searchProvider = GetSearchProviderSafe();
|
||||
|
||||
if (searchProvider != null)
|
||||
{
|
||||
@@ -198,16 +218,16 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
LogHelper.Debug<PublishedMediaCache>(
|
||||
LogHelper.Warn<PublishedMediaCache>(
|
||||
"Could not retrieve media {0} from Examine index, reverting to looking up media via legacy library.GetMedia method",
|
||||
() => id);
|
||||
|
||||
var media = global::umbraco.library.GetMedia(id, true);
|
||||
var media = global::umbraco.library.GetMedia(id, false);
|
||||
|
||||
return ConvertFromXPathNodeIterator(media, id);
|
||||
}
|
||||
|
||||
internal IPublishedContent ConvertFromXPathNodeIterator(XPathNodeIterator media, int id)
|
||||
internal CacheValues ConvertFromXPathNodeIterator(XPathNodeIterator media, int id)
|
||||
{
|
||||
if (media != null && media.Current != null)
|
||||
{
|
||||
@@ -216,14 +236,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
: ConvertFromXPathNavigator(media.Current);
|
||||
}
|
||||
|
||||
LogHelper.Debug<PublishedMediaCache>(
|
||||
LogHelper.Warn<PublishedMediaCache>(
|
||||
"Could not retrieve media {0} from Examine index or from legacy library.GetMedia method",
|
||||
() => id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal IPublishedContent ConvertFromSearchResult(SearchResult searchResult)
|
||||
internal CacheValues ConvertFromSearchResult(SearchResult searchResult)
|
||||
{
|
||||
//NOTE: Some fields will not be included if the config section for the internal index has been
|
||||
//mucked around with. It should index everything and so the index definition should simply be:
|
||||
@@ -253,19 +273,28 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
values.Add("level", values["__Path"].Split(',').Length.ToString());
|
||||
}
|
||||
|
||||
// because, migration
|
||||
if (values.ContainsKey("key") == false)
|
||||
values["key"] = Guid.Empty.ToString();
|
||||
|
||||
var content = new DictionaryPublishedContent(values,
|
||||
d => d.ParentId != -1 //parent should be null if -1
|
||||
? GetUmbracoMedia(d.ParentId)
|
||||
: null,
|
||||
//callback to return the children of the current node
|
||||
d => GetChildrenMedia(d.Id),
|
||||
GetProperty,
|
||||
true);
|
||||
return content.CreateModel();
|
||||
return new CacheValues
|
||||
{
|
||||
Values = values,
|
||||
FromExamine = true
|
||||
};
|
||||
|
||||
//var content = new DictionaryPublishedContent(values,
|
||||
// d => d.ParentId != -1 //parent should be null if -1
|
||||
// ? GetUmbracoMedia(d.ParentId)
|
||||
// : null,
|
||||
// //callback to return the children of the current node
|
||||
// d => GetChildrenMedia(d.Id),
|
||||
// GetProperty,
|
||||
// true);
|
||||
//return content.CreateModel();
|
||||
}
|
||||
|
||||
internal IPublishedContent ConvertFromXPathNavigator(XPathNavigator xpath)
|
||||
internal CacheValues ConvertFromXPathNavigator(XPathNavigator xpath, bool forceNav = false)
|
||||
{
|
||||
if (xpath == null) throw new ArgumentNullException("xpath");
|
||||
|
||||
@@ -293,6 +322,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
result.Current.MoveToParent();
|
||||
}
|
||||
}
|
||||
// because, migration
|
||||
if (values.ContainsKey("key") == false)
|
||||
values["key"] = Guid.Empty.ToString();
|
||||
//add the user props
|
||||
while (result.MoveNext())
|
||||
{
|
||||
@@ -310,15 +342,21 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
var content = new DictionaryPublishedContent(values,
|
||||
d => d.ParentId != -1 //parent should be null if -1
|
||||
? GetUmbracoMedia(d.ParentId)
|
||||
: null,
|
||||
//callback to return the children of the current node based on the xml structure already found
|
||||
d => GetChildrenMedia(d.Id, xpath),
|
||||
GetProperty,
|
||||
false);
|
||||
return content.CreateModel();
|
||||
return new CacheValues
|
||||
{
|
||||
Values = values,
|
||||
XPath = forceNav ? xpath : null // outside of tests we do NOT want to cache the navigator!
|
||||
};
|
||||
|
||||
//var content = new DictionaryPublishedContent(values,
|
||||
// d => d.ParentId != -1 //parent should be null if -1
|
||||
// ? GetUmbracoMedia(d.ParentId)
|
||||
// : null,
|
||||
// //callback to return the children of the current node based on the xml structure already found
|
||||
// d => GetChildrenMedia(d.Id, xpath),
|
||||
// GetProperty,
|
||||
// false);
|
||||
//return content.CreateModel();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -395,9 +433,17 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
if (results.Any())
|
||||
{
|
||||
return useLuceneSort
|
||||
? results.Select(ConvertFromSearchResult) //will already be sorted by lucene
|
||||
: results.Select(ConvertFromSearchResult).OrderBy(x => x.SortOrder);
|
||||
// var medias = results.Select(ConvertFromSearchResult);
|
||||
var medias = results.Select(x =>
|
||||
{
|
||||
int nid;
|
||||
if (int.TryParse(x["__NodeId"], out nid) == false && int.TryParse(x["NodeId"], out nid) == false)
|
||||
throw new Exception("Failed to extract NodeId from search result.");
|
||||
var cacheValues = GetCacheValues(nid, id => ConvertFromSearchResult(x));
|
||||
return CreateFromCacheValues(cacheValues);
|
||||
});
|
||||
|
||||
return useLuceneSort ? medias : medias.OrderBy(x => x.SortOrder);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -429,29 +475,51 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
//The xpath might be the whole xpath including the current ones ancestors so we need to select the current node
|
||||
var item = xpath.Select("//*[@id='" + parentId + "']");
|
||||
if (item.Current == null)
|
||||
{
|
||||
return Enumerable.Empty<IPublishedContent>();
|
||||
}
|
||||
var children = item.Current.SelectChildren(XPathNodeType.Element);
|
||||
var mediaList = new List<IPublishedContent>();
|
||||
|
||||
// this is so bad, really
|
||||
var item = xpath.Select("//*[@id='" + parentId + "']");
|
||||
if (item.Current == null)
|
||||
return Enumerable.Empty<IPublishedContent>();
|
||||
var items = item.Current.SelectChildren(XPathNodeType.Element);
|
||||
|
||||
// and this does not work, because... meh
|
||||
//var q = "//* [@id='" + parentId + "']/* [@id]";
|
||||
//var items = xpath.Select(q);
|
||||
|
||||
foreach (XPathNavigator itemm in items)
|
||||
{
|
||||
int id;
|
||||
if (int.TryParse(itemm.GetAttribute("id", ""), out id) == false)
|
||||
continue; // wtf?
|
||||
var captured = itemm;
|
||||
var cacheValues = GetCacheValues(id, idd => ConvertFromXPathNavigator(captured));
|
||||
mediaList.Add(CreateFromCacheValues(cacheValues));
|
||||
}
|
||||
|
||||
////The xpath might be the whole xpath including the current ones ancestors so we need to select the current node
|
||||
//var item = xpath.Select("//*[@id='" + parentId + "']");
|
||||
//if (item.Current == null)
|
||||
//{
|
||||
// return Enumerable.Empty<IPublishedContent>();
|
||||
//}
|
||||
//var children = item.Current.SelectChildren(XPathNodeType.Element);
|
||||
|
||||
//foreach(XPathNavigator x in children)
|
||||
//{
|
||||
// //NOTE: I'm not sure why this is here, it is from legacy code of ExamineBackedMedia, but
|
||||
// // will leave it here as it must have done something!
|
||||
// if (x.Name != "contents")
|
||||
// {
|
||||
// //make sure it's actually a node, not a property
|
||||
// if (!string.IsNullOrEmpty(x.GetAttribute("path", "")) &&
|
||||
// !string.IsNullOrEmpty(x.GetAttribute("id", "")))
|
||||
// {
|
||||
// mediaList.Add(ConvertFromXPathNavigator(x));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
var mediaList = new List<IPublishedContent>();
|
||||
foreach(XPathNavigator x in children)
|
||||
{
|
||||
//NOTE: I'm not sure why this is here, it is from legacy code of ExamineBackedMedia, but
|
||||
// will leave it here as it must have done something!
|
||||
if (x.Name != "contents")
|
||||
{
|
||||
//make sure it's actually a node, not a property
|
||||
if (!string.IsNullOrEmpty(x.GetAttribute("path", "")) &&
|
||||
!string.IsNullOrEmpty(x.GetAttribute("id", "")))
|
||||
{
|
||||
mediaList.Add(ConvertFromXPathNavigator(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
return mediaList;
|
||||
}
|
||||
|
||||
@@ -462,7 +530,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// This is a helper class and definitely not intended for public use, it expects that all of the values required
|
||||
/// to create an IPublishedContent exist in the dictionary by specific aliases.
|
||||
/// </remarks>
|
||||
internal class DictionaryPublishedContent : PublishedContentBase
|
||||
internal class DictionaryPublishedContent : PublishedContentWithKeyBase
|
||||
{
|
||||
// note: I'm not sure this class fully complies with IPublishedContent rules especially
|
||||
// I'm not sure that _properties contains all properties including those without a value,
|
||||
@@ -470,27 +538,30 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
// List of properties that will appear in the XML and do not match
|
||||
// anything in the ContentType, so they must be ignored.
|
||||
private static readonly string[] IgnoredKeys = { "version", "isDoc", "key" };
|
||||
private static readonly string[] IgnoredKeys = { "version", "isDoc" };
|
||||
|
||||
public DictionaryPublishedContent(
|
||||
IDictionary<string, string> valueDictionary,
|
||||
Func<DictionaryPublishedContent, IPublishedContent> getParent,
|
||||
Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> getChildren,
|
||||
Func<int, IPublishedContent> getParent,
|
||||
Func<int, XPathNavigator, IEnumerable<IPublishedContent>> getChildren,
|
||||
Func<DictionaryPublishedContent, string, IPublishedProperty> getProperty,
|
||||
XPathNavigator nav,
|
||||
bool fromExamine)
|
||||
{
|
||||
if (valueDictionary == null) throw new ArgumentNullException("valueDictionary");
|
||||
if (getParent == null) throw new ArgumentNullException("getParent");
|
||||
if (getProperty == null) throw new ArgumentNullException("getProperty");
|
||||
|
||||
_getParent = getParent;
|
||||
_getChildren = getChildren;
|
||||
_getParent = new Lazy<IPublishedContent>(() => getParent(ParentId));
|
||||
_getChildren = new Lazy<IEnumerable<IPublishedContent>>(() => getChildren(Id, nav));
|
||||
_getProperty = getProperty;
|
||||
|
||||
LoadedFromExamine = fromExamine;
|
||||
|
||||
ValidateAndSetProperty(valueDictionary, val => _id = int.Parse(val), "id", "nodeId", "__NodeId"); //should validate the int!
|
||||
ValidateAndSetProperty(valueDictionary, val => _templateId = int.Parse(val), "template", "templateId");
|
||||
ValidateAndSetProperty(valueDictionary, val => _key = Guid.Parse(val), "key");
|
||||
// wtf are we dealing with templates for medias?!
|
||||
ValidateAndSetProperty(valueDictionary, val => _templateId = int.Parse(val), "template", "templateId");
|
||||
ValidateAndSetProperty(valueDictionary, val => _sortOrder = int.Parse(val), "sortOrder");
|
||||
ValidateAndSetProperty(valueDictionary, val => _name = val, "nodeName", "__nodeName");
|
||||
ValidateAndSetProperty(valueDictionary, val => _urlName = val, "urlName");
|
||||
@@ -573,8 +644,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// </summary>
|
||||
internal bool LoadedFromExamine { get; private set; }
|
||||
|
||||
private readonly Func<DictionaryPublishedContent, IPublishedContent> _getParent;
|
||||
private readonly Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> _getChildren;
|
||||
//private readonly Func<DictionaryPublishedContent, IPublishedContent> _getParent;
|
||||
private readonly Lazy<IPublishedContent> _getParent;
|
||||
//private readonly Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> _getChildren;
|
||||
private readonly Lazy<IEnumerable<IPublishedContent>> _getChildren;
|
||||
private readonly Func<DictionaryPublishedContent, string, IPublishedProperty> _getProperty;
|
||||
|
||||
/// <summary>
|
||||
@@ -587,7 +660,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
public override IPublishedContent Parent
|
||||
{
|
||||
get { return _getParent(this); }
|
||||
get { return _getParent.Value; }
|
||||
}
|
||||
|
||||
public int ParentId { get; private set; }
|
||||
@@ -596,6 +669,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
get { return _id; }
|
||||
}
|
||||
|
||||
public override Guid Key { get { return _key; } }
|
||||
|
||||
public override int TemplateId
|
||||
{
|
||||
get
|
||||
@@ -687,7 +762,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
public override IEnumerable<IPublishedContent> Children
|
||||
{
|
||||
get { return _getChildren(this); }
|
||||
get { return _getChildren.Value; }
|
||||
}
|
||||
|
||||
public override IPublishedProperty GetProperty(string alias)
|
||||
@@ -735,6 +810,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
private readonly List<string> _keysAdded = new List<string>();
|
||||
private int _id;
|
||||
private Guid _key;
|
||||
private int _templateId;
|
||||
private int _sortOrder;
|
||||
private string _name;
|
||||
@@ -765,5 +841,93 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
_keysAdded.Add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// REFACTORING
|
||||
|
||||
// caching the basic atomic values - and the parent id
|
||||
// but NOT caching actual parent nor children and NOT even
|
||||
// the list of children ids - BUT caching the path
|
||||
|
||||
internal class CacheValues
|
||||
{
|
||||
public IDictionary<string, string> Values { get; set; }
|
||||
public XPathNavigator XPath { get; set; }
|
||||
public bool FromExamine { get; set; }
|
||||
}
|
||||
|
||||
public const string PublishedMediaCacheKey = "MediaCacheMeh.";
|
||||
private const int PublishedMediaCacheTimespanSeconds = 4 * 60; // 4 mins
|
||||
private static TimeSpan _publishedMediaCacheTimespan;
|
||||
private static bool _publishedMediaCacheEnabled;
|
||||
|
||||
private static void InitializeCacheConfig()
|
||||
{
|
||||
var value = ConfigurationManager.AppSettings["Umbraco.PublishedMediaCache.Seconds"];
|
||||
int seconds;
|
||||
if (int.TryParse(value, out seconds) == false)
|
||||
seconds = PublishedMediaCacheTimespanSeconds;
|
||||
if (seconds > 0)
|
||||
{
|
||||
_publishedMediaCacheEnabled = true;
|
||||
_publishedMediaCacheTimespan = TimeSpan.FromSeconds(seconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
_publishedMediaCacheEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal IPublishedContent CreateFromCacheValues(CacheValues cacheValues)
|
||||
{
|
||||
var content = new DictionaryPublishedContent(
|
||||
cacheValues.Values,
|
||||
parentId => parentId < 0 ? null : GetUmbracoMedia(parentId),
|
||||
GetChildrenMedia,
|
||||
GetProperty,
|
||||
cacheValues.XPath, // though, outside of tests, that should be null
|
||||
cacheValues.FromExamine
|
||||
);
|
||||
return content.CreateModel();
|
||||
}
|
||||
|
||||
private static CacheValues GetCacheValues(int id, Func<int, CacheValues> func)
|
||||
{
|
||||
if (_publishedMediaCacheEnabled == false)
|
||||
return func(id);
|
||||
|
||||
var cache = ApplicationContext.Current.ApplicationCache.RuntimeCache;
|
||||
var key = PublishedMediaCacheKey + id;
|
||||
return (CacheValues) cache.GetCacheItem(key, () => func(id), _publishedMediaCacheTimespan);
|
||||
}
|
||||
|
||||
internal static void ClearCache(int id)
|
||||
{
|
||||
var cache = ApplicationContext.Current.ApplicationCache.RuntimeCache;
|
||||
var sid = id.ToString();
|
||||
var key = PublishedMediaCacheKey + sid;
|
||||
|
||||
// we do clear a lot of things... but the cache refresher is somewhat
|
||||
// convoluted and it's hard to tell what to clear exactly ;-(
|
||||
|
||||
// clear the parent - NOT (why?)
|
||||
//var exist = (CacheValues) cache.GetCacheItem(key);
|
||||
//if (exist != null)
|
||||
// cache.ClearCacheItem(PublishedMediaCacheKey + GetValuesValue(exist.Values, "parentID"));
|
||||
|
||||
// clear the item
|
||||
cache.ClearCacheItem(key);
|
||||
|
||||
// clear all children - in case we moved and their path has changed
|
||||
var fid = "/" + sid + "/";
|
||||
cache.ClearCacheObjectTypes<CacheValues>((k, v) =>
|
||||
GetValuesValue(v.Values, "path", "__Path").Contains(fid));
|
||||
}
|
||||
|
||||
private static string GetValuesValue(IDictionary<string, string> d, params string[] keys)
|
||||
{
|
||||
string value = null;
|
||||
var ignored = keys.Any(x => d.TryGetValue(x, out value));
|
||||
return value ?? "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,11 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// if multiple threads are performing publishing tasks that the file will be persisted in accordance with the final resulting
|
||||
/// xml structure since the file writes are queued.
|
||||
/// </remarks>
|
||||
internal class XmlCacheFilePersister : ILatchedBackgroundTask
|
||||
internal class XmlCacheFilePersister : LatchedBackgroundTaskBase
|
||||
{
|
||||
private readonly IBackgroundTaskRunner<XmlCacheFilePersister> _runner;
|
||||
private readonly content _content;
|
||||
private readonly ProfilingLogger _logger;
|
||||
private readonly ManualResetEventSlim _latch = new ManualResetEventSlim(false);
|
||||
private readonly object _locko = new object();
|
||||
private bool _released;
|
||||
private Timer _timer;
|
||||
@@ -39,7 +38,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
private const int MaxWaitMilliseconds = 30000; // save the cache after some time (ie no more than 30s of changes)
|
||||
|
||||
// save the cache when the app goes down
|
||||
public bool RunsOnShutdown { get { return true; } }
|
||||
public override bool RunsOnShutdown { get { return _timer != null; } }
|
||||
|
||||
// initialize the first instance, which is inactive (not touched yet)
|
||||
public XmlCacheFilePersister(IBackgroundTaskRunner<XmlCacheFilePersister> runner, content content, ProfilingLogger logger)
|
||||
@@ -132,7 +131,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
|
||||
if (runNow)
|
||||
Run();
|
||||
//Run();
|
||||
LogHelper.Warn<XmlCacheFilePersister>("Cannot write now because we are going down, changes may be lost.");
|
||||
|
||||
return ret; // this, by default, unless we created a new one
|
||||
}
|
||||
@@ -142,28 +142,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
lock (_locko)
|
||||
{
|
||||
_logger.Logger.Debug<XmlCacheFilePersister>("Timer: release.");
|
||||
if (_timer != null)
|
||||
_timer.Dispose();
|
||||
_timer = null;
|
||||
_released = true;
|
||||
|
||||
// if running (because of shutdown) this will have no effect
|
||||
// else it tells the runner it is time to run the task
|
||||
_latch.Set();
|
||||
Release();
|
||||
}
|
||||
}
|
||||
|
||||
public WaitHandle Latch
|
||||
{
|
||||
get { return _latch.WaitHandle; }
|
||||
}
|
||||
|
||||
public bool IsLatched
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public async Task RunAsync(CancellationToken token)
|
||||
public override async Task RunAsync(CancellationToken token)
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
@@ -188,15 +173,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAsync
|
||||
public override bool IsAsync
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{ }
|
||||
|
||||
public void Run()
|
||||
public override void Run()
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
@@ -210,5 +192,15 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
_content.SaveXmlToFile();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
base.DisposeResources();
|
||||
|
||||
// stop the timer
|
||||
if (_timer == null) return;
|
||||
_timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
_timer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[XmlType(Namespace = "http://umbraco.org/webservices/")]
|
||||
internal class XmlPublishedContent : PublishedContentBase
|
||||
internal class XmlPublishedContent : PublishedContentWithKeyBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <c>XmlPublishedContent</c> class with an Xml node.
|
||||
@@ -64,6 +64,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
private IPublishedContent _parent;
|
||||
|
||||
private int _id;
|
||||
private Guid _key;
|
||||
private int _template;
|
||||
private string _name;
|
||||
private string _docTypeAlias;
|
||||
@@ -150,6 +151,16 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
public override Guid Key
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _key;
|
||||
}
|
||||
}
|
||||
|
||||
public override int TemplateId
|
||||
{
|
||||
get
|
||||
@@ -348,6 +359,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
if (_xmlNode.Attributes != null)
|
||||
{
|
||||
_id = int.Parse(_xmlNode.Attributes.GetNamedItem("id").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("key") != null) // because, migration
|
||||
_key = Guid.Parse(_xmlNode.Attributes.GetNamedItem("key").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("template") != null)
|
||||
_template = int.Parse(_xmlNode.Attributes.GetNamedItem("template").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("sortOrder") != null)
|
||||
|
||||
Reference in New Issue
Block a user