Skip to content

Commit 9019c49

Browse files
committed
Merge branch '7.1.9' into 7.2.0
Conflicts: build/NuSpecs/UmbracoCms.Core.nuspec build/UmbracoVersion.txt src/Umbraco.Core/Configuration/UmbracoVersion.cs src/Umbraco.Core/Sync/ServerEnvironmentHelper.cs src/Umbraco.Tests/Plugins/PluginManagerTests.cs src/Umbraco.Web.UI/Umbraco.Web.UI.csproj src/Umbraco.Web/Scheduling/KeepAlive.cs src/Umbraco.Web/Scheduling/ScheduledPublishing.cs src/Umbraco.Web/Trees/ApplicationTreeRegistrar.cs src/UmbracoExamine/BaseUmbracoIndexer.cs src/UmbracoExamine/DataServices/UmbracoContentService.cs src/UmbracoExamine/DataServices/UmbracoMediaService.cs src/UmbracoExamine/UmbracoContentIndexer.cs src/UmbracoExamine/UmbracoMemberIndexer.cs
2 parents a5240a8 + 74ebf67 commit 9019c49

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3675
-2092
lines changed

src/Umbraco.Core/ApplicationEventHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ protected virtual void ApplicationStarted(UmbracoApplicationBase umbracoApplicat
7474
/// <returns></returns>
7575
private bool ShouldExecute(ApplicationContext applicationContext)
7676
{
77-
if (applicationContext.IsConfigured && applicationContext.DatabaseContext.IsDatabaseConfigured)
77+
if (applicationContext.IsConfigured && applicationContext.DatabaseContext.CanConnect)
7878
{
7979
return true;
8080
}
@@ -84,7 +84,7 @@ private bool ShouldExecute(ApplicationContext applicationContext)
8484
return true;
8585
}
8686

87-
if (!applicationContext.DatabaseContext.IsDatabaseConfigured && ExecuteWhenDatabaseNotConfigured)
87+
if (!applicationContext.DatabaseContext.CanConnect && ExecuteWhenDatabaseNotConfigured)
8888
{
8989
return true;
9090
}

src/Umbraco.Core/Configuration/UmbracoSettings/IScheduledTasksSection.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
55
public interface IScheduledTasksSection : IUmbracoConfigurationSection
66
{
77
IEnumerable<IScheduledTask> Tasks { get; }
8+
9+
string BaseUrl { get; }
810
}
911
}

src/Umbraco.Core/Configuration/UmbracoSettings/ScheduledTasksElement.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,11 @@ IEnumerable<IScheduledTask> IScheduledTasksSection.Tasks
1616
{
1717
get { return Tasks; }
1818
}
19+
20+
[ConfigurationProperty("baseUrl", IsRequired = false, DefaultValue = null)]
21+
public string BaseUrl
22+
{
23+
get { return (string)base["baseUrl"]; }
24+
}
1925
}
2026
}

src/Umbraco.Core/DatabaseContext.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ public class DatabaseContext
2626
{
2727
private readonly IDatabaseFactory _factory;
2828
private bool _configured;
29+
private bool _canConnect;
30+
private volatile bool _connectCheck = false;
31+
private readonly object _locker = new object();
2932
private string _connectionString;
3033
private string _providerName;
3134
private DatabaseSchemaResult _result;
@@ -56,6 +59,32 @@ public bool IsDatabaseConfigured
5659
get { return _configured; }
5760
}
5861

62+
/// <summary>
63+
/// Determines if the db can be connected to
64+
/// </summary>
65+
public bool CanConnect
66+
{
67+
get
68+
{
69+
if (IsDatabaseConfigured == false) return false;
70+
71+
//double check lock so that it is only checked once and is fast
72+
if (_connectCheck == false)
73+
{
74+
lock (_locker)
75+
{
76+
if (_canConnect == false)
77+
{
78+
_canConnect = DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DatabaseProvider);
79+
_connectCheck = true;
80+
}
81+
}
82+
}
83+
84+
return _canConnect;
85+
}
86+
}
87+
5988
/// <summary>
6089
/// Gets the configured umbraco db connection string.
6190
/// </summary>

src/Umbraco.Core/Persistence/DbConnectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public static bool IsAvailable(this IDbConnection connection)
7575
connection.Open();
7676
connection.Close();
7777
}
78-
catch (SqlException)
78+
catch (DbException)
7979
{
8080
return false;
8181
}

src/Umbraco.Core/Services/ApplicationTreeService.cs

Lines changed: 177 additions & 75 deletions
Large diffs are not rendered by default.

src/Umbraco.Core/Services/IApplicationTreeService.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@ namespace Umbraco.Core.Services
55
{
66
public interface IApplicationTreeService
77
{
8-
void Intitialize(IEnumerable<ApplicationTree> existingTrees);
8+
/// <summary>
9+
/// Initializes the service with any trees found in plugins
10+
/// </summary>
11+
/// <param name="allAvailableTrees">
12+
/// A collection of all available tree found in assemblies in the application
13+
/// </param>
14+
/// <remarks>
15+
/// This will update the trees.config with the found tree plugins that are not currently listed in the file when the first
16+
/// access is made to resolve the tree collection
17+
/// </remarks>
18+
void Intitialize(IEnumerable<ApplicationTree> allAvailableTrees);
919

1020
/// <summary>
1121
/// Creates a new application tree.

src/Umbraco.Core/Services/ISectionService.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@ namespace Umbraco.Core.Services
66
public interface ISectionService
77
{
88
/// <summary>
9-
/// Ensures all available sections exist in the storage medium
9+
/// Initializes the service with all available application plugins
1010
/// </summary>
11-
/// <param name="existingSections"></param>
12-
void Initialize(IEnumerable<Section> existingSections);
11+
/// <param name="allAvailableSections">
12+
/// All application plugins found in assemblies
13+
/// </param>
14+
/// <remarks>
15+
/// This is used to populate the app.config file with any applications declared in plugins that don't exist in the file
16+
/// </remarks>
17+
void Initialize(IEnumerable<Section> allAvailableSections);
1318

1419
/// <summary>
1520
/// The cache storage for all applications

src/Umbraco.Core/Services/SectionService.cs

Lines changed: 105 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,31 @@ namespace Umbraco.Core.Services
1717
internal class SectionService : ISectionService
1818
{
1919
private readonly IUserService _userService;
20+
private IEnumerable<Section> _allAvailableSections;
2021
private readonly IApplicationTreeService _applicationTreeService;
22+
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
2123
private readonly CacheHelper _cache;
24+
internal const string AppConfigFileName = "applications.config";
25+
private static string _appConfig;
26+
private volatile bool _isInitialized = false;
27+
private static readonly object Locker = new object();
2228

2329
public SectionService(
2430
IUserService userService,
25-
IApplicationTreeService applicationTreeService,
31+
IApplicationTreeService applicationTreeService,
32+
IDatabaseUnitOfWorkProvider uowProvider,
2633
CacheHelper cache)
2734
{
2835
if (applicationTreeService == null) throw new ArgumentNullException("applicationTreeService");
2936
if (cache == null) throw new ArgumentNullException("cache");
3037

3138
_userService = userService;
3239
_applicationTreeService = applicationTreeService;
40+
_uowProvider = uowProvider;
3341
_cache = cache;
3442
}
3543

36-
internal const string AppConfigFileName = "applications.config";
37-
private static string _appConfig;
38-
private static readonly object Locker = new object();
44+
3945

4046
/// <summary>
4147
/// gets/sets the application.config file path
@@ -57,59 +63,92 @@ internal static string AppConfigFilePath
5763
}
5864

5965
/// <summary>
60-
/// Ensures all available sections exist in the storage medium
66+
/// Initializes the service with all available application plugins
6167
/// </summary>
62-
/// <param name="existingSections"></param>
63-
public void Initialize(IEnumerable<Section> existingSections)
68+
/// <param name="allAvailableSections">
69+
/// All application plugins found in assemblies
70+
/// </param>
71+
/// <remarks>
72+
/// This is used to populate the app.config file with any applications declared in plugins that don't exist in the file
73+
/// </remarks>
74+
public void Initialize(IEnumerable<Section> allAvailableSections)
6475
{
65-
LoadXml(doc =>
66-
{
67-
foreach (var attr in existingSections)
68-
{
69-
doc.Root.Add(new XElement("add",
70-
new XAttribute("alias", attr.Alias),
71-
new XAttribute("name", attr.Name),
72-
new XAttribute("icon", attr.Icon),
73-
new XAttribute("sortOrder", attr.SortOrder)));
74-
}
75-
}, true);
76+
_allAvailableSections = allAvailableSections;
7677
}
7778

7879
/// <summary>
7980
/// The cache storage for all applications
8081
/// </summary>
8182
public IEnumerable<Section> GetSections()
8283
{
83-
return _cache.GetCacheItem(
84+
return _cache.RuntimeCache.GetCacheItem<IEnumerable<Section>>(
8485
CacheKeys.ApplicationsCacheKey,
8586
() =>
8687
{
8788
////used for unit tests
8889
//if (_testApps != null)
8990
// return _testApps;
9091

91-
var tmp = new List<Section>();
92+
var list = ReadFromXmlAndSort();
9293

93-
LoadXml(doc =>
94+
//On first access we need to do some initialization
95+
if (_isInitialized == false)
96+
{
97+
lock (Locker)
9498
{
95-
foreach (var addElement in doc.Root.Elements("add").OrderBy(x =>
96-
{
97-
var sortOrderAttr = x.Attribute("sortOrder");
98-
return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0;
99-
}))
99+
if (_isInitialized == false)
100100
{
101-
var sortOrderAttr = addElement.Attribute("sortOrder");
102-
tmp.Add(new Section(addElement.Attribute("name").Value,
103-
addElement.Attribute("alias").Value,
104-
addElement.Attribute("icon").Value,
105-
sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0));
101+
//now we can check the non-volatile flag
102+
if (_allAvailableSections != null)
103+
{
104+
var hasChanges = false;
105+
106+
LoadXml(doc =>
107+
{
108+
//Now, load in the xml structure and update it with anything that is not declared there and save the file.
109+
110+
//NOTE: On the first iteration here, it will lazily scan all apps, etc... this is because this ienumerable is lazy
111+
// based on the ApplicationRegistrar - and as noted there this is not an ideal way to do things but were stuck like this
112+
// currently because of the legacy assemblies and types not in the Core.
113+
114+
//Get all the trees not registered in the config
115+
var unregistered = _allAvailableSections
116+
.Where(x => list.Any(l => l.Alias == x.Alias) == false)
117+
.ToArray();
118+
119+
hasChanges = unregistered.Any();
120+
121+
var count = 0;
122+
foreach (var attr in unregistered)
123+
{
124+
doc.Root.Add(new XElement("add",
125+
new XAttribute("alias", attr.Alias),
126+
new XAttribute("name", attr.Name),
127+
new XAttribute("icon", attr.Icon),
128+
new XAttribute("sortOrder", attr.SortOrder)));
129+
count++;
130+
}
131+
132+
//don't save if there's no changes
133+
return count > 0;
134+
}, true);
135+
136+
if (hasChanges)
137+
{
138+
//If there were changes, we need to re-read the structures from the XML
139+
list = ReadFromXmlAndSort();
140+
}
141+
}
106142
}
107-
}, false);
108-
return tmp;
143+
}
144+
}
145+
146+
return list;
147+
109148
});
110149
}
111150

112-
internal void LoadXml(Action<XDocument> callback, bool saveAfterCallback)
151+
internal void LoadXml(Func<XDocument, bool> callback, bool saveAfterCallbackIfChanged)
113152
{
114153
lock (Locker)
115154
{
@@ -119,9 +158,9 @@ internal void LoadXml(Action<XDocument> callback, bool saveAfterCallback)
119158

120159
if (doc.Root != null)
121160
{
122-
callback.Invoke(doc);
161+
var changed = callback.Invoke(doc);
123162

124-
if (saveAfterCallback)
163+
if (saveAfterCallbackIfChanged && changed)
125164
{
126165
//ensure the folder is created!
127166
Directory.CreateDirectory(Path.GetDirectoryName(AppConfigFilePath));
@@ -194,6 +233,7 @@ public void MakeNew(string name, string alias, string icon, int sortOrder)
194233
new XAttribute("name", name),
195234
new XAttribute("icon", icon),
196235
new XAttribute("sortOrder", sortOrder)));
236+
return true;
197237
}, true);
198238

199239
//raise event
@@ -209,7 +249,7 @@ public void DeleteSection(Section section)
209249
lock (Locker)
210250
{
211251
//delete the assigned applications
212-
ApplicationContext.Current.DatabaseContext.Database.Execute(
252+
_uowProvider.GetUnitOfWork().Database.Execute(
213253
"delete from umbracoUser2App where app = @appAlias",
214254
new { appAlias = section.Alias });
215255

@@ -222,14 +262,41 @@ public void DeleteSection(Section section)
222262

223263
LoadXml(doc =>
224264
{
225-
doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == section.Alias).Remove();
265+
doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == section.Alias)
266+
.Remove();
267+
268+
return true;
226269
}, true);
227270

228271
//raise event
229272
OnDeleted(section, new EventArgs());
230273
}
231274
}
232275

276+
private List<Section> ReadFromXmlAndSort()
277+
{
278+
var tmp = new List<Section>();
279+
280+
LoadXml(doc =>
281+
{
282+
foreach (var addElement in doc.Root.Elements("add").OrderBy(x =>
283+
{
284+
var sortOrderAttr = x.Attribute("sortOrder");
285+
return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0;
286+
}))
287+
{
288+
var sortOrderAttr = addElement.Attribute("sortOrder");
289+
tmp.Add(new Section(addElement.Attribute("name").Value,
290+
addElement.Attribute("alias").Value,
291+
addElement.Attribute("icon").Value,
292+
sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0));
293+
}
294+
return false;
295+
}, false);
296+
297+
return tmp;
298+
}
299+
233300
internal static event TypedEventHandler<Section, EventArgs> Deleted;
234301
private static void OnDeleted(Section app, EventArgs args)
235302
{

src/Umbraco.Core/Services/ServiceContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ private void BuildServiceCache(
164164
_treeService = new Lazy<IApplicationTreeService>(() => new ApplicationTreeService(cache));
165165

166166
if (_sectionService == null)
167-
_sectionService = new Lazy<ISectionService>(() => new SectionService(_userService.Value, _treeService.Value, cache));
167+
_sectionService = new Lazy<ISectionService>(() => new SectionService(_userService.Value, _treeService.Value, provider, cache));
168168

169169
if (_macroService == null)
170170
_macroService = new Lazy<IMacroService>(() => new MacroService(provider, repositoryFactory.Value));

0 commit comments

Comments
 (0)