Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8baaae4da6 | |||
| ed05a3223f | |||
| 25e3134e35 | |||
| f1b9b98f5d | |||
| d2f7eda074 | |||
| 3062eedb4f | |||
| 1e3dd4c5cd | |||
| a7871abbd9 | |||
| bf3a08cf85 | |||
| 7bc208e490 | |||
| 6aa633c8c5 | |||
| 9be2f99e7b | |||
| 2d5bfc0fe2 | |||
| c01f864e37 | |||
| a8be796d68 | |||
| 4acbdbe896 | |||
| 34a9eef8b8 | |||
| 0f56fa4baa | |||
| 82a8404b2e | |||
| bce8affe16 | |||
| 4bbd8097a2 | |||
| da9c810d78 | |||
| 431d066300 | |||
| 6d50bd891a | |||
| 1d00e3c5d8 | |||
| e69422c8d8 | |||
| a277ac2fe4 | |||
| 1067b1e245 | |||
| 7987f13a11 | |||
| ccda1bdd73 | |||
| 76a6f2d2d0 | |||
| 69428b2281 | |||
| 7cd39918a0 | |||
| 9a626c9da6 | |||
| 0520797c09 | |||
| 9b85ba5b90 | |||
| ca738979ce | |||
| 8cfb56adf4 | |||
| 053346d79b | |||
| 044c9c95f8 | |||
| b23ea69b3e | |||
| 46f9c5ff05 | |||
| 3bc4b50d74 | |||
| 1a2849dfb0 | |||
| bcb5883230 | |||
| 18080c1cfb | |||
| 2600a3887e | |||
| 45bec2a67d | |||
| da7456fd2a | |||
| 275ba00e24 | |||
| d00bf4649d | |||
| 04976f8063 | |||
| 3e7c9fc81e | |||
| a1f4d7b16f | |||
| 811ef4a444 | |||
| 69ac621f5a | |||
| 610582df38 | |||
| 181f7c1819 | |||
| 73fbe7d78c | |||
| 5d1340e864 | |||
| c867f609f1 | |||
| 69879dc8f8 | |||
| f663a13391 |
+9
-9
@@ -1,9 +1,9 @@
|
||||
# The MIT License (MIT) #
|
||||
|
||||
Copyright (c) 2013 Umbraco
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
# The MIT License (MIT) #
|
||||
|
||||
Copyright (c) 2013 Umbraco
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -266,7 +266,6 @@
|
||||
<Message Text="Finished compiling projects" Importance="high" />
|
||||
</Target>
|
||||
|
||||
|
||||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<PropertyGroup>
|
||||
<NewVersion>$(BUILD_RELEASE)</NewVersion>
|
||||
|
||||
@@ -15,25 +15,24 @@
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.40804.0,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.30506.0,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[4.0.30506,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi.WebHost" version="[4.0.30506, 6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi.Core" version="[4.0.30506, 6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi.Client" version="[4.0.30506, 6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.1" />
|
||||
<dependency id="Microsoft.Net.Http" version="[2.0.20710.0, 3.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.0, 3.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.Cookies" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.OAuth" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.9.6, 7.0.0)" />
|
||||
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.8.3.1, 2.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.8.4, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.8.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.0.0, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.63, 1.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.65, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
|
||||
</dependencies>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoExamine.PDF</id>
|
||||
<version>0.7.0</version>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>UmbracoExmine.PDF</description>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[7.0.0, 8.0.0)" />
|
||||
<dependency id="iTextSharp" version="[5.5.3, 6.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\UmbracoExamine.PDF\UmbracoExamine.PDF.dll" target="lib\UmbracoExamine.PDF.dll" />
|
||||
<file src="..\_BuildOutput\UmbracoExamine.PDF\UmbracoExamine.PDF.XML" target="lib\UmbracoExamine.PDF.XML" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -21,7 +21,6 @@
|
||||
<appSettings xdt:Transform="InsertIfMissing" />
|
||||
<appSettings>
|
||||
<add key="ValidationSettings:UnobtrusiveValidationMode" value="None" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
</appSettings>
|
||||
|
||||
<umbracoConfiguration xdt:Transform="InsertIfMissing">
|
||||
@@ -144,7 +143,6 @@
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Newtonsoft.Json')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Mvc')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Htttp')" xdt:Transform="Remove" />
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
@@ -162,10 +160,6 @@
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.3.0
|
||||
beta
|
||||
7.2.7
|
||||
Binary file not shown.
@@ -77,9 +77,8 @@
|
||||
<Compile Include="SqlCEUtility.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="app.config" />
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -14,22 +14,6 @@
|
||||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.3.0-beta")]
|
||||
[assembly: AssemblyFileVersion("7.2.7")]
|
||||
[assembly: AssemblyInformationalVersion("7.2.7")]
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
@@ -13,14 +12,13 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
internal sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="packageActions"></param>
|
||||
internal ActionsResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> packageActions)
|
||||
: base(serviceProvider, logger, packageActions)
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="packageActions"></param>
|
||||
internal ActionsResolver(Func<IEnumerable<Type>> packageActions)
|
||||
: base(packageActions)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -57,7 +55,7 @@ namespace Umbraco.Core
|
||||
var instance = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
|
||||
//if the singletone initializer is not found, try simply creating an instance of the IAction if it supports public constructors
|
||||
if (instance == null)
|
||||
typeInstance = ServiceProvider.GetService(type) as IAction;
|
||||
typeInstance = PluginManager.Current.CreateInstance<IAction>(type);
|
||||
else
|
||||
typeInstance = instance.GetValue(null, null) as IAction;
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Helper methods for Activation
|
||||
/// </summary>
|
||||
internal static class ActivatorHelper
|
||||
@@ -12,9 +14,7 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
public static T CreateInstance<T>() where T : class, new()
|
||||
{
|
||||
return new ActivatorServiceProvider().GetService(typeof (T)) as T;
|
||||
return Activator.CreateInstance(typeof(T)) as T;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
internal class ActivatorServiceProvider : IServiceProvider
|
||||
{
|
||||
public object GetService(Type serviceType)
|
||||
{
|
||||
return Activator.CreateInstance(serviceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,12 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Cache;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -22,35 +18,23 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public class ApplicationContext : IDisposable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, ProfilingLogger logger)
|
||||
{
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
|
||||
{
|
||||
if (dbContext == null) throw new ArgumentNullException("dbContext");
|
||||
if (serviceContext == null) throw new ArgumentNullException("serviceContext");
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
_databaseContext = dbContext;
|
||||
_services = serviceContext;
|
||||
ApplicationCache = cache;
|
||||
ProfilingLogger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <param name="cache"></param>
|
||||
[Obsolete("Use the other constructor specifying an ILogger instead")]
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
|
||||
: this(dbContext, serviceContext, cache,
|
||||
new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler))
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -60,6 +44,8 @@ namespace Umbraco.Core
|
||||
public ApplicationContext(CacheHelper cache)
|
||||
{
|
||||
ApplicationCache = cache;
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -75,13 +61,13 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public static ApplicationContext EnsureContext(ApplicationContext appContext, bool replaceContext)
|
||||
{
|
||||
if (ApplicationContext.Current != null)
|
||||
if (Current != null)
|
||||
{
|
||||
if (!replaceContext)
|
||||
return ApplicationContext.Current;
|
||||
return Current;
|
||||
}
|
||||
ApplicationContext.Current = appContext;
|
||||
return ApplicationContext.Current;
|
||||
Current = appContext;
|
||||
return Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -98,44 +84,16 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
[Obsolete("Use the other method specifying an ProfilingLogger instead")]
|
||||
public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, bool replaceContext)
|
||||
{
|
||||
if (ApplicationContext.Current != null)
|
||||
if (Current != null)
|
||||
{
|
||||
if (!replaceContext)
|
||||
return ApplicationContext.Current;
|
||||
return Current;
|
||||
}
|
||||
var ctx = new ApplicationContext(dbContext, serviceContext, cache);
|
||||
ApplicationContext.Current = ctx;
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A method used to create and ensure that a global ApplicationContext singleton is created.
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="replaceContext">
|
||||
/// If set to true will replace the current singleton instance - This should only be used for unit tests or on app
|
||||
/// startup if for some reason the boot manager is not the umbraco boot manager.
|
||||
/// </param>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, ProfilingLogger logger, bool replaceContext)
|
||||
{
|
||||
if (ApplicationContext.Current != null)
|
||||
{
|
||||
if (!replaceContext)
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
var ctx = new ApplicationContext(dbContext, serviceContext, cache, logger);
|
||||
ApplicationContext.Current = ctx;
|
||||
return ApplicationContext.Current;
|
||||
Current = ctx;
|
||||
return Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -151,13 +109,7 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public CacheHelper ApplicationCache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Exposes the global ProfilingLogger - this should generally not be accessed via the UmbracoContext and should normally just be exposed
|
||||
/// on most base classes or injected with IoC
|
||||
/// </summary>
|
||||
public ProfilingLogger ProfilingLogger { get; private set; }
|
||||
|
||||
// IsReady is set to true by the boot manager once it has successfully booted
|
||||
// IsReady is set to true by the boot manager once it has successfully booted
|
||||
// note - the original umbraco module checks on content.Instance in umbraco.dll
|
||||
// now, the boot task that setup the content store ensures that it is ready
|
||||
bool _isReady = false;
|
||||
@@ -190,80 +142,75 @@ namespace Umbraco.Core
|
||||
// GlobalSettings.CurrentVersion returns the hard-coded "current version"
|
||||
// the system is configured if they match
|
||||
// if they don't, install runs, updates web.config (presumably) and updates GlobalSettings.ConfiguredStatus
|
||||
//
|
||||
// then there is Application["umbracoNeedConfiguration"] which makes no sense... getting rid of it... SD: I have actually remove that now!
|
||||
//
|
||||
|
||||
public bool IsConfigured
|
||||
{
|
||||
// todo - we should not do this - ok for now
|
||||
get { return _configured.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The application url.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The application url is the url that should be used by services to talk to the application,
|
||||
/// eg keep alive or scheduled publishing services. It must exist on a global context because
|
||||
/// some of these services may not run within a web context.
|
||||
/// The format of the application url is:
|
||||
/// - has a scheme (http or https)
|
||||
/// - has the SystemDirectories.Umbraco path
|
||||
/// - does not end with a slash
|
||||
/// It is initialized on the first request made to the server, by UmbracoModule.EnsureApplicationUrl:
|
||||
/// - if umbracoSettings:settings/web.routing/@umbracoApplicationUrl is set, use the value (new setting)
|
||||
/// - if umbracoSettings:settings/scheduledTasks/@baseUrl is set, use the value (backward compatibility)
|
||||
/// - otherwise, use the url of the (first) request.
|
||||
/// Not locking, does not matter if several threads write to this.
|
||||
/// See also issues:
|
||||
/// - http://issues.umbraco.org/issue/U4-2059
|
||||
/// - http://issues.umbraco.org/issue/U4-6788
|
||||
/// - http://issues.umbraco.org/issue/U4-5728
|
||||
/// - http://issues.umbraco.org/issue/U4-5391
|
||||
/// </remarks>
|
||||
internal string UmbracoApplicationUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return Configured;
|
||||
// if initialized, return
|
||||
if (_umbracoApplicationUrl != null) return _umbracoApplicationUrl;
|
||||
|
||||
// try settings
|
||||
ServerEnvironmentHelper.TrySetApplicationUrlFromSettings(this, UmbracoConfig.For.UmbracoSettings());
|
||||
|
||||
// and return what we have, may be null
|
||||
return _umbracoApplicationUrl;
|
||||
}
|
||||
set
|
||||
{
|
||||
_umbracoApplicationUrl = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the db is configured, there is a database context and there is an umbraco schema, but we are not 'configured' , then it means we are upgrading
|
||||
/// </summary>
|
||||
public bool IsUpgrading
|
||||
{
|
||||
get
|
||||
internal string _umbracoApplicationUrl; // internal for tests
|
||||
|
||||
private Lazy<bool> _configured;
|
||||
internal MainDom MainDom { get; private set; }
|
||||
|
||||
private void Init()
|
||||
{
|
||||
MainDom = new MainDom();
|
||||
MainDom.Acquire();
|
||||
//Create the lazy value to resolve whether or not the application is 'configured'
|
||||
_configured = new Lazy<bool>(() =>
|
||||
{
|
||||
if (IsConfigured == false
|
||||
&& DatabaseContext != null
|
||||
&& DatabaseContext.IsDatabaseConfigured)
|
||||
var configStatus = ConfigurationStatus;
|
||||
var currentVersion = UmbracoVersion.Current.ToString(3);
|
||||
var ok = configStatus == currentVersion;
|
||||
if (ok == false)
|
||||
{
|
||||
var schemaresult = DatabaseContext.ValidateDatabaseSchema();
|
||||
if (schemaresult.ValidTables.Count > 0) return true;
|
||||
LogHelper.Debug<ApplicationContext>("CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The original/first url that the web application executes
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// we need to set the initial url in our ApplicationContext, this is so our keep alive service works and this must
|
||||
/// exist on a global context because the keep alive service doesn't run in a web context.
|
||||
/// we are NOT going to put a lock on this because locking will slow down the application and we don't really care
|
||||
/// if two threads write to this at the exact same time during first page hit.
|
||||
/// see: http://issues.umbraco.org/issue/U4-2059
|
||||
/// </remarks>
|
||||
internal string OriginalRequestUrl { get; set; }
|
||||
|
||||
private bool _versionsDifferenceReported;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the version configured matches the assembly version
|
||||
/// </summary>
|
||||
private bool Configured
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var configStatus = ConfigurationStatus;
|
||||
var currentVersion = UmbracoVersion.Current.ToString(3);
|
||||
var ok = configStatus == currentVersion;
|
||||
|
||||
if (ok == false && _versionsDifferenceReported == false)
|
||||
{
|
||||
// remember it's been reported so we don't flood the log
|
||||
// no thread-safety so there may be a few log entries, doesn't matter
|
||||
_versionsDifferenceReported = true;
|
||||
ProfilingLogger.Logger.Debug<ApplicationContext>("CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
});
|
||||
}
|
||||
|
||||
private string ConfigurationStatus
|
||||
{
|
||||
@@ -280,12 +227,6 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertIsReady()
|
||||
{
|
||||
if (!this.IsReady)
|
||||
throw new Exception("ApplicationContext is not ready yet.");
|
||||
}
|
||||
|
||||
private void AssertIsNotReady()
|
||||
{
|
||||
if (this.IsReady)
|
||||
@@ -361,7 +302,7 @@ namespace Umbraco.Core
|
||||
this.ApplicationCache = null;
|
||||
if (_databaseContext != null) //need to check the internal field here
|
||||
{
|
||||
if (DatabaseContext.IsDatabaseConfigured && DatabaseContext.Database != null)
|
||||
if (DatabaseContext.IsDatabaseConfigured)
|
||||
{
|
||||
DatabaseContext.Database.Dispose();
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
private bool ShouldExecute(ApplicationContext applicationContext)
|
||||
{
|
||||
if (applicationContext.IsConfigured && applicationContext.DatabaseContext.CanConnect)
|
||||
if (applicationContext.IsConfigured && applicationContext.DatabaseContext.IsDatabaseConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace Umbraco.Core
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!applicationContext.DatabaseContext.CanConnect && ExecuteWhenDatabaseNotConfigured)
|
||||
if (!applicationContext.DatabaseContext.IsDatabaseConfigured && ExecuteWhenDatabaseNotConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,14 +63,14 @@ namespace Umbraco.Core
|
||||
// for anonymous semaphore, use the unique releaser, else create a new one
|
||||
return _semaphore != null
|
||||
? _releaser // (IDisposable)new SemaphoreSlimReleaser(_semaphore)
|
||||
: (IDisposable)new NamedSemaphoreReleaser(_semaphore2);
|
||||
: new NamedSemaphoreReleaser(_semaphore2);
|
||||
}
|
||||
|
||||
public Task<IDisposable> LockAsync()
|
||||
{
|
||||
var wait = _semaphore != null
|
||||
? _semaphore.WaitAsync()
|
||||
: WaitOneAsync(_semaphore2);
|
||||
? _semaphore.WaitAsync()
|
||||
: _semaphore2.WaitOneAsync();
|
||||
|
||||
return wait.IsCompleted
|
||||
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
|
||||
@@ -79,6 +79,19 @@ namespace Umbraco.Core
|
||||
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
|
||||
}
|
||||
|
||||
public Task<IDisposable> LockAsync(int millisecondsTimeout)
|
||||
{
|
||||
var wait = _semaphore != null
|
||||
? _semaphore.WaitAsync(millisecondsTimeout)
|
||||
: _semaphore2.WaitOneAsync(millisecondsTimeout);
|
||||
|
||||
return wait.IsCompleted
|
||||
? _releaserTask ?? Task.FromResult(CreateReleaser()) // anonymous vs named
|
||||
: wait.ContinueWith((_, state) => (((AsyncLock)state).CreateReleaser()),
|
||||
this, CancellationToken.None,
|
||||
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
|
||||
}
|
||||
|
||||
public IDisposable Lock()
|
||||
{
|
||||
if (_semaphore != null)
|
||||
@@ -168,40 +181,5 @@ namespace Umbraco.Core
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/25382583/waiting-on-a-named-semaphore-with-waitone100-vs-waitone0-task-delay100
|
||||
// http://blog.nerdbank.net/2011/07/c-await-for-waithandle.html
|
||||
// F# has a AwaitWaitHandle method that accepts a time out... and seems pretty complex...
|
||||
// version below should be OK
|
||||
|
||||
private static Task WaitOneAsync(WaitHandle handle)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
var callbackHandleInitLock = new object();
|
||||
lock (callbackHandleInitLock)
|
||||
{
|
||||
RegisteredWaitHandle callbackHandle = null;
|
||||
// ReSharper disable once RedundantAssignment
|
||||
callbackHandle = ThreadPool.RegisterWaitForSingleObject(
|
||||
handle,
|
||||
(state, timedOut) =>
|
||||
{
|
||||
tcs.SetResult(null);
|
||||
|
||||
// we take a lock here to make sure the outer method has completed setting the local variable callbackHandle.
|
||||
lock (callbackHandleInitLock)
|
||||
{
|
||||
// ReSharper disable once PossibleNullReferenceException
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
callbackHandle.Unregister(null);
|
||||
}
|
||||
},
|
||||
/*state:*/ null,
|
||||
/*millisecondsTimeOutInterval:*/ Timeout.Infinite,
|
||||
/*executeOnlyOnce:*/ true);
|
||||
}
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,13 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
[Obsolete("Use Umbraco.Core.Services.IAuditService instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
/// <summary>
|
||||
/// Public method to create new audit trail
|
||||
/// </summary>
|
||||
public static class Audit
|
||||
{
|
||||
public static void Add(Umbraco.Core.Auditing.AuditTypes type, string comment, int userId, int objectId)
|
||||
public static void Add(AuditTypes type, string comment, int userId, int objectId)
|
||||
{
|
||||
ApplicationContext.Current.Services.AuditService.Add(
|
||||
Enum<Umbraco.Core.Models.AuditType>.Parse(type.ToString()),
|
||||
comment, userId, objectId);
|
||||
AuditTrail.Current.AddEntry(type, comment, userId, objectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the Audit implementation
|
||||
/// </summary>
|
||||
internal class AuditTrail
|
||||
{
|
||||
#region Singleton
|
||||
|
||||
private static readonly Lazy<AuditTrail> lazy = new Lazy<AuditTrail>(() => new AuditTrail());
|
||||
|
||||
public static AuditTrail Current { get { return lazy.Value; } }
|
||||
|
||||
private AuditTrail()
|
||||
{
|
||||
WriteProvider = new DataAuditWriteProvider();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private IAuditWriteProvider WriteProvider { get; set; }
|
||||
|
||||
public void AddEntry(AuditTypes type, string comment, int userId, int objectId)
|
||||
{
|
||||
WriteProvider.WriteEntry(objectId, userId, DateTime.Now, type.ToString(), comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
[Obsolete("Use Umbraco.Core.Models.AuditType instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
/// <summary>
|
||||
/// Enums for vailable types of auditing
|
||||
/// </summary>
|
||||
public enum AuditTypes
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
internal class DataAuditWriteProvider : IAuditWriteProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes an audit entry to the underlaying datastore.
|
||||
/// </summary>
|
||||
/// <param name="objectId">Id of the object (Content, ContentType, Media, etc.)</param>
|
||||
/// <param name="userId">Id of the user</param>
|
||||
/// <param name="date">Datestamp</param>
|
||||
/// <param name="header">Audit header</param>
|
||||
/// <param name="comment">Audit comment</param>
|
||||
public void WriteEntry(int objectId, int userId, DateTime date, string header, string comment)
|
||||
{
|
||||
ApplicationContext.Current.DatabaseContext.Database.Insert(new LogDto
|
||||
{
|
||||
Comment = comment,
|
||||
Datestamp = date,
|
||||
Header = header,
|
||||
NodeId = objectId,
|
||||
UserId = userId
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
internal interface IAuditWriteProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes an audit entry to the underlaying datastore.
|
||||
/// </summary>
|
||||
/// <param name="objectId">Id of the object (Content, ContentType, Media, etc.)</param>
|
||||
/// <param name="userId">Id of the user</param>
|
||||
/// <param name="date">Datestamp</param>
|
||||
/// <param name="header">Audit header</param>
|
||||
/// <param name="comment">Audit comment</param>
|
||||
void WriteEntry(int objectId, int userId, DateTime date, string header, string comment);
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,6 @@ namespace Umbraco.Core.Cache
|
||||
public const string MemberBusinessLogicCacheKey = "MemberCacheItem_";
|
||||
|
||||
public const string TemplateFrontEndCacheKey = "template";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache";
|
||||
|
||||
public const string UserContextCacheKey = "UmbracoUserContext";
|
||||
@@ -47,15 +45,11 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string LanguageCacheKey = "UmbracoLanguageCache";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string DomainCacheKey = "UmbracoDomainList";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string StylesheetCacheKey = "UmbracoStylesheet";
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty";
|
||||
|
||||
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
foreach (var entry in GetDictionaryEntries()
|
||||
.ToArray())
|
||||
RemoveEntry((string) entry.Key);
|
||||
RemoveEntry((string)entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace Umbraco.Core.Cache
|
||||
return value == null || (isInterface ? (type.IsInstanceOfType(value)) : (value.GetType() == type));
|
||||
})
|
||||
.ToArray())
|
||||
RemoveEntry((string) entry.Key);
|
||||
RemoveEntry((string)entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace Umbraco.Core.Cache
|
||||
return value == null || (isInterface ? (value is T) : (value.GetType() == typeOfT));
|
||||
})
|
||||
.ToArray())
|
||||
RemoveEntry((string) entry.Key);
|
||||
RemoveEntry((string)entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,10 +171,10 @@ namespace Umbraco.Core.Cache
|
||||
// if T is an interface remove anything that implements that interface
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return (isInterface ? (value is T) : (value.GetType() == typeOfT))
|
||||
// run predicate on the 'public key' part only, ie without prefix
|
||||
&& predicate(((string) x.Key).Substring(plen), (T) value);
|
||||
// run predicate on the 'public key' part only, ie without prefix
|
||||
&& predicate(((string)x.Key).Substring(plen), (T)value);
|
||||
}))
|
||||
RemoveEntry((string) entry.Key);
|
||||
RemoveEntry((string)entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace Umbraco.Core.Cache
|
||||
foreach (var entry in GetDictionaryEntries()
|
||||
.Where(x => ((string)x.Key).Substring(plen).InvariantStartsWith(keyStartsWith))
|
||||
.ToArray())
|
||||
RemoveEntry((string) entry.Key);
|
||||
RemoveEntry((string)entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace Umbraco.Core.Cache
|
||||
foreach (var entry in GetDictionaryEntries()
|
||||
.Where(x => Regex.IsMatch(((string)x.Key).Substring(plen), regexString))
|
||||
.ToArray())
|
||||
RemoveEntry((string) entry.Key);
|
||||
RemoveEntry((string)entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Cache
|
||||
// cannot create value within the lock, so if result.IsValueCreated is false, just
|
||||
// do nothing here - means that if creation throws, a race condition could cause
|
||||
// more than one thread to reach the return statement below and throw - accepted.
|
||||
|
||||
|
||||
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
|
||||
{
|
||||
result = GetSafeLazy(getCacheItem);
|
||||
@@ -122,7 +122,7 @@ namespace Umbraco.Core.Cache
|
||||
if (eh != null) throw eh.Exception; // throw once!
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Insert
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
const string prefix = CacheItemPrefix + "-";
|
||||
return _cache.Cast<DictionaryEntry>()
|
||||
.Where(x => x.Key is string && ((string) x.Key).StartsWith(prefix));
|
||||
.Where(x => x.Key is string && ((string)x.Key).StartsWith(prefix));
|
||||
}
|
||||
|
||||
protected override void RemoveEntry(string key)
|
||||
@@ -191,7 +191,7 @@ namespace Umbraco.Core.Cache
|
||||
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
|
||||
if (value == null) return; // do not store null values (backward compat)
|
||||
|
||||
cacheKey = GetCacheKey(cacheKey);
|
||||
cacheKey = GetCacheKey(cacheKey);
|
||||
|
||||
var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
|
||||
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache refresher that supports refreshing cache based on a custom payload
|
||||
/// </summary>
|
||||
interface IPayloadCacheRefresher : IJsonCacheRefresher
|
||||
{
|
||||
/// <summary>
|
||||
/// Refreshes, clears, etc... any cache based on the information provided in the payload
|
||||
/// </summary>
|
||||
/// <param name="payload"></param>
|
||||
void Refresh(object payload);
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,17 @@ using umbraco.interfaces;
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for "json" cache refreshers.
|
||||
/// A base class for json cache refreshers that ensures the correct events are raised when
|
||||
/// cache refreshing occurs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstance">The actual cache refresher type.</typeparam>
|
||||
/// <remarks>Ensures that the correct events are raised when cache refreshing occurs.</remarks>
|
||||
public abstract class JsonCacheRefresherBase<TInstance> : CacheRefresherBase<TInstance>, IJsonCacheRefresher
|
||||
where TInstance : ICacheRefresher
|
||||
/// <typeparam name="TInstanceType">The real cache refresher type, this is used for raising strongly typed events</typeparam>
|
||||
public abstract class JsonCacheRefresherBase<TInstanceType> : CacheRefresherBase<TInstanceType>, IJsonCacheRefresher
|
||||
where TInstanceType : ICacheRefresher
|
||||
{
|
||||
public virtual void Refresh(string json)
|
||||
|
||||
public virtual void Refresh(string jsonPayload)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(json, MessageType.RefreshByJson));
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
if (MemoryCache[key] == null) return;
|
||||
MemoryCache.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ClearCacheObjectTypes(string typeName)
|
||||
@@ -81,7 +81,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
using (new WriteLock(_locker))
|
||||
{
|
||||
var typeOfT = typeof (T);
|
||||
var typeOfT = typeof(T);
|
||||
var isInterface = typeOfT.IsInterface;
|
||||
foreach (var key in MemoryCache
|
||||
.Where(x =>
|
||||
@@ -137,7 +137,7 @@ namespace Umbraco.Core.Cache
|
||||
.Select(x => x.Key)
|
||||
.ToArray()) // ToArray required to remove
|
||||
MemoryCache.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ClearCacheByKeyExpression(string regexString)
|
||||
@@ -149,7 +149,7 @@ namespace Umbraco.Core.Cache
|
||||
.Select(x => x.Key)
|
||||
.ToArray()) // ToArray required to remove
|
||||
MemoryCache.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -201,7 +201,7 @@ namespace Umbraco.Core.Cache
|
||||
return GetCacheItem(cacheKey, getCacheItem, null);
|
||||
}
|
||||
|
||||
public object GetCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal,CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
|
||||
public object GetCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
|
||||
{
|
||||
// see notes in HttpRuntimeCacheProvider
|
||||
|
||||
@@ -264,7 +264,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
policy.ChangeMonitors.Add(new HostFileChangeMonitor(dependentFiles.ToList()));
|
||||
}
|
||||
|
||||
|
||||
if (removedCallback != null)
|
||||
{
|
||||
policy.RemovedCallback = arguments =>
|
||||
@@ -295,6 +295,6 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using Umbraco.Core.Sync;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for "payload" cache refreshers.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstance">The actual cache refresher type.</typeparam>
|
||||
/// <remarks>Ensures that the correct events are raised when cache refreshing occurs.</remarks>
|
||||
public abstract class PayloadCacheRefresherBase<TInstance> : JsonCacheRefresherBase<TInstance>, IPayloadCacheRefresher
|
||||
where TInstance : ICacheRefresher
|
||||
{
|
||||
protected abstract object Deserialize(string json);
|
||||
|
||||
public override void Refresh(string json)
|
||||
{
|
||||
var payload = Deserialize(json);
|
||||
Refresh(payload);
|
||||
}
|
||||
|
||||
public virtual void Refresh(object payload)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(payload, MessageType.RefreshByPayload));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
@@ -13,14 +12,13 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
internal sealed class CacheRefreshersResolver : LegacyTransientObjectsResolver<CacheRefreshersResolver, ICacheRefresher>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="refreshers"></param>
|
||||
internal CacheRefreshersResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> refreshers)
|
||||
: base(serviceProvider, logger, refreshers)
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="refreshers"></param>
|
||||
internal CacheRefreshersResolver(Func<IEnumerable<Type>> refreshers)
|
||||
: base(refreshers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -8,13 +8,10 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
internal class ClientDependencyConfiguration
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly string _fileName;
|
||||
|
||||
public ClientDependencyConfiguration(ILogger logger)
|
||||
public ClientDependencyConfiguration()
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_logger = logger;
|
||||
_fileName = IOHelper.MapPath(string.Format("{0}/ClientDependency.config", SystemDirectories.Config));
|
||||
}
|
||||
|
||||
@@ -38,13 +35,13 @@ namespace Umbraco.Core.Configuration
|
||||
versionAttribute.SetValue(newVersion);
|
||||
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
|
||||
|
||||
_logger.Info<ClientDependencyConfiguration>(string.Format("Updated version number from {0} to {1}", oldVersion, newVersion));
|
||||
LogHelper.Info<ClientDependencyConfiguration>(string.Format("Updated version number from {0} to {1}", oldVersion, newVersion));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
|
||||
LogHelper.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
|
||||
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
|
||||
/// </remarks>
|
||||
public static string UmbracoMvcArea
|
||||
internal static string UmbracoMvcArea
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -83,20 +83,14 @@ namespace Umbraco.Core.Configuration
|
||||
return _dashboardSection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
//ONLY for unit testing
|
||||
internal void SetDashboardSettings(IDashboardSection value)
|
||||
{
|
||||
_dashboardSection = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetUmbracoSettings(IUmbracoSettingsSection value)
|
||||
//ONLY for unit testing
|
||||
internal void SetUmbracoSettings(IUmbracoSettingsSection value)
|
||||
{
|
||||
_umbracoSettings = value;
|
||||
}
|
||||
@@ -116,10 +110,7 @@ namespace Umbraco.Core.Configuration
|
||||
return _umbracoSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
//ONLY for unit testing
|
||||
public void SetBaseRestExtensions(IBaseRestSection value)
|
||||
{
|
||||
_baseRestExtensions = value;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
public interface ITemplatesSection : IUmbracoConfigurationSection
|
||||
{
|
||||
@@ -10,7 +8,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
|
||||
RenderingEngine DefaultRenderingEngine { get; }
|
||||
|
||||
[Obsolete("This has no affect and will be removed in future versions")]
|
||||
bool EnableTemplateFolders { get; }
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@
|
||||
bool DisableFindContentByIdPath { get; }
|
||||
|
||||
string UrlProviderMode { get; }
|
||||
|
||||
string UmbracoApplicationUrl { get; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
@@ -41,7 +40,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("This has no affect and will be removed in future versions")]
|
||||
[ConfigurationProperty("enableTemplateFolders")]
|
||||
internal InnerTextConfigurationElement<bool> EnableTemplateFolders
|
||||
{
|
||||
@@ -69,7 +67,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return DefaultRenderingEngine; }
|
||||
}
|
||||
|
||||
[Obsolete("This has no affect and will be removed in future versions")]
|
||||
bool ITemplatesSection.EnableTemplateFolders
|
||||
{
|
||||
get { return EnableTemplateFolders; }
|
||||
|
||||
@@ -30,8 +30,13 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
[ConfigurationProperty("urlProviderMode", DefaultValue = "AutoLegacy")]
|
||||
public string UrlProviderMode
|
||||
{
|
||||
get { return (string)base["urlProviderMode"]; }
|
||||
get { return (string) base["urlProviderMode"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("umbracoApplicationUrl", DefaultValue = null)]
|
||||
public string UmbracoApplicationUrl
|
||||
{
|
||||
get { return (string)base["umbracoApplicationUrl"]; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.3.0");
|
||||
private static readonly Version Version = new Version("7.2.7");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "beta"; } }
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -78,12 +78,12 @@
|
||||
/// </summary>
|
||||
public const string Dictionary = "dictionary";
|
||||
|
||||
public const string Stylesheets = "stylesheets";
|
||||
//TODO: Fill in the rest!
|
||||
|
||||
/// <summary>
|
||||
/// alias for the template tree.
|
||||
/// alias for the media tree.
|
||||
/// </summary>
|
||||
public const string Templates = "templates";
|
||||
public const string Templates = "template";
|
||||
|
||||
public const string RelationTypes = "relationTypes";
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
|
||||
public const string Languages = "languages";
|
||||
|
||||
//TODO: Fill in the rest!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,25 +11,6 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public static class Conventions
|
||||
{
|
||||
public static class PublicAccess
|
||||
{
|
||||
public const string MemberUsernameRuleType = "MemberUsername";
|
||||
public const string MemberRoleRuleType = "MemberRole";
|
||||
|
||||
[Obsolete("No longer supported, this is here for backwards compatibility only")]
|
||||
public const string MemberIdRuleType = "MemberId";
|
||||
[Obsolete("No longer supported, this is here for backwards compatibility only")]
|
||||
public const string MemberGroupIdRuleType = "MemberGroupId";
|
||||
}
|
||||
|
||||
public static class Localization
|
||||
{
|
||||
/// <summary>
|
||||
/// The root id for all top level dictionary items
|
||||
/// </summary>
|
||||
public const string DictionaryItemRootId = "41c7638d-f529-4bff-853e-59a0c2fb1bde";
|
||||
}
|
||||
|
||||
public static class DataTypes
|
||||
{
|
||||
public const string ListViewPrefix = "List View - ";
|
||||
@@ -303,7 +284,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the alias identifiers for built-in Umbraco relation types.
|
||||
/// Defines the alias identifiers for Umbraco relation types.
|
||||
/// </summary>
|
||||
public static class RelationTypes
|
||||
{
|
||||
@@ -316,16 +297,6 @@ namespace Umbraco.Core
|
||||
/// ContentType alias for default relation type "Relate Document On Copy".
|
||||
/// </summary>
|
||||
public const string RelateDocumentOnCopyAlias = "relateDocumentOnCopy";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType name for default relation type "Relate Parent Document On Delete".
|
||||
/// </summary>
|
||||
public const string RelateParentDocumentOnDeleteName = "Relate Parent Document On Delete";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType alias for default relation type "Relate Parent Document On Delete".
|
||||
/// </summary>
|
||||
public const string RelateParentDocumentOnDeleteAlias = "relateParentDocumentOnDelete";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
@@ -72,11 +70,7 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Guid for a Stylesheet object.
|
||||
/// </summary>
|
||||
[Obsolete("This no longer exists in the database")]
|
||||
public const string Stylesheet = "9F68DA4F-A3A8-44C2-8226-DCBD125E4840";
|
||||
|
||||
[Obsolete("This no longer exists in the database")]
|
||||
internal const string StylesheetProperty = "5555da4f-a123-42b2-4488-dcdfb25e4111";
|
||||
public const string Stylesheet = "9F68DA4F-A3A8-44C2-8226-DCBD125E4840";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the System Root.
|
||||
|
||||
@@ -18,29 +18,5 @@
|
||||
public const string AuthCookieName = "UMB_UCONTEXT";
|
||||
|
||||
}
|
||||
|
||||
public static class Security
|
||||
{
|
||||
|
||||
public const string BackOfficeAuthenticationType = "UmbracoBackOffice";
|
||||
public const string BackOfficeExternalAuthenticationType = "UmbracoExternalCookie";
|
||||
public const string BackOfficeExternalCookieName = "UMB_EXTLOGIN";
|
||||
public const string BackOfficeTokenAuthenticationType = "UmbracoBackOfficeToken";
|
||||
|
||||
/// <summary>
|
||||
/// The prefix used for external identity providers for their authentication type
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default we don't want to interfere with front-end external providers and their default setup, for back office the
|
||||
/// providers need to be setup differently and each auth type for the back office will be prefixed with this value
|
||||
/// </remarks>
|
||||
public const string BackOfficeExternalAuthenticationTypePrefix = "Umbraco.";
|
||||
|
||||
public const string StartContentNodeIdClaimType = "http://umbraco.org/2015/02/identity/claims/backoffice/startcontentnode";
|
||||
public const string StartMediaNodeIdClaimType = "http://umbraco.org/2015/02/identity/claims/backoffice/startmedianode";
|
||||
public const string AllowedApplicationsClaimType = "http://umbraco.org/2015/02/identity/claims/backoffice/allowedapp";
|
||||
public const string SessionIdClaimType = "http://umbraco.org/2015/02/identity/claims/backoffice/sessionid";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+205
-170
@@ -2,10 +2,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
@@ -32,101 +34,95 @@ using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrad
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A bootstrapper for the Umbraco application which initializes all objects for the Core of the application
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does not provide any startup functionality relating to web objects
|
||||
/// </remarks>
|
||||
public class CoreBootManager : IBootManager
|
||||
{
|
||||
private ProfilingLogger _profilingLogger;
|
||||
private DisposableTimer _timer;
|
||||
private bool _isInitialized = false;
|
||||
private bool _isStarted = false;
|
||||
private bool _isComplete = false;
|
||||
private readonly IServiceProvider _serviceProvider = new ActivatorServiceProvider();
|
||||
/// A bootstrapper for the Umbraco application which initializes all objects for the Core of the application
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does not provide any startup functionality relating to web objects
|
||||
/// </remarks>
|
||||
public class CoreBootManager : IBootManager
|
||||
{
|
||||
|
||||
private DisposableTimer _timer;
|
||||
private bool _isInitialized = false;
|
||||
private bool _isStarted = false;
|
||||
private bool _isComplete = false;
|
||||
private readonly UmbracoApplicationBase _umbracoApplication;
|
||||
protected ApplicationContext ApplicationContext { get; set; }
|
||||
protected ApplicationContext ApplicationContext { get; set; }
|
||||
protected CacheHelper ApplicationCache { get; set; }
|
||||
protected PluginManager PluginManager { get; private set; }
|
||||
|
||||
protected UmbracoApplicationBase UmbracoApplication
|
||||
{
|
||||
get { return _umbracoApplication; }
|
||||
}
|
||||
protected UmbracoApplicationBase UmbracoApplication
|
||||
{
|
||||
get { return _umbracoApplication; }
|
||||
}
|
||||
|
||||
protected IServiceProvider ServiceProvider
|
||||
{
|
||||
get { return _serviceProvider; }
|
||||
}
|
||||
|
||||
public CoreBootManager(UmbracoApplicationBase umbracoApplication)
|
||||
{
|
||||
public CoreBootManager(UmbracoApplicationBase umbracoApplication)
|
||||
{
|
||||
if (umbracoApplication == null) throw new ArgumentNullException("umbracoApplication");
|
||||
_umbracoApplication = umbracoApplication;
|
||||
}
|
||||
|
||||
public virtual IBootManager Initialize()
|
||||
{
|
||||
if (_isInitialized)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
public virtual IBootManager Initialize()
|
||||
{
|
||||
if (_isInitialized)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
|
||||
InitializeLoggerResolver();
|
||||
InitializeProfilerResolver();
|
||||
InitializeProfilerResolver();
|
||||
|
||||
_profilingLogger = new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler);
|
||||
|
||||
_timer = _profilingLogger.TraceDuration<CoreBootManager>("Umbraco application starting", "Umbraco application startup complete");
|
||||
|
||||
CreateApplicationCache();
|
||||
|
||||
//create and set the plugin manager (I'd much prefer to not use this singleton anymore but many things are using it unfortunately and
|
||||
// the way that it is setup, there must only ever be one per app so without IoC it would be hard to make this not a singleton)
|
||||
PluginManager = new PluginManager(ServiceProvider, ApplicationCache.RuntimeCache, _profilingLogger);
|
||||
PluginManager.Current = PluginManager;
|
||||
_timer = DisposableTimer.TraceDuration<CoreBootManager>(
|
||||
string.Format("Umbraco {0} application starting on {1}", UmbracoVersion.Current, NetworkHelper.MachineName),
|
||||
"Umbraco application startup complete");
|
||||
|
||||
CreateApplicationCache();
|
||||
|
||||
//Create the legacy prop-eds mapping
|
||||
LegacyPropertyEditorIdToAliasConverter.CreateMappingsForCoreEditors();
|
||||
LegacyParameterEditorAliasConverter.CreateMappingsForCoreEditors();
|
||||
|
||||
//create database and service contexts for the app context
|
||||
var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, LoggerResolver.Current.Logger);
|
||||
Database.Mapper = new PetaPocoMapper();
|
||||
|
||||
var dbContext = new DatabaseContext(
|
||||
dbFactory,
|
||||
LoggerResolver.Current.Logger,
|
||||
SqlSyntaxProviders.CreateDefault(LoggerResolver.Current.Logger));
|
||||
|
||||
//initialize the DatabaseContext
|
||||
dbContext.Initialize();
|
||||
|
||||
var serviceContext = new ServiceContext(
|
||||
new RepositoryFactory(ApplicationCache, LoggerResolver.Current.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
|
||||
new PetaPocoUnitOfWorkProvider(dbFactory),
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy(),
|
||||
ApplicationCache,
|
||||
LoggerResolver.Current.Logger);
|
||||
//create database and service contexts for the app context
|
||||
var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName);
|
||||
Database.Mapper = new PetaPocoMapper();
|
||||
var dbContext = new DatabaseContext(dbFactory);
|
||||
var serviceContext = new ServiceContext(
|
||||
new PetaPocoUnitOfWorkProvider(dbFactory),
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy(),
|
||||
ApplicationCache);
|
||||
|
||||
CreateApplicationContext(dbContext, serviceContext);
|
||||
|
||||
InitializeApplicationEventsResolver();
|
||||
|
||||
InitializeResolvers();
|
||||
InitializeResolvers();
|
||||
|
||||
|
||||
//initialize the DatabaseContext
|
||||
dbContext.Initialize();
|
||||
|
||||
InitializeModelMappers();
|
||||
|
||||
//now we need to call the initialize methods
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext));
|
||||
using (DisposableTimer.DebugDuration<CoreBootManager>(
|
||||
() => string.Format("Executing {0} IApplicationEventHandler.OnApplicationInitialized", ApplicationEventsResolver.Current.ApplicationEventHandlers.Count()),
|
||||
() => "Finished executing IApplicationEventHandler.OnApplicationInitialized"))
|
||||
{
|
||||
//now we need to call the initialize methods
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<CoreBootManager>("An error occurred running OnApplicationInitialized for handler " + x.GetType(), ex);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
_isInitialized = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and assigns the application context singleton
|
||||
@@ -136,7 +132,7 @@ namespace Umbraco.Core
|
||||
protected virtual void CreateApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
|
||||
{
|
||||
//create the ApplicationContext
|
||||
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext, ApplicationCache, _profilingLogger);
|
||||
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext, ApplicationCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -147,7 +143,7 @@ namespace Umbraco.Core
|
||||
var cacheHelper = new CacheHelper(
|
||||
new ObjectCacheRuntimeCacheProvider(),
|
||||
new StaticCacheProvider(),
|
||||
//we have no request based cache when not running in web-based context
|
||||
//we have no request based cache when not running in web-based context
|
||||
new NullCacheProvider());
|
||||
|
||||
ApplicationCache = cacheHelper;
|
||||
@@ -171,31 +167,18 @@ namespace Umbraco.Core
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special method to initialize the LoggerResolver
|
||||
/// </summary>
|
||||
protected virtual void InitializeLoggerResolver()
|
||||
{
|
||||
LoggerResolver.Current = new LoggerResolver(Logger.CreateWithDefaultLog4NetConfiguration())
|
||||
{
|
||||
//This is another special resolver that needs to be resolvable before resolution is frozen
|
||||
//since it is used for profiling the application startup
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special method to initialize the ProfilerResolver
|
||||
/// </summary>
|
||||
protected virtual void InitializeProfilerResolver()
|
||||
{
|
||||
//By default we'll initialize the Log profiler (in the web project, we'll override with the web profiler)
|
||||
ProfilerResolver.Current = new ProfilerResolver(new LogProfiler(LoggerResolver.Current.Logger))
|
||||
{
|
||||
//This is another special resolver that needs to be resolvable before resolution is frozen
|
||||
//since it is used for profiling the application startup
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
ProfilerResolver.Current = new ProfilerResolver(new LogProfiler())
|
||||
{
|
||||
//This is another special resolver that needs to be resolvable before resolution is frozen
|
||||
//since it is used for profiling the application startup
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -210,9 +193,7 @@ namespace Umbraco.Core
|
||||
//ApplicationStartupHandler.RegisterHandlers();
|
||||
//... and set the special flag to let us resolve before frozen resolution
|
||||
ApplicationEventsResolver.Current = new ApplicationEventsResolver(
|
||||
ServiceProvider,
|
||||
LoggerResolver.Current.Logger,
|
||||
PluginManager.ResolveApplicationStartupHandlers())
|
||||
PluginManager.Current.ResolveApplicationStartupHandlers())
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
@@ -229,46 +210,81 @@ namespace Umbraco.Core
|
||||
Umbraco.Core.IO.IOHelper.SetRootDirectory(rootPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires after initialization and calls the callback to allow for customizations to occur &
|
||||
/// <summary>
|
||||
/// Fires after initialization and calls the callback to allow for customizations to occur &
|
||||
/// Ensure that the OnApplicationStarting methods of the IApplicationEvents are called
|
||||
/// </summary>
|
||||
/// <param name="afterStartup"></param>
|
||||
/// <returns></returns>
|
||||
public virtual IBootManager Startup(Action<ApplicationContext> afterStartup)
|
||||
{
|
||||
if (_isStarted)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
/// </summary>
|
||||
/// <param name="afterStartup"></param>
|
||||
/// <returns></returns>
|
||||
public virtual IBootManager Startup(Action<ApplicationContext> afterStartup)
|
||||
{
|
||||
if (_isStarted)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationStarting(UmbracoApplication, ApplicationContext));
|
||||
using (DisposableTimer.DebugDuration<CoreBootManager>(
|
||||
() => string.Format("Executing {0} IApplicationEventHandler.OnApplicationStarting", ApplicationEventsResolver.Current.ApplicationEventHandlers.Count()),
|
||||
() => "Finished executing IApplicationEventHandler.OnApplicationStarting"))
|
||||
{
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<CoreBootManager>("An error occurred running OnApplicationStarting for handler " + x.GetType(), ex);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (afterStartup != null)
|
||||
if (afterStartup != null)
|
||||
{
|
||||
afterStartup(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
_isStarted = true;
|
||||
_isStarted = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires after startup and calls the callback once customizations are locked
|
||||
/// </summary>
|
||||
/// <param name="afterComplete"></param>
|
||||
/// <returns></returns>
|
||||
public virtual IBootManager Complete(Action<ApplicationContext> afterComplete)
|
||||
{
|
||||
if (_isComplete)
|
||||
throw new InvalidOperationException("The boot manager has already been completed");
|
||||
/// <summary>
|
||||
/// Fires after startup and calls the callback once customizations are locked
|
||||
/// </summary>
|
||||
/// <param name="afterComplete"></param>
|
||||
/// <returns></returns>
|
||||
public virtual IBootManager Complete(Action<ApplicationContext> afterComplete)
|
||||
{
|
||||
if (_isComplete)
|
||||
throw new InvalidOperationException("The boot manager has already been completed");
|
||||
|
||||
FreezeResolution();
|
||||
FreezeResolution();
|
||||
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationStarted(UmbracoApplication, ApplicationContext));
|
||||
//Here we need to make sure the db can be connected to
|
||||
EnsureDatabaseConnection();
|
||||
|
||||
using (DisposableTimer.DebugDuration<CoreBootManager>(
|
||||
() => string.Format("Executing {0} IApplicationEventHandler.OnApplicationStarted", ApplicationEventsResolver.Current.ApplicationEventHandlers.Count()),
|
||||
() => "Finished executing IApplicationEventHandler.OnApplicationStarted"))
|
||||
{
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<CoreBootManager>("An error occurred running OnApplicationStarted for handler " + x.GetType(), ex);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Now, startup all of our legacy startup handler
|
||||
ApplicationEventsResolver.Current.InstantiateLegacyStartupHandlers();
|
||||
@@ -278,14 +294,40 @@ namespace Umbraco.Core
|
||||
afterComplete(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
_isComplete = true;
|
||||
_isComplete = true;
|
||||
|
||||
// we're ready to serve content!
|
||||
ApplicationContext.IsReady = true;
|
||||
|
||||
//stop the timer and log the output
|
||||
_timer.Dispose();
|
||||
return this;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We cannot continue if the db cannot be connected to
|
||||
/// </summary>
|
||||
private void EnsureDatabaseConnection()
|
||||
{
|
||||
if (ApplicationContext.IsConfigured == false) return;
|
||||
if (ApplicationContext.DatabaseContext.IsDatabaseConfigured == false) return;
|
||||
|
||||
var currentTry = 0;
|
||||
while (currentTry < 5)
|
||||
{
|
||||
if (ApplicationContext.DatabaseContext.CanConnect)
|
||||
break;
|
||||
|
||||
//wait and retry
|
||||
Thread.Sleep(1000);
|
||||
currentTry++;
|
||||
}
|
||||
|
||||
if (currentTry == 5)
|
||||
{
|
||||
throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but the Umbraco cannot connect to the database.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -295,22 +337,21 @@ namespace Umbraco.Core
|
||||
{
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the resolvers
|
||||
/// </summary>
|
||||
protected virtual void InitializeResolvers()
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Create the resolvers
|
||||
/// </summary>
|
||||
protected virtual void InitializeResolvers()
|
||||
{
|
||||
var builder = new ManifestBuilder(
|
||||
ApplicationCache.RuntimeCache,
|
||||
new ManifestParser(new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")), ApplicationCache.RuntimeCache));
|
||||
|
||||
PropertyEditorResolver.Current = new PropertyEditorResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolvePropertyEditors(), builder);
|
||||
ParameterEditorResolver.Current = new ParameterEditorResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveParameterEditors(), builder);
|
||||
PropertyEditorResolver.Current = new PropertyEditorResolver(() => PluginManager.Current.ResolvePropertyEditors(), builder);
|
||||
ParameterEditorResolver.Current = new ParameterEditorResolver(() => PluginManager.Current.ResolveParameterEditors(), builder);
|
||||
|
||||
//setup the validators resolver with our predefined validators
|
||||
ValidatorsResolver.Current = new ValidatorsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger, new[]
|
||||
ValidatorsResolver.Current = new ValidatorsResolver(new[]
|
||||
{
|
||||
new Lazy<Type>(() => typeof (RequiredManifestValueValidator)),
|
||||
new Lazy<Type>(() => typeof (RegexValidator)),
|
||||
@@ -321,69 +362,63 @@ namespace Umbraco.Core
|
||||
|
||||
//by default we'll use the standard configuration based sync
|
||||
ServerRegistrarResolver.Current = new ServerRegistrarResolver(
|
||||
new ConfigServerRegistrar());
|
||||
new ConfigServerRegistrar());
|
||||
|
||||
//by default (outside of the web) we'll use the default server messenger without
|
||||
//supplying a username/password, this will automatically disable distributed calls
|
||||
// .. we'll override this in the WebBootManager
|
||||
ServerMessengerResolver.Current = new ServerMessengerResolver(
|
||||
new WebServiceServerMessenger());
|
||||
new DefaultServerMessenger());
|
||||
|
||||
MappingResolver.Current = new MappingResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveAssignedMapperTypes());
|
||||
() => PluginManager.Current.ResolveAssignedMapperTypes());
|
||||
|
||||
|
||||
RepositoryResolver.Current = new RepositoryResolver(
|
||||
new RepositoryFactory(ApplicationCache));
|
||||
|
||||
//RepositoryResolver.Current = new RepositoryResolver(
|
||||
// new RepositoryFactory(ApplicationCache));
|
||||
SqlSyntaxProvidersResolver.Current = new SqlSyntaxProvidersResolver(
|
||||
new[] { typeof(MySqlSyntaxProvider), typeof(SqlCeSyntaxProvider), typeof(SqlServerSyntaxProvider) })
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
|
||||
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveCacheRefreshers());
|
||||
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
|
||||
() => PluginManager.Current.ResolveCacheRefreshers());
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveDataTypes());
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveMacroRenderings());
|
||||
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
|
||||
() => PluginManager.Current.ResolveMacroRenderings());
|
||||
|
||||
PackageActionsResolver.Current = new PackageActionsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolvePackageActions());
|
||||
PackageActionsResolver.Current = new PackageActionsResolver(
|
||||
() => PluginManager.Current.ResolvePackageActions());
|
||||
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveActions());
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
() => PluginManager.Current.ResolveActions());
|
||||
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(
|
||||
LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveTypes<IMigration>());
|
||||
() => PluginManager.Current.ResolveTypes<IMigration>());
|
||||
|
||||
// todo: remove once we drop IPropertyEditorValueConverter support.
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
PluginManager.ResolvePropertyEditorValueConverters());
|
||||
PluginManager.Current.ResolvePropertyEditorValueConverters());
|
||||
|
||||
// need to filter out the ones we dont want!!
|
||||
PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
PluginManager.ResolveTypes<IPropertyValueConverter>());
|
||||
// need to filter out the ones we dont want!!
|
||||
PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(
|
||||
PluginManager.Current.ResolveTypes<IPropertyValueConverter>());
|
||||
|
||||
// use the new DefaultShortStringHelper
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
//new LegacyShortStringHelper());
|
||||
new DefaultShortStringHelper().WithDefaultConfig());
|
||||
|
||||
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
typeof(DefaultUrlSegmentProvider));
|
||||
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
|
||||
typeof (DefaultUrlSegmentProvider));
|
||||
|
||||
// by default, no factory is activated
|
||||
PublishedContentModelFactoryResolver.Current = new PublishedContentModelFactoryResolver();
|
||||
}
|
||||
}
|
||||
PublishedContentModelFactoryResolver.Current = new PublishedContentModelFactoryResolver();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
@@ -12,14 +11,12 @@ namespace Umbraco.Core
|
||||
[Obsolete("IDataType is obsolete and is no longer used, it will be removed from the codebase in future versions")]
|
||||
internal sealed class DataTypesResolver : LegacyTransientObjectsResolver<DataTypesResolver, IDataType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="dataTypes"></param>
|
||||
internal DataTypesResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> dataTypes)
|
||||
: base(serviceProvider, logger, dataTypes)
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dataTypes"></param>
|
||||
internal DataTypesResolver(Func<IEnumerable<Type>> dataTypes)
|
||||
: base(dataTypes)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -25,63 +25,17 @@ namespace Umbraco.Core
|
||||
public class DatabaseContext
|
||||
{
|
||||
private readonly IDatabaseFactory _factory;
|
||||
private readonly ILogger _logger;
|
||||
private readonly SqlSyntaxProviders _syntaxProviders;
|
||||
private bool _configured;
|
||||
private bool _canConnect;
|
||||
private volatile bool _connectCheck = false;
|
||||
private readonly object _locker = new object();
|
||||
private string _connectionString;
|
||||
private string _providerName;
|
||||
private DatabaseSchemaResult _result;
|
||||
|
||||
[Obsolete("Use the constructor specifying all dependencies instead")]
|
||||
public DatabaseContext(IDatabaseFactory factory)
|
||||
: this(factory, LoggerResolver.Current.Logger, new SqlSyntaxProviders(new ISqlSyntaxProvider[]
|
||||
{
|
||||
new MySqlSyntaxProvider(LoggerResolver.Current.Logger),
|
||||
new SqlCeSyntaxProvider(),
|
||||
new SqlServerSyntaxProvider()
|
||||
}))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="syntaxProviders"></param>
|
||||
public DatabaseContext(IDatabaseFactory factory, ILogger logger, SqlSyntaxProviders syntaxProviders)
|
||||
{
|
||||
if (factory == null) throw new ArgumentNullException("factory");
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (syntaxProviders == null) throw new ArgumentNullException("syntaxProviders");
|
||||
|
||||
_factory = factory;
|
||||
_logger = logger;
|
||||
_syntaxProviders = syntaxProviders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a configured DatabaseContext
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="sqlSyntax"></param>
|
||||
/// <param name="providerName"></param>
|
||||
public DatabaseContext(IDatabaseFactory factory, ILogger logger, ISqlSyntaxProvider sqlSyntax, string providerName)
|
||||
{
|
||||
_providerName = providerName;
|
||||
SqlSyntax = sqlSyntax;
|
||||
SqlSyntaxContext.SqlSyntaxProvider = SqlSyntax;
|
||||
_factory = factory;
|
||||
_logger = logger;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public ISqlSyntaxProvider SqlSyntax { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Database"/> object for doing CRUD operations
|
||||
/// against custom tables that resides in the Umbraco database.
|
||||
@@ -111,21 +65,9 @@ namespace Umbraco.Core
|
||||
get
|
||||
{
|
||||
if (IsDatabaseConfigured == false) return false;
|
||||
|
||||
//double check lock so that it is only checked once and is fast
|
||||
if (_connectCheck == false)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (_canConnect == false)
|
||||
{
|
||||
_canConnect = DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DatabaseProvider);
|
||||
_connectCheck = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _canConnect;
|
||||
var canConnect = DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DatabaseProvider);
|
||||
LogHelper.Info<DatabaseContext>("CanConnect = " + canConnect);
|
||||
return canConnect;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +310,7 @@ namespace Umbraco.Core
|
||||
|
||||
xml.Save(fileName, SaveOptions.DisableFormatting);
|
||||
|
||||
_logger.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
|
||||
LogHelper.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -442,23 +384,12 @@ namespace Umbraco.Core
|
||||
|
||||
internal void Initialize(string providerName)
|
||||
{
|
||||
//only configure once!
|
||||
if (_configured == true) return;
|
||||
|
||||
_providerName = providerName;
|
||||
|
||||
try
|
||||
{
|
||||
if (_syntaxProviders != null)
|
||||
{
|
||||
SqlSyntax = _syntaxProviders.GetByProviderNameOrDefault(providerName);
|
||||
}
|
||||
else if (SqlSyntax == null)
|
||||
{
|
||||
throw new InvalidOperationException("No " + typeof(ISqlSyntaxProvider) + " specified or no " + typeof(SqlSyntaxProviders) + " instance specified");
|
||||
}
|
||||
|
||||
SqlSyntaxContext.SqlSyntaxProvider = SqlSyntax;
|
||||
SqlSyntaxContext.SqlSyntaxProvider =
|
||||
SqlSyntaxProvidersResolver.Current.GetByProviderNameOrDefault(providerName);
|
||||
|
||||
_configured = true;
|
||||
}
|
||||
@@ -466,8 +397,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
_configured = false;
|
||||
|
||||
_logger.Info<DatabaseContext>("Initialization of the DatabaseContext failed with following error: " + e.Message);
|
||||
_logger.Info<DatabaseContext>(e.StackTrace);
|
||||
LogHelper.Info<DatabaseContext>("Initialization of the DatabaseContext failed with following error: " + e.Message);
|
||||
LogHelper.Info<DatabaseContext>(e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,8 +413,8 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
private void DetermineSqlServerVersion()
|
||||
{
|
||||
|
||||
var sqlServerSyntax = SqlSyntax as SqlServerSyntaxProvider;
|
||||
|
||||
var sqlServerSyntax = SqlSyntaxContext.SqlSyntaxProvider as SqlServerSyntaxProvider;
|
||||
if (sqlServerSyntax != null)
|
||||
{
|
||||
//this will not execute now, it is lazy so will only execute when we need to actually know
|
||||
@@ -534,8 +465,8 @@ namespace Umbraco.Core
|
||||
throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration");
|
||||
}
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName, _logger);
|
||||
var dbSchema = new DatabaseSchemaCreation(database, _logger, SqlSyntax);
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
var dbSchema = new DatabaseSchemaCreation(database);
|
||||
_result = dbSchema.ValidateSchema();
|
||||
}
|
||||
return _result;
|
||||
@@ -551,17 +482,17 @@ namespace Umbraco.Core
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
_logger.Info<DatabaseContext>("Database configuration status: Started");
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: Started");
|
||||
|
||||
string message;
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName, _logger);
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
|
||||
// If MySQL, we're going to ensure that database calls are maintaining proper casing as to remove the necessity for checks
|
||||
// for case insensitive queries. In an ideal situation (which is what we're striving for), all calls would be case sensitive.
|
||||
|
||||
/*
|
||||
var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database);
|
||||
var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
if (supportsCaseInsensitiveQueries == false)
|
||||
{
|
||||
message = "<p> </p><p>The database you're trying to use does not support case insensitive queries. <br />We currently do not support these types of databases.</p>" +
|
||||
@@ -587,12 +518,12 @@ namespace Umbraco.Core
|
||||
message = message + "<p>Installation completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
_logger.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
|
||||
//we need to do an upgrade so return a new status message and it will need to be done during the next step
|
||||
_logger.Info<DatabaseContext>("Database requires upgrade");
|
||||
LogHelper.Info<DatabaseContext>("Database requires upgrade");
|
||||
message = "<p>Upgrading database, this may take some time...</p>";
|
||||
return new Result
|
||||
{
|
||||
@@ -623,10 +554,10 @@ namespace Umbraco.Core
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
_logger.Info<DatabaseContext>("Database upgrade started");
|
||||
LogHelper.Info<DatabaseContext>("Database upgrade started");
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName, _logger);
|
||||
//var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database);
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
//var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
|
||||
var message = GetResultMessageForMySql();
|
||||
|
||||
@@ -639,13 +570,13 @@ namespace Umbraco.Core
|
||||
? installedVersion
|
||||
: new Version(GlobalSettings.ConfigurationStatus);
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
var runner = new MigrationRunner(_logger, currentVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
|
||||
var runner = new MigrationRunner(currentVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
|
||||
var upgraded = runner.Execute(database, true);
|
||||
message = message + "<p>Upgrade completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
|
||||
_logger.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
@@ -657,7 +588,7 @@ namespace Umbraco.Core
|
||||
|
||||
private string GetResultMessageForMySql()
|
||||
{
|
||||
if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider))
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
@@ -683,7 +614,7 @@ namespace Umbraco.Core
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider))
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
@@ -720,11 +651,11 @@ namespace Umbraco.Core
|
||||
|
||||
private Result HandleInstallException(Exception ex)
|
||||
{
|
||||
_logger.Error<DatabaseContext>("Database configuration failed", ex);
|
||||
LogHelper.Error<DatabaseContext>("Database configuration failed", ex);
|
||||
|
||||
if (_result != null)
|
||||
{
|
||||
_logger.Info<DatabaseContext>("The database schema validation produced the following summary: \n" + _result.GetSummary());
|
||||
LogHelper.Info<DatabaseContext>("The database schema validation produced the following summary: \n" + _result.GetSummary());
|
||||
}
|
||||
|
||||
return new Result
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Dictionary
|
||||
@@ -14,22 +12,15 @@ namespace Umbraco.Core.Dictionary
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use SetDictionaryFactory instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
/// <summary>
|
||||
/// Can be used by developers at runtime to set their ICultureDictionaryFactory at app startup
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
public void SetContentStore(ICultureDictionaryFactory factory)
|
||||
{
|
||||
Value = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used by developers at runtime to set their ICultureDictionaryFactory at app startup
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
public void SetDictionaryFactory(ICultureDictionaryFactory factory)
|
||||
{
|
||||
Value = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ICultureDictionaryFactory
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Umbraco.Core.Dictionary
|
||||
@@ -20,12 +19,5 @@ namespace Umbraco.Core.Dictionary
|
||||
/// Returns the current culture
|
||||
/// </summary>
|
||||
CultureInfo Culture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the child dictionary entries for a given key
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
IDictionary<string, string> GetChildren(string key);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -134,6 +135,20 @@ namespace Umbraco.Core
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a dictionary to a FormCollection
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <returns></returns>
|
||||
public static FormCollection ToFormCollection(this IDictionary<string, object> d)
|
||||
{
|
||||
var n = new FormCollection();
|
||||
foreach (var i in d)
|
||||
{
|
||||
n.Add(i.Key, Convert.ToString(i.Value));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges all key/values from the sources dictionaries into the destination dictionary
|
||||
|
||||
@@ -4,69 +4,58 @@ using System.Threading;
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract implementation of logic commonly required to safely handle disposable unmanaged resources.
|
||||
/// Abstract implementation of IDisposable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Can also be used as a pattern for when inheriting is not possible.
|
||||
///
|
||||
/// See also: https://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.110%29.aspx
|
||||
/// See also: https://lostechies.com/chrispatterson/2012/11/29/idisposable-done-right/
|
||||
///
|
||||
/// Note: if an object's ctor throws, it will never be disposed, and so if that ctor
|
||||
/// has allocated disposable objects, it should take care of disposing them.
|
||||
/// </remarks>
|
||||
public abstract class DisposableObject : IDisposable
|
||||
{
|
||||
private bool _disposed;
|
||||
private readonly ReaderWriterLockSlim _disposalLocker = new ReaderWriterLockSlim();
|
||||
private readonly object _locko = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is disposed.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsDisposed
|
||||
{
|
||||
get { return _disposed; }
|
||||
}
|
||||
// gets a value indicating whether this instance is disposed.
|
||||
// for internal tests only (not thread safe)
|
||||
//TODO make this internal + rename "Disposed" when we can break compatibility
|
||||
public bool IsDisposed { get { return _disposed; } }
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
// implements IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
// Use SupressFinalize in case a subclass of this type implements a finalizer.
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// finalizer
|
||||
~DisposableObject()
|
||||
{
|
||||
// Run dispose but let the class know it was due to the finalizer running.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
//TODO make this private, non-virtual when we can break compatibility
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
// Only operate if we haven't already disposed
|
||||
if (IsDisposed || !disposing) return;
|
||||
lock (_locko)
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
using (new WriteLock(_disposalLocker))
|
||||
{
|
||||
// Check again now we're inside the lock
|
||||
if (IsDisposed) return;
|
||||
DisposeUnmanagedResources();
|
||||
|
||||
// Call to actually release resources. This method is only
|
||||
// kept separate so that the entire disposal logic can be used as a VS snippet
|
||||
DisposeResources();
|
||||
|
||||
// Indicate that the instance has been disposed.
|
||||
_disposed = true;
|
||||
}
|
||||
if (disposing)
|
||||
DisposeResources();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObject"/> which handles common required locking logic.
|
||||
/// </summary>
|
||||
protected abstract void DisposeResources();
|
||||
|
||||
protected virtual void DisposeUnmanagedResources()
|
||||
{
|
||||
|
||||
}
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -10,65 +9,32 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Starts the timer and invokes a callback upon disposal. Provides a simple way of timing an operation by wrapping it in a <code>using</code> (C#) statement.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
///
|
||||
/// using (DisposableTimer.TraceDuration{MyType}("starting", "finished"))
|
||||
/// {
|
||||
/// Thread.Sleep(567);
|
||||
/// }
|
||||
///
|
||||
/// Console.WriteLine("Testing Stopwatchdisposable, should be 567:");
|
||||
/// using (var timer = new DisposableTimer(result => Console.WriteLine("Took {0}ms", result)))
|
||||
/// {
|
||||
/// Thread.Sleep(567);
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class DisposableTimer : DisposableObject
|
||||
{
|
||||
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
|
||||
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
|
||||
private readonly Action<long> _callback;
|
||||
|
||||
internal enum LogType
|
||||
{
|
||||
Debug, Info
|
||||
}
|
||||
protected DisposableTimer(Action<long> callback)
|
||||
{
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
internal DisposableTimer(ILogger logger, LogType logType, IProfiler profiler, Type loggerType, string startMessage, string endMessage)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (loggerType == null) throw new ArgumentNullException("loggerType");
|
||||
|
||||
_callback = x =>
|
||||
{
|
||||
if (profiler != null)
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
}
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Debug:
|
||||
logger.Debug(loggerType, () => endMessage + " (took " + x + "ms)");
|
||||
break;
|
||||
case LogType.Info:
|
||||
logger.Info(loggerType, () => endMessage + " (took " + x + "ms)");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("logType");
|
||||
}
|
||||
|
||||
};
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Debug:
|
||||
logger.Debug(loggerType, startMessage);
|
||||
break;
|
||||
case LogType.Info:
|
||||
logger.Info(loggerType, startMessage);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("logType");
|
||||
}
|
||||
|
||||
if (profiler != null)
|
||||
{
|
||||
profiler.Step(loggerType, startMessage);
|
||||
}
|
||||
}
|
||||
|
||||
protected internal DisposableTimer(Action<long> callback)
|
||||
{
|
||||
if (callback == null) throw new ArgumentNullException("callback");
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
public Stopwatch Stopwatch
|
||||
public Stopwatch Stopwatch
|
||||
{
|
||||
get { return _stopwatch; }
|
||||
}
|
||||
@@ -85,25 +51,25 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
#region TraceDuration
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the other methods that specify strings instead of Func")]
|
||||
public static DisposableTimer TraceDuration<T>(Func<string> startMessage, Func<string> completeMessage)
|
||||
{
|
||||
return TraceDuration(typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the other methods that specify strings instead of Func")]
|
||||
public static DisposableTimer TraceDuration(Type loggerType, Func<string> startMessage, Func<string> completeMessage)
|
||||
{
|
||||
return new DisposableTimer(
|
||||
LoggerResolver.Current.Logger,
|
||||
LogType.Info,
|
||||
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
|
||||
loggerType,
|
||||
startMessage(),
|
||||
completeMessage());
|
||||
var startMsg = startMessage();
|
||||
LogHelper.Info(loggerType, startMsg);
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("Start: " + startMsg);
|
||||
var profiler = ActivateProfiler(loggerType, startMsg);
|
||||
return new DisposableTimer(x =>
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
LogHelper.Info(loggerType, () => completeMessage() + " (took " + x + "ms)");
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("End: " + startMsg);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -113,19 +79,11 @@ namespace Umbraco.Core
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer TraceDuration<T>(string startMessage, string completeMessage)
|
||||
{
|
||||
return TraceDuration(typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a start and end log entry as Info and tracks how long it takes until disposed.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="startMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer TraceDuration<T>(string startMessage)
|
||||
{
|
||||
return TraceDuration(typeof(T), startMessage, "Complete");
|
||||
@@ -138,18 +96,20 @@ namespace Umbraco.Core
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(
|
||||
LoggerResolver.Current.Logger,
|
||||
LogType.Info,
|
||||
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
|
||||
loggerType,
|
||||
startMessage,
|
||||
completeMessage);
|
||||
}
|
||||
|
||||
LogHelper.Info(loggerType, startMessage);
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("Start: " + startMessage);
|
||||
var profiler = ActivateProfiler(loggerType, startMessage);
|
||||
return new DisposableTimer(x =>
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
LogHelper.Info(loggerType, () => completeMessage + " (took " + x + "ms)");
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("End: " + startMessage);
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DebugDuration
|
||||
@@ -160,26 +120,23 @@ namespace Umbraco.Core
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer DebugDuration<T>(string startMessage, string completeMessage)
|
||||
{
|
||||
return DebugDuration(typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
public static DisposableTimer DebugDuration<T>(string startMessage)
|
||||
{
|
||||
return DebugDuration(typeof(T), startMessage, "Complete");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer DebugDuration<T>(string startMessage)
|
||||
{
|
||||
return DebugDuration(typeof(T), startMessage, "Complete");
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the other methods that specify strings instead of Func")]
|
||||
public static DisposableTimer DebugDuration<T>(Func<string> startMessage, Func<string> completeMessage)
|
||||
{
|
||||
return DebugDuration(typeof(T), startMessage, completeMessage);
|
||||
@@ -192,29 +149,42 @@ namespace Umbraco.Core
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(
|
||||
LoggerResolver.Current.Logger,
|
||||
LogType.Debug,
|
||||
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
|
||||
loggerType,
|
||||
startMessage,
|
||||
completeMessage);
|
||||
LogHelper.Debug(loggerType, startMessage);
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("Start: " + startMessage);
|
||||
var profiler = ActivateProfiler(loggerType, startMessage);
|
||||
return new DisposableTimer(x =>
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
LogHelper.Debug(loggerType, () => completeMessage + " (took " + x + "ms)");
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("End: " + startMessage);
|
||||
});
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the other methods that specify strings instead of Func")]
|
||||
/// <summary>
|
||||
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
|
||||
/// </summary>
|
||||
/// <param name="loggerType"></param>
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
public static DisposableTimer DebugDuration(Type loggerType, Func<string> startMessage, Func<string> completeMessage)
|
||||
{
|
||||
return new DisposableTimer(
|
||||
LoggerResolver.Current.Logger,
|
||||
LogType.Debug,
|
||||
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
|
||||
loggerType,
|
||||
startMessage(),
|
||||
completeMessage());
|
||||
var msg = startMessage();
|
||||
LogHelper.Debug(loggerType, msg);
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("Start: " + startMessage);
|
||||
var profiler = ActivateProfiler(loggerType, msg);
|
||||
return new DisposableTimer(x =>
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
LogHelper.Debug(loggerType, () => completeMessage() + " (took " + x + "ms)");
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("End: " + startMessage);
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -226,5 +196,18 @@ namespace Umbraco.Core
|
||||
_callback.Invoke(Stopwatch.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
private static IDisposable ActivateProfiler(Type loggerType, string profileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ProfilerResolver.Current.Profiler.Step(loggerType, profileName);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
//swallow this exception, it will occur if the ProfilerResolver is not initialized... generally only in
|
||||
// unit tests.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception that is thrown if the umbraco application cannnot boot
|
||||
/// </summary>
|
||||
public class UmbracoStartupFailedException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Exception"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error. </param>
|
||||
public UmbracoStartupFailedException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,11 +56,11 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.ResolveUrlsFromTextString)
|
||||
{
|
||||
using (DisposableTimer.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete"))
|
||||
using (var timer = DisposableTimer.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete"))
|
||||
{
|
||||
// find all relative urls (ie. urls that contain ~)
|
||||
var tags = ResolveUrlPattern.Matches(text);
|
||||
|
||||
LogHelper.Debug(typeof(IOHelper), "After regex: " + timer.Stopwatch.ElapsedMilliseconds + " matched: " + tags.Count);
|
||||
foreach (Match tag in tags)
|
||||
{
|
||||
string url = "";
|
||||
|
||||
@@ -1,450 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
internal class MasterPageHelper
|
||||
{
|
||||
private readonly IFileSystem _masterPageFileSystem;
|
||||
internal static readonly string DefaultMasterTemplate = SystemDirectories.Umbraco + "/masterpages/default.master";
|
||||
//private static readonly char[] NewLineChars = Environment.NewLine.ToCharArray();
|
||||
|
||||
public MasterPageHelper(IFileSystem masterPageFileSystem)
|
||||
{
|
||||
if (masterPageFileSystem == null) throw new ArgumentNullException("masterPageFileSystem");
|
||||
_masterPageFileSystem = masterPageFileSystem;
|
||||
}
|
||||
|
||||
public bool MasterPageExists(ITemplate t)
|
||||
{
|
||||
return _masterPageFileSystem.FileExists(GetFilePath(t));
|
||||
}
|
||||
|
||||
[Obsolete("This is only used for legacy purposes and will be removed in future versions")]
|
||||
internal string GetPhysicalFilePath(ITemplate t)
|
||||
{
|
||||
return _masterPageFileSystem.GetFullPath(GetFilePath(t.Alias));
|
||||
}
|
||||
|
||||
private string GetFilePath(ITemplate t)
|
||||
{
|
||||
return GetFilePath(t.Alias);
|
||||
}
|
||||
|
||||
private string GetFilePath(string alias)
|
||||
{
|
||||
return alias + ".master";
|
||||
}
|
||||
|
||||
public string CreateMasterPage(ITemplate t, ITemplateRepository templateRepo, bool overWrite = false)
|
||||
{
|
||||
string masterpageContent = "";
|
||||
|
||||
var filePath = GetFilePath(t);
|
||||
if (_masterPageFileSystem.FileExists(filePath) == false || overWrite)
|
||||
{
|
||||
masterpageContent = t.Content.IsNullOrWhiteSpace() ? CreateDefaultMasterPageContent(t, templateRepo) : t.Content;
|
||||
|
||||
var data = Encoding.UTF8.GetBytes(masterpageContent);
|
||||
var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
|
||||
|
||||
using (var ms = new MemoryStream(withBom))
|
||||
{
|
||||
_masterPageFileSystem.AddFile(filePath, ms, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var s = _masterPageFileSystem.OpenFile(filePath))
|
||||
using (var tr = new StreamReader(s, Encoding.UTF8))
|
||||
{
|
||||
masterpageContent = tr.ReadToEnd();
|
||||
tr.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return masterpageContent;
|
||||
}
|
||||
|
||||
//internal string GetFileContents(ITemplate t)
|
||||
//{
|
||||
// var masterpageContent = "";
|
||||
// if (_masterPageFileSystem.FileExists(GetFilePath(t)))
|
||||
// {
|
||||
// using (var s = _masterPageFileSystem.OpenFile(GetFilePath(t)))
|
||||
// using (var tr = new StreamReader(s))
|
||||
// {
|
||||
// masterpageContent = tr.ReadToEnd();
|
||||
// tr.Close();
|
||||
// }
|
||||
// }
|
||||
|
||||
// return masterpageContent;
|
||||
//}
|
||||
|
||||
public string UpdateMasterPageFile(ITemplate t, string currentAlias, ITemplateRepository templateRepo)
|
||||
{
|
||||
var template = UpdateMasterPageContent(t, currentAlias);
|
||||
UpdateChildTemplates(t, currentAlias, templateRepo);
|
||||
var filePath = GetFilePath(t);
|
||||
|
||||
var data = Encoding.UTF8.GetBytes(template);
|
||||
var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
|
||||
|
||||
using (var ms = new MemoryStream(withBom))
|
||||
{
|
||||
_masterPageFileSystem.AddFile(filePath, ms, true);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
private string CreateDefaultMasterPageContent(ITemplate template, ITemplateRepository templateRepo)
|
||||
{
|
||||
var design = new StringBuilder();
|
||||
design.Append(GetMasterPageHeader(template) + Environment.NewLine);
|
||||
|
||||
if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
var master = templateRepo.Get(template.MasterTemplateAlias);
|
||||
if (master != null)
|
||||
{
|
||||
foreach (var cpId in GetContentPlaceholderIds(master))
|
||||
{
|
||||
design.Append("<asp:content ContentPlaceHolderId=\"" + cpId + "\" runat=\"server\">" +
|
||||
Environment.NewLine +
|
||||
Environment.NewLine +
|
||||
"</asp:content>" +
|
||||
Environment.NewLine +
|
||||
Environment.NewLine);
|
||||
}
|
||||
|
||||
return design.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
design.Append(GetMasterContentElement(template) + Environment.NewLine);
|
||||
design.Append(template.Content + Environment.NewLine);
|
||||
design.Append("</asp:Content>" + Environment.NewLine);
|
||||
|
||||
return design.ToString();
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetContentPlaceholderIds(ITemplate template)
|
||||
{
|
||||
var retVal = new List<string>();
|
||||
|
||||
var mp = template.Content;
|
||||
var path = "<asp:ContentPlaceHolder+(\\s+[a-zA-Z]+\\s*=\\s*(\"([^\"]*)\"|'([^']*)'))*\\s*/?>";
|
||||
var r = new Regex(path, RegexOptions.IgnoreCase);
|
||||
var m = r.Match(mp);
|
||||
|
||||
while (m.Success)
|
||||
{
|
||||
var cc = m.Groups[3].Captures;
|
||||
retVal.AddRange(cc.Cast<Capture>().Where(c => c.Value != "server").Select(c => c.Value));
|
||||
|
||||
m = m.NextMatch();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private static string UpdateMasterPageContent(ITemplate template, string currentAlias)
|
||||
{
|
||||
var masterPageContent = template.Content;
|
||||
|
||||
if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias)
|
||||
{
|
||||
var masterHeader =
|
||||
masterPageContent.Substring(0, masterPageContent.IndexOf("%>", StringComparison.Ordinal) + 2).Trim(
|
||||
Environment.NewLine.ToCharArray());
|
||||
|
||||
// find the masterpagefile attribute
|
||||
var m = Regex.Matches(masterHeader, "(?<attributeName>\\S*)=\"(?<attributeValue>[^\"]*)\"",
|
||||
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
foreach (Match attributeSet in m)
|
||||
{
|
||||
if (attributeSet.Groups["attributeName"].Value.ToLower() == "masterpagefile")
|
||||
{
|
||||
// validate the masterpagefile
|
||||
var currentMasterPageFile = attributeSet.Groups["attributeValue"].Value;
|
||||
var currentMasterTemplateFile = ParentTemplatePath(template);
|
||||
|
||||
if (currentMasterPageFile != currentMasterTemplateFile)
|
||||
{
|
||||
masterPageContent =
|
||||
masterPageContent.Replace(
|
||||
attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterPageFile + "\"",
|
||||
attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterTemplateFile +
|
||||
"\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return masterPageContent;
|
||||
}
|
||||
|
||||
private void UpdateChildTemplates(ITemplate template, string currentAlias, ITemplateRepository templateRepo)
|
||||
{
|
||||
//if we have a Old Alias if the alias and therefor the masterpage file name has changed...
|
||||
//so before we save the new masterfile, we'll clear the old one, so we don't up with
|
||||
//Unused masterpage files
|
||||
if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias)
|
||||
{
|
||||
//Ensure that child templates have the right master masterpage file name
|
||||
if (template.IsMasterTemplate)
|
||||
{
|
||||
var children = templateRepo.GetChildren(template.Id);
|
||||
foreach (var t in children)
|
||||
UpdateMasterPageFile(t, null, templateRepo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//private void SaveDesignToFile(ITemplate t, string currentAlias, string design)
|
||||
//{
|
||||
// //kill the old file..
|
||||
// if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != t.Alias)
|
||||
// {
|
||||
// var oldFile =
|
||||
// IOHelper.MapPath(SystemDirectories.Masterpages + "/" + currentAlias.Replace(" ", "") + ".master");
|
||||
// if (System.IO.File.Exists(oldFile))
|
||||
// System.IO.File.Delete(oldFile);
|
||||
// }
|
||||
|
||||
// // save the file in UTF-8
|
||||
// System.IO.File.WriteAllText(GetFilePath(t), design, Encoding.UTF8);
|
||||
//}
|
||||
|
||||
//internal static void RemoveMasterPageFile(string alias)
|
||||
//{
|
||||
// if (string.IsNullOrWhiteSpace(alias) == false)
|
||||
// {
|
||||
// string file = IOHelper.MapPath(SystemDirectories.Masterpages + "/" + alias.Replace(" ", "") + ".master");
|
||||
// if (System.IO.File.Exists(file))
|
||||
// System.IO.File.Delete(file);
|
||||
// }
|
||||
//}
|
||||
|
||||
//internal string SaveTemplateToFile(ITemplate template, string currentAlias, ITemplateRepository templateRepo)
|
||||
//{
|
||||
// var masterPageContent = template.Content;
|
||||
// if (IsMasterPageSyntax(masterPageContent) == false)
|
||||
// masterPageContent = ConvertToMasterPageSyntax(template);
|
||||
|
||||
// // Add header to master page if it doesn't exist
|
||||
// if (masterPageContent.TrimStart().StartsWith("<%@") == false)
|
||||
// {
|
||||
// masterPageContent = GetMasterPageHeader(template) + Environment.NewLine + masterPageContent;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // verify that the masterpage attribute is the same as the masterpage
|
||||
// var masterHeader =
|
||||
// masterPageContent.Substring(0, masterPageContent.IndexOf("%>", StringComparison.Ordinal) + 2).Trim(NewLineChars);
|
||||
|
||||
// // find the masterpagefile attribute
|
||||
// var m = Regex.Matches(masterHeader, "(?<attributeName>\\S*)=\"(?<attributeValue>[^\"]*)\"",
|
||||
// RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
// foreach (Match attributeSet in m)
|
||||
// {
|
||||
// if (attributeSet.Groups["attributeName"].Value.ToLower() == "masterpagefile")
|
||||
// {
|
||||
// // validate the masterpagefile
|
||||
// var currentMasterPageFile = attributeSet.Groups["attributeValue"].Value;
|
||||
// var currentMasterTemplateFile = ParentTemplatePath(template);
|
||||
|
||||
// if (currentMasterPageFile != currentMasterTemplateFile)
|
||||
// {
|
||||
// masterPageContent =
|
||||
// masterPageContent.Replace(
|
||||
// attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterPageFile + "\"",
|
||||
// attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterTemplateFile +
|
||||
// "\"");
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// //we have a Old Alias if the alias and therefor the masterpage file name has changed...
|
||||
// //so before we save the new masterfile, we'll clear the old one, so we don't up with
|
||||
// //Unused masterpage files
|
||||
// if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias)
|
||||
// {
|
||||
|
||||
// //Ensure that child templates have the right master masterpage file name
|
||||
// if (template.IsMasterTemplate)
|
||||
// {
|
||||
// var children = templateRepo.GetChildren(template.Id);
|
||||
|
||||
// foreach (var t in children)
|
||||
// UpdateMasterPageFile(t, null, templateRepo);
|
||||
// }
|
||||
|
||||
// //then kill the old file..
|
||||
// var oldFile = GetFilePath(currentAlias);
|
||||
// if (_masterPageFileSystem.FileExists(oldFile))
|
||||
// _masterPageFileSystem.DeleteFile(oldFile);
|
||||
// }
|
||||
|
||||
// // save the file in UTF-8
|
||||
// System.IO.File.WriteAllText(GetFilePath(template), masterPageContent, Encoding.UTF8);
|
||||
|
||||
// return masterPageContent;
|
||||
//}
|
||||
|
||||
//internal static string ConvertToMasterPageSyntax(ITemplate template)
|
||||
//{
|
||||
// string masterPageContent = GetMasterContentElement(template) + Environment.NewLine;
|
||||
|
||||
// masterPageContent += template.Content;
|
||||
|
||||
// // Parse the design for getitems
|
||||
// masterPageContent = EnsureMasterPageSyntax(template.Alias, masterPageContent);
|
||||
|
||||
// // append ending asp:content element
|
||||
// masterPageContent += Environment.NewLine + "</asp:Content>" + Environment.NewLine;
|
||||
|
||||
// return masterPageContent;
|
||||
//}
|
||||
|
||||
public static bool IsMasterPageSyntax(string code)
|
||||
{
|
||||
return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) ||
|
||||
code.InvariantContains("<umbraco:Item") || code.InvariantContains("<asp:") || code.InvariantContains("<umbraco:Macro");
|
||||
}
|
||||
|
||||
private static string GetMasterPageHeader(ITemplate template)
|
||||
{
|
||||
return String.Format("<%@ Master Language=\"C#\" MasterPageFile=\"{0}\" AutoEventWireup=\"true\" %>", ParentTemplatePath(template)) + Environment.NewLine;
|
||||
}
|
||||
|
||||
private static string ParentTemplatePath(ITemplate template)
|
||||
{
|
||||
var masterTemplate = DefaultMasterTemplate;
|
||||
if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
masterTemplate = SystemDirectories.Masterpages + "/" + template.MasterTemplateAlias + ".master";
|
||||
|
||||
return masterTemplate;
|
||||
}
|
||||
|
||||
private static string GetMasterContentElement(ITemplate template)
|
||||
{
|
||||
if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
string masterAlias = template.MasterTemplateAlias;
|
||||
return
|
||||
String.Format("<asp:Content ContentPlaceHolderID=\"{0}ContentPlaceHolder\" runat=\"server\">", masterAlias);
|
||||
}
|
||||
else
|
||||
return
|
||||
String.Format("<asp:Content ContentPlaceHolderID=\"ContentPlaceHolderDefault\" runat=\"server\">");
|
||||
|
||||
}
|
||||
|
||||
//internal static string EnsureMasterPageSyntax(string templateAlias, string masterPageContent)
|
||||
//{
|
||||
// ReplaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", true);
|
||||
// ReplaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", false);
|
||||
|
||||
// // Parse the design for macros
|
||||
// ReplaceElement(ref masterPageContent, "?UMBRACO_MACRO", "umbraco:Macro", true);
|
||||
// ReplaceElement(ref masterPageContent, "?UMBRACO_MACRO", "umbraco:Macro", false);
|
||||
|
||||
// // Parse the design for load childs
|
||||
// masterPageContent = masterPageContent.Replace("<?UMBRACO_TEMPLATE_LOAD_CHILD/>", CreateDefaultPlaceHolder(templateAlias))
|
||||
// .Replace("<?UMBRACO_TEMPLATE_LOAD_CHILD />", CreateDefaultPlaceHolder(templateAlias));
|
||||
// // Parse the design for aspnet forms
|
||||
// GetAspNetMasterPageForm(ref masterPageContent, templateAlias);
|
||||
// masterPageContent = masterPageContent.Replace("</?ASPNET_FORM>", "</form>");
|
||||
// // Parse the design for aspnet heads
|
||||
// masterPageContent = masterPageContent.Replace("</ASPNET_HEAD>", String.Format("<head id=\"{0}Head\" runat=\"server\">", templateAlias.Replace(" ", "")));
|
||||
// masterPageContent = masterPageContent.Replace("</?ASPNET_HEAD>", "</head>");
|
||||
// return masterPageContent;
|
||||
//}
|
||||
|
||||
|
||||
//private static void GetAspNetMasterPageForm(ref string design, string templateAlias)
|
||||
//{
|
||||
// var formElement = Regex.Match(design, GetElementRegExp("?ASPNET_FORM", false), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
// if (string.IsNullOrEmpty(formElement.Value) == false)
|
||||
// {
|
||||
// string formReplace = String.Format("<form id=\"{0}Form\" runat=\"server\">", templateAlias.Replace(" ", ""));
|
||||
// if (formElement.Groups.Count == 0)
|
||||
// {
|
||||
// formReplace += "<asp:scriptmanager runat=\"server\"></asp:scriptmanager>";
|
||||
// }
|
||||
// design = design.Replace(formElement.Value, formReplace);
|
||||
// }
|
||||
//}
|
||||
|
||||
//private static string CreateDefaultPlaceHolder(string templateAlias)
|
||||
//{
|
||||
// return String.Format("<asp:ContentPlaceHolder ID=\"{0}ContentPlaceHolder\" runat=\"server\"></asp:ContentPlaceHolder>", templateAlias.Replace(" ", ""));
|
||||
//}
|
||||
|
||||
//private static void ReplaceElement(ref string design, string elementName, string newElementName, bool checkForQuotes)
|
||||
//{
|
||||
// var m =
|
||||
// Regex.Matches(design, GetElementRegExp(elementName, checkForQuotes),
|
||||
// RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
// foreach (Match match in m)
|
||||
// {
|
||||
// GroupCollection groups = match.Groups;
|
||||
|
||||
// // generate new element (compensate for a closing trail on single elements ("/"))
|
||||
// string elementAttributes = groups[1].Value;
|
||||
// // test for macro alias
|
||||
// if (elementName == "?UMBRACO_MACRO")
|
||||
// {
|
||||
// var tags = XmlHelper.GetAttributesFromElement(match.Value);
|
||||
// if (tags["macroAlias"] != null)
|
||||
// elementAttributes = String.Format(" Alias=\"{0}\"", tags["macroAlias"]) + elementAttributes;
|
||||
// else if (tags["macroalias"] != null)
|
||||
// elementAttributes = String.Format(" Alias=\"{0}\"", tags["macroalias"]) + elementAttributes;
|
||||
// }
|
||||
// string newElement = "<" + newElementName + " runat=\"server\" " + elementAttributes.Trim() + ">";
|
||||
// if (elementAttributes.EndsWith("/"))
|
||||
// {
|
||||
// elementAttributes = elementAttributes.Substring(0, elementAttributes.Length - 1);
|
||||
// }
|
||||
// else if (groups[0].Value.StartsWith("</"))
|
||||
// // It's a closing element, so generate that instead of a starting element
|
||||
// newElement = "</" + newElementName + ">";
|
||||
|
||||
// if (checkForQuotes)
|
||||
// {
|
||||
// // if it's inside quotes, we'll change element attribute quotes to single quotes
|
||||
// newElement = newElement.Replace("\"", "'");
|
||||
// newElement = String.Format("\"{0}\"", newElement);
|
||||
// }
|
||||
// design = design.Replace(match.Value, newElement);
|
||||
// }
|
||||
//}
|
||||
|
||||
//private static string GetElementRegExp(string elementName, bool checkForQuotes)
|
||||
//{
|
||||
// if (checkForQuotes)
|
||||
// return String.Format("\"<[^>\\s]*\\b{0}(\\b[^>]*)>\"", elementName);
|
||||
// else
|
||||
// return String.Format("<[^>\\s]*\\b{0}(\\b[^>]*)>", elementName);
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Core.IO
|
||||
public PhysicalFileSystem(string virtualRoot)
|
||||
{
|
||||
if (virtualRoot == null) throw new ArgumentNullException("virtualRoot");
|
||||
if (virtualRoot.StartsWith("~/") == false)
|
||||
if (!virtualRoot.StartsWith("~/"))
|
||||
throw new ArgumentException("The virtualRoot argument must be a virtual path and start with '~/'");
|
||||
|
||||
RootPath = IOHelper.MapPath(virtualRoot);
|
||||
@@ -65,7 +65,7 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public void DeleteDirectory(string path, bool recursive)
|
||||
{
|
||||
if (DirectoryExists(path) == false)
|
||||
if (!DirectoryExists(path))
|
||||
return;
|
||||
|
||||
try
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
public class SystemFiles
|
||||
{
|
||||
[Obsolete("This file is no longer used and should not be accessed!")]
|
||||
|
||||
public static string AccessXml
|
||||
{
|
||||
get
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
internal class ViewHelper
|
||||
{
|
||||
private readonly IFileSystem _viewFileSystem;
|
||||
|
||||
public ViewHelper(IFileSystem viewFileSystem)
|
||||
{
|
||||
if (viewFileSystem == null) throw new ArgumentNullException("viewFileSystem");
|
||||
_viewFileSystem = viewFileSystem;
|
||||
}
|
||||
|
||||
internal bool ViewExists(ITemplate t)
|
||||
{
|
||||
return _viewFileSystem.FileExists(ViewPath(t.Alias));
|
||||
}
|
||||
|
||||
[Obsolete("This is only used for legacy purposes and will be removed in future versions")]
|
||||
internal string GetPhysicalFilePath(ITemplate t)
|
||||
{
|
||||
return _viewFileSystem.GetFullPath(ViewPath(t.Alias));
|
||||
}
|
||||
|
||||
internal string GetFileContents(ITemplate t)
|
||||
{
|
||||
string viewContent = "";
|
||||
string path = ViewPath(t.Alias);
|
||||
|
||||
if (_viewFileSystem.FileExists(path))
|
||||
{
|
||||
using (var tr = new StreamReader(_viewFileSystem.OpenFile(path)))
|
||||
{
|
||||
viewContent = tr.ReadToEnd();
|
||||
tr.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return viewContent;
|
||||
}
|
||||
|
||||
public string CreateView(ITemplate t, bool overWrite = false)
|
||||
{
|
||||
string viewContent;
|
||||
string path = ViewPath(t.Alias);
|
||||
|
||||
if (_viewFileSystem.FileExists(path) == false || overWrite)
|
||||
{
|
||||
viewContent = SaveTemplateToFile(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var tr = new StreamReader(_viewFileSystem.OpenFile(path)))
|
||||
{
|
||||
viewContent = tr.ReadToEnd();
|
||||
tr.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return viewContent;
|
||||
}
|
||||
|
||||
internal static string GetDefaultFileContent(string layoutPageAlias = null)
|
||||
{
|
||||
var design = @"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
|
||||
@{
|
||||
Layout = null;
|
||||
}";
|
||||
|
||||
if (layoutPageAlias.IsNullOrWhiteSpace() == false)
|
||||
design = design.Replace("null", string.Format("\"{0}.cshtml\"", layoutPageAlias));
|
||||
|
||||
return design;
|
||||
}
|
||||
|
||||
private string SaveTemplateToFile(ITemplate template)
|
||||
{
|
||||
var design = template.Content.IsNullOrWhiteSpace() ? EnsureInheritedLayout(template) : template.Content;
|
||||
var path = ViewPath(template.Alias);
|
||||
|
||||
var data = Encoding.UTF8.GetBytes(design);
|
||||
var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
|
||||
|
||||
using (var ms = new MemoryStream(withBom))
|
||||
{
|
||||
_viewFileSystem.AddFile(path, ms, true);
|
||||
}
|
||||
|
||||
return design;
|
||||
}
|
||||
|
||||
public string UpdateViewFile(ITemplate t, string currentAlias = null)
|
||||
{
|
||||
var path = ViewPath(t.Alias);
|
||||
|
||||
if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != t.Alias)
|
||||
{
|
||||
//then kill the old file..
|
||||
var oldFile = ViewPath(currentAlias);
|
||||
if (_viewFileSystem.FileExists(oldFile))
|
||||
_viewFileSystem.DeleteFile(oldFile);
|
||||
}
|
||||
|
||||
var data = Encoding.UTF8.GetBytes(t.Content);
|
||||
var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
|
||||
|
||||
using (var ms = new MemoryStream(withBom))
|
||||
{
|
||||
_viewFileSystem.AddFile(path, ms, true);
|
||||
}
|
||||
return t.Content;
|
||||
}
|
||||
|
||||
internal void RemoveViewFile(string alias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(alias) == false)
|
||||
{
|
||||
var file = ViewPath(alias);
|
||||
if (_viewFileSystem.FileExists(file))
|
||||
_viewFileSystem.DeleteFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
public string ViewPath(string alias)
|
||||
{
|
||||
return _viewFileSystem.GetRelativePath(alias.Replace(" ", "") + ".cshtml");
|
||||
|
||||
//return SystemDirectories.MvcViews + "/" + alias.Replace(" ", "") + ".cshtml";
|
||||
}
|
||||
|
||||
private string EnsureInheritedLayout(ITemplate template)
|
||||
{
|
||||
string design = template.Content;
|
||||
|
||||
if (string.IsNullOrEmpty(design))
|
||||
{
|
||||
design = GetDefaultFileContent(template.MasterTemplateAlias);
|
||||
}
|
||||
|
||||
return design;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows for outputting a normalized appdomainappid token in a log format
|
||||
/// </summary>
|
||||
public sealed class AppDomainTokenConverter : log4net.Util.PatternConverter
|
||||
{
|
||||
protected override void Convert(TextWriter writer, object state)
|
||||
{
|
||||
writer.Write(HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
internal class DebugDiagnosticsLogger : ILogger
|
||||
{
|
||||
public void Error(Type callingType, string message, Exception exception)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, callingType.ToString());
|
||||
}
|
||||
|
||||
public void Warn(Type callingType, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(message, formatItems.Select(x => x()).ToArray()), callingType.ToString());
|
||||
}
|
||||
|
||||
public void WarnWithException(Type callingType, string message, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(message + Environment.NewLine + e, formatItems.Select(x => x()).ToArray()), callingType.ToString());
|
||||
}
|
||||
|
||||
public void Info(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(generateMessage(), callingType.ToString());
|
||||
}
|
||||
|
||||
public void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(generateMessageFormat, formatItems.Select(x => x()).ToArray()), type.ToString());
|
||||
}
|
||||
|
||||
public void Debug(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(generateMessage(), callingType.ToString());
|
||||
}
|
||||
|
||||
public void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(generateMessageFormat, formatItems.Select(x => x()).ToArray()), type.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for logging service.
|
||||
/// </summary>
|
||||
public interface ILogger
|
||||
{
|
||||
void Error(Type callingType, string message, Exception exception);
|
||||
|
||||
void Warn(Type callingType, string message, params Func<object>[] formatItems);
|
||||
|
||||
void WarnWithException(Type callingType, string message, Exception e, params Func<object>[] formatItems);
|
||||
|
||||
void Info(Type callingType, Func<string> generateMessage);
|
||||
|
||||
void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems);
|
||||
|
||||
void Debug(Type callingType, Func<string> generateMessage);
|
||||
|
||||
void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
@@ -6,14 +7,46 @@ using log4net;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
///<summary>
|
||||
/// Used for logging, ILogger should be used instead but this is available for static access to logging
|
||||
///<summary>
|
||||
/// Used for logging
|
||||
///</summary>
|
||||
/// <remarks>
|
||||
/// this wraps ILogger
|
||||
/// </remarks>
|
||||
public static class LogHelper
|
||||
{
|
||||
///<summary>
|
||||
/// Returns a logger for the type specified
|
||||
///</summary>
|
||||
///<typeparam name="T"></typeparam>
|
||||
///<returns></returns>
|
||||
internal static ILog LoggerFor<T>()
|
||||
{
|
||||
return LogManager.GetLogger(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a logger for the object's type
|
||||
/// </summary>
|
||||
/// <param name="getTypeFromInstance"></param>
|
||||
/// <returns></returns>
|
||||
internal static ILog LoggerFor(object getTypeFromInstance)
|
||||
{
|
||||
if (getTypeFromInstance == null) throw new ArgumentNullException("getTypeFromInstance");
|
||||
|
||||
return LogManager.GetLogger(getTypeFromInstance.GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Useful if the logger itself is running on another thread
|
||||
/// </summary>
|
||||
/// <param name="generateMessageFormat"></param>
|
||||
/// <returns></returns>
|
||||
private static string PrefixThreadId(string generateMessageFormat)
|
||||
{
|
||||
return (_prefixThreadId ?? (_prefixThreadId = "[P" + Process.GetCurrentProcess().Id + "/T" + Thread.CurrentThread.ManagedThreadId + "/D" + AppDomain.CurrentDomain.Id + "] "))
|
||||
+ generateMessageFormat;
|
||||
}
|
||||
|
||||
private static string _prefixThreadId = null;
|
||||
|
||||
#region Error
|
||||
/// <summary>
|
||||
/// Adds an error log
|
||||
@@ -23,14 +56,14 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="exception"></param>
|
||||
public static void Error<T>(string message, Exception exception)
|
||||
{
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Error<T>(message, exception);
|
||||
Error(typeof (T), message, exception);
|
||||
}
|
||||
|
||||
public static void Error(Type callingType, string message, Exception exception)
|
||||
{
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Error(callingType, message, exception);
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger != null)
|
||||
logger.Error(PrefixThreadId(message), exception);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -39,11 +72,11 @@ namespace Umbraco.Core.Logging
|
||||
|
||||
public static void Warn(Type callingType, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Warn(callingType, message, formatItems);
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsWarnEnabled) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Warn(Type callingType, string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(callingType, "callingType");
|
||||
@@ -52,10 +85,11 @@ namespace Umbraco.Core.Logging
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn(callingType.Name, string.Format(message, formatItems.Select(x => x.Invoke()).ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Warn(callingType, message, formatItems);
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsWarnEnabled) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
|
||||
}
|
||||
|
||||
@@ -64,7 +98,6 @@ namespace Umbraco.Core.Logging
|
||||
WarnWithException(callingType, message, false, e, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void WarnWithException(Type callingType, string message, bool showHttpTrace, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(e, "e");
|
||||
@@ -79,8 +112,10 @@ namespace Umbraco.Core.Logging
|
||||
e);
|
||||
}
|
||||
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.WarnWithException(callingType, message, e, formatItems);
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsWarnEnabled) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.WarnFormat(PrefixThreadId(message) + ". Exception: " + e, executedParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,7 +129,6 @@ namespace Umbraco.Core.Logging
|
||||
Warn(typeof(T), message, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Warn<T>(string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
Warn(typeof(T), message, showHttpTrace, formatItems);
|
||||
@@ -104,8 +138,6 @@ namespace Umbraco.Core.Logging
|
||||
{
|
||||
WarnWithException(typeof(T), message, e, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void WarnWithException<T>(string message, bool showHttpTrace, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
WarnWithException(typeof(T), message, showHttpTrace, e, formatItems);
|
||||
@@ -132,8 +164,9 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="generateMessage"></param>
|
||||
public static void Info(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Info(callingType, generateMessage);
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsInfoEnabled) return;
|
||||
logger.Info(PrefixThreadId(generateMessage.Invoke()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,8 +177,10 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public static void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Info(type, generateMessageFormat, formatItems);
|
||||
var logger = LogManager.GetLogger(type);
|
||||
if (logger == null || !logger.IsInfoEnabled) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.InfoFormat(PrefixThreadId(generateMessageFormat), executedParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -180,8 +215,9 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="generateMessage"></param>
|
||||
public static void Debug(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Debug(callingType, generateMessage);
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsDebugEnabled) return;
|
||||
logger.Debug(PrefixThreadId(generateMessage.Invoke()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -192,8 +228,10 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public static void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Debug(type, generateMessageFormat, formatItems);
|
||||
var logger = LogManager.GetLogger(type);
|
||||
if (logger == null || !logger.IsDebugEnabled) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.DebugFormat(PrefixThreadId(generateMessageFormat), executedParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -216,7 +254,6 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="generateMessageFormat"></param>
|
||||
/// <param name="showHttpTrace"></param>
|
||||
/// <param name="formatItems"></param>
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Debug<T>(string generateMessageFormat, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using log4net;
|
||||
using log4net.Config;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
///<summary>
|
||||
/// Used for logging
|
||||
///</summary>
|
||||
public class Logger : ILogger
|
||||
{
|
||||
public Logger(FileInfo log4NetConfigFile)
|
||||
{
|
||||
XmlConfigurator.Configure(log4NetConfigFile);
|
||||
}
|
||||
|
||||
private Logger()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a logger with the default log4net configuration discovered (i.e. from the web.config)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Logger CreateWithDefaultLog4NetConfiguration()
|
||||
{
|
||||
return new Logger();
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Returns a logger for the type specified
|
||||
///</summary>
|
||||
///<typeparam name="T"></typeparam>
|
||||
///<returns></returns>
|
||||
internal ILog LoggerFor<T>()
|
||||
{
|
||||
return LogManager.GetLogger(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a logger for the object's type
|
||||
/// </summary>
|
||||
/// <param name="getTypeFromInstance"></param>
|
||||
/// <returns></returns>
|
||||
internal ILog LoggerFor(object getTypeFromInstance)
|
||||
{
|
||||
if (getTypeFromInstance == null) throw new ArgumentNullException("getTypeFromInstance");
|
||||
|
||||
return LogManager.GetLogger(getTypeFromInstance.GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Useful if the logger itself is running on another thread
|
||||
/// </summary>
|
||||
/// <param name="generateMessageFormat"></param>
|
||||
/// <returns></returns>
|
||||
private string PrefixThreadId(string generateMessageFormat)
|
||||
{
|
||||
return "[Thread " + Thread.CurrentThread.ManagedThreadId + "] " + generateMessageFormat;
|
||||
}
|
||||
|
||||
public void Error(Type callingType, string message, Exception exception)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger != null)
|
||||
logger.Error(PrefixThreadId(message), exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Warn(Type callingType, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
}
|
||||
|
||||
public void Warn(Type callingType, string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(callingType, "callingType");
|
||||
Mandate.ParameterNotNullOrEmpty(message, "message");
|
||||
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn(callingType.Name, string.Format(message, formatItems.Select(x => x.Invoke()).ToArray()));
|
||||
}
|
||||
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
|
||||
}
|
||||
|
||||
public void WarnWithException(Type callingType, string message, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(e, "e");
|
||||
Mandate.ParameterNotNull(callingType, "callingType");
|
||||
Mandate.ParameterNotNullOrEmpty(message, "message");
|
||||
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.WarnFormat(PrefixThreadId(message) + ". Exception: " + e, executedParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="callingType"></param>
|
||||
/// <param name="generateMessage"></param>
|
||||
public void Info(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsInfoEnabled == false) return;
|
||||
logger.Info(PrefixThreadId(generateMessage.Invoke()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="type">The type for the logging namespace.</param>
|
||||
/// <param name="generateMessageFormat">The message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(type);
|
||||
if (logger == null || logger.IsInfoEnabled == false) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.InfoFormat(PrefixThreadId(generateMessageFormat), executedParams);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Debugs if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="callingType"></param>
|
||||
/// <param name="generateMessage"></param>
|
||||
public void Debug(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsDebugEnabled == false) return;
|
||||
logger.Debug(PrefixThreadId(generateMessage.Invoke()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="type">The type for the logging namespace.</param>
|
||||
/// <param name="generateMessageFormat">The message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(type);
|
||||
if (logger == null || logger.IsDebugEnabled == false) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.DebugFormat(PrefixThreadId(generateMessageFormat), executedParams);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows for strongly typed log sources
|
||||
/// </summary>
|
||||
public static class LoggerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an error log
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exception"></param>
|
||||
public static void Error<T>(this ILogger logger, string message, Exception exception)
|
||||
{
|
||||
logger.Error(typeof(T), message, exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a warn log
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="formatItems"></param>
|
||||
public static void Warn<T>(this ILogger logger, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
logger.Warn(typeof(T), message, formatItems);
|
||||
}
|
||||
|
||||
public static void WarnWithException<T>(this ILogger logger, string message, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
logger.WarnWithException(typeof(T), message, e, formatItems);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="generateMessageFormat">The generate message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Info<T>(this ILogger logger, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
logger.Info(typeof(T), generateMessageFormat, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="generateMessage">The delegate to generate a message.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Info<T>(this ILogger logger, Func<string> generateMessage)
|
||||
{
|
||||
logger.Info(typeof(T), generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="generateMessage">The delegate to generate a message.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Debug<T>(this ILogger logger, Func<string> generateMessage)
|
||||
{
|
||||
logger.Debug(typeof(T), generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs a message, only generating the message if debug is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="generateMessageFormat">The generate message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Debug<T>(this ILogger logger, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
logger.Debug(typeof(T), generateMessageFormat, formatItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
public sealed class LoggerResolver : SingleObjectResolverBase<LoggerResolver, ILogger>
|
||||
{
|
||||
public LoggerResolver(ILogger logger)
|
||||
: base(logger)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method allowing to change the logger during startup
|
||||
/// </summary>
|
||||
/// <param name="profiler"></param>
|
||||
internal void SetLogger(ILogger profiler)
|
||||
{
|
||||
Value = profiler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current logger
|
||||
/// </summary>
|
||||
public ILogger Logger
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
internal class OwinLogger : Microsoft.Owin.Logging.ILogger
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly Lazy<Type> _type;
|
||||
|
||||
public OwinLogger(ILogger logger, Lazy<Type> type)
|
||||
{
|
||||
_logger = logger;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates most logging patterns to a single method. This must be compatible with the Func representation in the OWIN environment.
|
||||
/// To check IsEnabled call WriteCore with only TraceEventType and check the return value, no event will be written.
|
||||
/// </summary>
|
||||
/// <param name="eventType"/><param name="eventId"/><param name="state"/><param name="exception"/><param name="formatter"/>
|
||||
/// <returns/>
|
||||
public bool WriteCore(TraceEventType eventType, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
|
||||
{
|
||||
if (state == null) state = "";
|
||||
switch (eventType)
|
||||
{
|
||||
case TraceEventType.Critical:
|
||||
_logger.Error(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state), exception ?? new Exception("Critical error"));
|
||||
return true;
|
||||
case TraceEventType.Error:
|
||||
_logger.Error(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state), exception ?? new Exception("Error"));
|
||||
return true;
|
||||
case TraceEventType.Warning:
|
||||
_logger.Warn(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Information:
|
||||
_logger.Info(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Verbose:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Start:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Stop:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Suspend:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Resume:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Transfer:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("eventType");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Owin.Logging;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
internal class OwinLoggerFactory : ILoggerFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new ILogger instance of the given name.
|
||||
/// </summary>
|
||||
/// <param name="name"/>
|
||||
/// <returns/>
|
||||
public Microsoft.Owin.Logging.ILogger Create(string name)
|
||||
{
|
||||
return new OwinLogger(
|
||||
LoggerResolver.HasCurrent ? LoggerResolver.Current.Logger : new DebugDiagnosticsLogger(),
|
||||
new Lazy<Type>(() => Type.GetType(name) ?? typeof (OwinLogger)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
using System;
|
||||
using Umbraco.Core.Profiling;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to create DisposableTimer instances for debugging or tracing durations
|
||||
/// </summary>
|
||||
public sealed class ProfilingLogger
|
||||
{
|
||||
public ILogger Logger { get; private set; }
|
||||
public IProfiler Profiler { get; private set; }
|
||||
|
||||
public ProfilingLogger(ILogger logger, IProfiler profiler)
|
||||
{
|
||||
Logger = logger;
|
||||
Profiler = profiler;
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (profiler == null) throw new ArgumentNullException("profiler");
|
||||
}
|
||||
|
||||
public DisposableTimer TraceDuration<T>(string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
public DisposableTimer TraceDuration<T>(string startMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, typeof(T), startMessage, "Complete");
|
||||
}
|
||||
|
||||
public DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, loggerType, startMessage, completeMessage);
|
||||
}
|
||||
|
||||
public DisposableTimer DebugDuration<T>(string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
public DisposableTimer DebugDuration<T>(string startMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, typeof(T), startMessage, "Complete");
|
||||
}
|
||||
|
||||
public DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, loggerType, startMessage, completeMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
@@ -19,14 +18,13 @@ namespace Umbraco.Core.Macros
|
||||
/// </remarks>
|
||||
internal sealed class MacroFieldEditorsResolver : LazyManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="macroEditors"></param>
|
||||
internal MacroFieldEditorsResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> macroEditors)
|
||||
: base(serviceProvider, logger, macroEditors, ObjectLifetimeScope.Transient)
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="macroEditors"></param>
|
||||
internal MacroFieldEditorsResolver(Func<IEnumerable<Type>> macroEditors)
|
||||
: base(macroEditors, ObjectLifetimeScope.Transient)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
@@ -72,10 +70,10 @@ namespace Umbraco.Core.Macros
|
||||
internal Control GetMacroRenderControlByType(PersistableMacroProperty prop, string uniqueId)
|
||||
{
|
||||
var m = MacroControlTypes.FindLast(macroGuiCcontrol => macroGuiCcontrol.ToString() == string.Format("{0}.{1}", prop.AssemblyName, prop.TypeName));
|
||||
var instance = ServiceProvider.GetService(m) as IMacroGuiRendering;
|
||||
var instance = PluginManager.Current.CreateInstance<IMacroGuiRendering>(m);
|
||||
if (instance != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(prop.Value) == false)
|
||||
if (!string.IsNullOrEmpty(prop.Value))
|
||||
{
|
||||
instance.Value = HttpUtility.HtmlDecode(prop.Value);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Macros
|
||||
@@ -10,14 +9,13 @@ namespace Umbraco.Core.Macros
|
||||
/// </summary>
|
||||
internal sealed class XsltExtensionsResolver : LazyManyObjectsResolverBase<XsltExtensionsResolver, XsltExtension>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="packageActions"></param>
|
||||
internal XsltExtensionsResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> packageActions)
|
||||
: base(serviceProvider, logger, packageActions, ObjectLifetimeScope.Application)
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="packageActions"></param>
|
||||
internal XsltExtensionsResolver(Func<IEnumerable<Type>> packageActions)
|
||||
: base(packageActions, ObjectLifetimeScope.Application)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
// represents the main domain
|
||||
class MainDom : IRegisteredObject
|
||||
{
|
||||
#region Vars
|
||||
|
||||
// our own lock for local consistency
|
||||
private readonly object _locko = new object();
|
||||
|
||||
// async lock representing the main domain lock
|
||||
private readonly AsyncLock _asyncLock;
|
||||
private IDisposable _asyncLocker;
|
||||
|
||||
// event wait handle used to notify current main domain that it should
|
||||
// release the lock because a new domain wants to be the main domain
|
||||
private readonly EventWaitHandle _signal;
|
||||
|
||||
// indicates whether...
|
||||
private volatile bool _isMainDom; // we are the main domain
|
||||
private volatile bool _signaled; // we have been signaled
|
||||
|
||||
// actions to run before releasing the main domain
|
||||
private readonly SortedList<int, Action> _callbacks = new SortedList<int, Action>();
|
||||
|
||||
private const int LockTimeoutMilliseconds = 90000; // (1.5 * 60 * 1000) == 1 min 30 seconds
|
||||
|
||||
#endregion
|
||||
|
||||
#region Ctor
|
||||
|
||||
// initializes a new instance of MainDom
|
||||
public MainDom()
|
||||
{
|
||||
var appId = string.Empty;
|
||||
// HostingEnvironment.ApplicationID is null in unit tests, making ReplaceNonAlphanumericChars fail
|
||||
if (HostingEnvironment.ApplicationID != null)
|
||||
appId = HostingEnvironment.ApplicationID.ReplaceNonAlphanumericChars(string.Empty);
|
||||
|
||||
var lockName = "UMBRACO-" + appId + "-MAINDOM-LCK";
|
||||
_asyncLock = new AsyncLock(lockName);
|
||||
|
||||
var eventName = "UMBRACO-" + appId + "-MAINDOM-EVT";
|
||||
_signal = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// register a main domain consumer
|
||||
public bool Register(Action release, int weight = 100)
|
||||
{
|
||||
return Register(null, release, weight);
|
||||
}
|
||||
|
||||
// register a main domain consumer
|
||||
public bool Register(Action install, Action release, int weight = 100)
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
if (_signaled) return false;
|
||||
if (install != null)
|
||||
install();
|
||||
if (release != null)
|
||||
_callbacks.Add(weight, release);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// handles the signal requesting that the main domain is released
|
||||
private void OnSignal(string source)
|
||||
{
|
||||
// once signaled, we stop waiting, but then there is the hosting environment
|
||||
// so we have to make sure that we only enter that method once
|
||||
|
||||
lock (_locko)
|
||||
{
|
||||
LogHelper.Debug<MainDom>("Signaled" + (_signaled ? " (again)" : "") + " (" + source + ").");
|
||||
if (_signaled) return;
|
||||
if (_isMainDom == false) return; // probably not needed
|
||||
_signaled = true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
LogHelper.Debug<MainDom>("Stopping...");
|
||||
foreach (var callback in _callbacks.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(); // no timeout on callbacks
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<MainDom>("Error while running callback, remaining callbacks will not run.", e);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
LogHelper.Debug<MainDom>("Stopped.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// in any case...
|
||||
_isMainDom = false;
|
||||
_asyncLocker.Dispose();
|
||||
LogHelper.Debug<MainDom>("Released MainDom.");
|
||||
}
|
||||
}
|
||||
|
||||
// acquires the main domain
|
||||
public bool Acquire()
|
||||
{
|
||||
lock (_locko) // we don't want the hosting environment to interfere by signaling
|
||||
{
|
||||
// if signaled, too late to acquire, give up
|
||||
// the handler is not installed so that would be the hosting environment
|
||||
if (_signaled)
|
||||
{
|
||||
LogHelper.Debug<MainDom>("Cannot acquire MainDom (signaled).");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogHelper.Debug<MainDom>("Acquiring MainDom...");
|
||||
|
||||
// signal other instances that we want the lock, then wait one the lock,
|
||||
// which may timeout, and this is accepted - see comments below
|
||||
|
||||
// signal, then wait for the lock, then make sure the event is
|
||||
// resetted (maybe there was noone listening..)
|
||||
_signal.Set();
|
||||
|
||||
// if more than 1 instance reach that point, one will get the lock
|
||||
// and the other one will timeout, which is accepted
|
||||
|
||||
_asyncLocker = _asyncLock.Lock(LockTimeoutMilliseconds);
|
||||
_isMainDom = true;
|
||||
|
||||
// we need to reset the event, because otherwise we would end up
|
||||
// signaling ourselves and commiting suicide immediately.
|
||||
// only 1 instance can reach that point, but other instances may
|
||||
// have started and be trying to get the lock - they will timeout,
|
||||
// which is accepted
|
||||
|
||||
_signal.Reset();
|
||||
_signal.WaitOneAsync()
|
||||
.ContinueWith(_ => OnSignal("signal"));
|
||||
|
||||
HostingEnvironment.RegisterObject(this);
|
||||
|
||||
LogHelper.Debug<MainDom>("Acquired MainDom.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// gets a value indicating whether we are the main domain
|
||||
public bool IsMainDom
|
||||
{
|
||||
get { return _isMainDom; }
|
||||
}
|
||||
|
||||
// IRegisteredObject
|
||||
public void Stop(bool immediate)
|
||||
{
|
||||
try
|
||||
{
|
||||
OnSignal("environment"); // will run once
|
||||
}
|
||||
finally
|
||||
{
|
||||
HostingEnvironment.UnregisterObject(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
@@ -8,17 +7,10 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
internal class ManifestWatcher : DisposableObject
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly List<FileSystemWatcher> _fws = new List<FileSystemWatcher>();
|
||||
private static volatile bool _isRestarting = false;
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
public ManifestWatcher(ILogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Start(params string[] packageFolders)
|
||||
{
|
||||
foreach (var packageFolder in packageFolders)
|
||||
@@ -51,7 +43,7 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
_isRestarting = true;
|
||||
|
||||
_logger.Info<ManifestWatcher>("manifest has changed, app pool is restarting (" + e.FullPath + ")");
|
||||
LogHelper.Info<ManifestWatcher>("manifest has changed, app pool is restarting (" + e.FullPath + ")");
|
||||
HttpRuntime.UnloadAppDomain();
|
||||
Dispose();
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public sealed class AuditItem : Entity, IAggregateRoot
|
||||
{
|
||||
public AuditItem(int objectId, string comment, AuditType type, int userId)
|
||||
{
|
||||
Id = objectId;
|
||||
Comment = comment;
|
||||
AuditType = type;
|
||||
UserId = userId;
|
||||
}
|
||||
|
||||
public string Comment { get; private set; }
|
||||
public AuditType AuditType { get; private set; }
|
||||
public int UserId { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Enums for vailable types of auditing
|
||||
/// </summary>
|
||||
public enum AuditType
|
||||
{
|
||||
/// <summary>
|
||||
/// Used when new nodes are added
|
||||
/// </summary>
|
||||
New,
|
||||
/// <summary>
|
||||
/// Used when nodes are saved
|
||||
/// </summary>
|
||||
Save,
|
||||
/// <summary>
|
||||
/// Used when nodes are opened
|
||||
/// </summary>
|
||||
Open,
|
||||
/// <summary>
|
||||
/// Used when nodes are deleted
|
||||
/// </summary>
|
||||
Delete,
|
||||
/// <summary>
|
||||
/// Used when nodes are published
|
||||
/// </summary>
|
||||
Publish,
|
||||
/// <summary>
|
||||
/// Used when nodes are send to publishing
|
||||
/// </summary>
|
||||
SendToPublish,
|
||||
/// <summary>
|
||||
/// Used when nodes are unpublished
|
||||
/// </summary>
|
||||
UnPublish,
|
||||
/// <summary>
|
||||
/// Used when nodes are moved
|
||||
/// </summary>
|
||||
Move,
|
||||
/// <summary>
|
||||
/// Used when nodes are copied
|
||||
/// </summary>
|
||||
Copy,
|
||||
/// <summary>
|
||||
/// Used when nodes are assígned a domain
|
||||
/// </summary>
|
||||
AssignDomain,
|
||||
/// <summary>
|
||||
/// Used when public access are changed for a node
|
||||
/// </summary>
|
||||
PublicAccess,
|
||||
/// <summary>
|
||||
/// Used when nodes are sorted
|
||||
/// </summary>
|
||||
Sort,
|
||||
/// <summary>
|
||||
/// Used when a notification are send to a user
|
||||
/// </summary>
|
||||
Notify,
|
||||
/// <summary>
|
||||
/// General system notification
|
||||
/// </summary>
|
||||
System,
|
||||
/// <summary>
|
||||
/// Used when a node's content is rolled back to a previous version
|
||||
/// </summary>
|
||||
RollBack,
|
||||
/// <summary>
|
||||
/// Used when a package is installed
|
||||
/// </summary>
|
||||
PackagerInstall,
|
||||
/// <summary>
|
||||
/// Used when a package is uninstalled
|
||||
/// </summary>
|
||||
PackagerUninstall,
|
||||
/// <summary>
|
||||
/// Used when a node is send to translation
|
||||
/// </summary>
|
||||
SendToTranslate,
|
||||
/// <summary>
|
||||
/// Use this log action for custom log messages that should be shown in the audit trail
|
||||
/// </summary>
|
||||
Custom
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,10 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Language of the data contained within this Content object.
|
||||
/// </summary>
|
||||
[Obsolete("This is not used and will be removed from the codebase in future versions")]
|
||||
/// <remarks>
|
||||
/// Left internal until multilingual support is implemented.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public string Language
|
||||
{
|
||||
get { return _language; }
|
||||
@@ -318,17 +321,6 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
internal PublishedState PublishedState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier of the published version, if any.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public Guid PublishedVersionGuid { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content has a published version.
|
||||
/// </summary>
|
||||
public bool HasPublishedVersion { get { return PublishedVersionGuid != default(Guid); } }
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Trashed state of the content object
|
||||
/// </summary>
|
||||
|
||||
@@ -657,10 +657,12 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns>True if the content has any published versiom otherwise False</returns>
|
||||
[Obsolete("Use the HasPublishedVersion property.", false)]
|
||||
public static bool HasPublishedVersion(this IContent content)
|
||||
{
|
||||
return content.HasPublishedVersion;
|
||||
if (content.HasIdentity == false)
|
||||
return false;
|
||||
|
||||
return ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
}
|
||||
|
||||
#region Tag methods
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal static class CssCompactor
|
||||
{
|
||||
#region CssCompactor.Options
|
||||
|
||||
[Flags]
|
||||
public enum Options
|
||||
{
|
||||
None = 0x00,
|
||||
PrettyPrint = 0x01,
|
||||
Overwrite = 0x02
|
||||
}
|
||||
|
||||
#endregion CssCompactor.Options
|
||||
|
||||
#region Public Methods
|
||||
|
||||
internal static List<ParseException> Compact(string inputFile, string outputFile, string copyright, string timeStamp, CssCompactor.Options options)
|
||||
{
|
||||
if (!System.IO.File.Exists(inputFile))
|
||||
{
|
||||
throw new FileNotFoundException(String.Format("File (\"{0}\") not found.", inputFile), inputFile);
|
||||
}
|
||||
|
||||
if ((options & CssCompactor.Options.Overwrite) == 0x0 && System.IO.File.Exists(outputFile))
|
||||
{
|
||||
throw new AccessViolationException(String.Format("File (\"{0}\") already exists.", outputFile));
|
||||
}
|
||||
|
||||
if (inputFile.Equals(outputFile, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new ApplicationException("Input and output file are set to the same path.");
|
||||
}
|
||||
|
||||
FileUtility.PrepSavePath(outputFile);
|
||||
using (TextWriter output = System.IO.File.CreateText(outputFile))
|
||||
{
|
||||
return CssCompactor.Compact(inputFile, null, output, copyright, timeStamp, options);
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<ParseException> Compact(string inputFile, string inputSource, TextWriter output, string copyright, string timeStamp, CssCompactor.Options options)
|
||||
{
|
||||
if (output == null)
|
||||
{
|
||||
throw new NullReferenceException("Output TextWriter was null.");
|
||||
}
|
||||
|
||||
// write out header with copyright and timestamp
|
||||
CssCompactor.WriteHeader(output, copyright, timeStamp);
|
||||
|
||||
// verify, compact and write out results
|
||||
CssParser parser = new CssParser(inputFile, inputSource);
|
||||
parser.Write(output, options);
|
||||
|
||||
// return any errors
|
||||
return parser.Errors;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private static void WriteHeader(TextWriter writer, string copyright, string timeStamp)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(copyright) || !String.IsNullOrEmpty(timeStamp))
|
||||
{
|
||||
int width = 6;
|
||||
if (!String.IsNullOrEmpty(copyright))
|
||||
{
|
||||
copyright = copyright.Replace("*/", "");// make sure not to nest commments
|
||||
width = Math.Max(copyright.Length + 6, width);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(timeStamp))
|
||||
{
|
||||
timeStamp = DateTime.Now.ToString(timeStamp).Replace("*/", "");// make sure not to nest commments
|
||||
width = Math.Max(timeStamp.Length + 6, width);
|
||||
}
|
||||
|
||||
writer.WriteLine("/*".PadRight(width, '-') + "*\\");
|
||||
|
||||
if (!String.IsNullOrEmpty(copyright))
|
||||
{
|
||||
writer.WriteLine("\t" + copyright);
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(timeStamp))
|
||||
{
|
||||
writer.WriteLine("\t" + timeStamp);
|
||||
}
|
||||
|
||||
writer.WriteLine("\\*".PadRight(width, '-') + "*/");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,653 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal class CssParser
|
||||
{
|
||||
#region Constants
|
||||
|
||||
// this defines comments for CSS
|
||||
private static readonly ReadFilter[] ReadFilters = new ReadFilter[] { new ReadFilter("/*", "*/") };
|
||||
private readonly object SyncLock = new object();
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Fields
|
||||
|
||||
private readonly List<ParseException> errors = new List<ParseException>();
|
||||
private LineReader reader;
|
||||
private CssStyleSheet styleSheet;
|
||||
private string fileContent;
|
||||
private string source;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="fileContent">path to source</param>
|
||||
public CssParser(string fileContent)
|
||||
: this(fileContent, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="fileContent">path to source</param>
|
||||
/// <param name="source">actual source</param>
|
||||
public CssParser(string fileContent, string source)
|
||||
{
|
||||
this.fileContent = fileContent;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<ParseException> Errors
|
||||
{
|
||||
get { return this.errors; }
|
||||
}
|
||||
|
||||
public CssStyleSheet StyleSheet
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.styleSheet == null)
|
||||
{
|
||||
lock (this.SyncLock)
|
||||
{
|
||||
// check again in case race condition
|
||||
// so we don't parse twice
|
||||
if (this.styleSheet == null)
|
||||
{
|
||||
this.styleSheet = this.ParseStyleSheet();
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.styleSheet;
|
||||
}
|
||||
}
|
||||
|
||||
private int Position
|
||||
{
|
||||
get { return this.reader.Position; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Parse Methods
|
||||
|
||||
#region StyleSheet
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) stylesheet : [ CDO | CDC | S | statement ]*;
|
||||
/// </summary>
|
||||
/// <returns>CSS StyleSheet parse tree</returns>
|
||||
private CssStyleSheet ParseStyleSheet()
|
||||
{
|
||||
CssStyleSheet styleSheet = new CssStyleSheet();
|
||||
using (this.reader = new LineReader(this.fileContent, this.source, CssParser.ReadFilters))
|
||||
{
|
||||
this.reader.NormalizeWhiteSpace = true;
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();
|
||||
#endif
|
||||
|
||||
char ch;
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '\uFEFF': // BOM (UTF byte order mark)
|
||||
case '\t': //TAB
|
||||
case '\n': //LF
|
||||
case '\r': //CR
|
||||
case ' ': //Space
|
||||
{
|
||||
// skip whitespace
|
||||
continue;
|
||||
}
|
||||
case '<':
|
||||
{
|
||||
// CDO (Char Data Open?)
|
||||
if (!this.Read(out ch) || ch != '-' ||
|
||||
!this.Read(out ch) || ch != '-')
|
||||
{
|
||||
throw new SyntaxError("Expected \"<!--\"", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case '-':
|
||||
{
|
||||
// CDC (Char Data Close?)
|
||||
if (!this.Read(out ch) || ch != '-' ||
|
||||
!this.Read(out ch) || ch != '>')
|
||||
{
|
||||
throw new SyntaxError("Expected \"-->\"", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
{
|
||||
try
|
||||
{
|
||||
CssStatement statement = this.ParseStatement();
|
||||
styleSheet.Statements.Add(statement);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
this.errors.Add(ex);
|
||||
|
||||
while (this.Read(out ch) && ch != '}')
|
||||
{
|
||||
// restabilize on next statement
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
watch.Stop();
|
||||
Console.WriteLine("CSS parse duration: {0} ms for {1} chars", watch.ElapsedMilliseconds, this.reader.Length);
|
||||
#endif
|
||||
}
|
||||
|
||||
this.reader = null;
|
||||
this.source = null;
|
||||
|
||||
return styleSheet;
|
||||
}
|
||||
|
||||
#endregion StyleSheet
|
||||
|
||||
#region Statement
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) statement : ruleset | at-rule;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssStatement ParseStatement()
|
||||
{
|
||||
if (this.reader.Current == '@')
|
||||
{
|
||||
return this.ParseAtRule();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PutBack();
|
||||
return this.ParseRuleSet();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Statement
|
||||
|
||||
#region At-Rule
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) at-rule : ATKEYWORD S* any* [ block | ';' S* ];
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// NOTE: each at-rule might parse differently according to CSS3
|
||||
/// The @media block for example contains a block of statements
|
||||
/// while other at-rules with a block contain a block of declarations
|
||||
/// </remarks>
|
||||
private CssAtRule ParseAtRule()
|
||||
{
|
||||
CssAtRule atRule = new CssAtRule();
|
||||
int start = this.Position + 1;// start with first char of ident
|
||||
|
||||
char ch;
|
||||
while (this.Read(out ch) && !Char.IsWhiteSpace(ch))
|
||||
{
|
||||
// continue consuming
|
||||
}
|
||||
|
||||
atRule.Ident = this.Copy(start);
|
||||
|
||||
while (this.Read(out ch) && Char.IsWhiteSpace(ch))
|
||||
{
|
||||
// consuming whitespace
|
||||
}
|
||||
|
||||
start = this.Position;// start with current char
|
||||
do
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '{': //Block Begin
|
||||
{
|
||||
atRule.Value = this.Copy(start);
|
||||
|
||||
bool containsRuleSets = String.Equals(atRule.Ident, CssAtRule.MediaIdent, StringComparison.Ordinal);
|
||||
while (true)
|
||||
{
|
||||
while (this.Read(out ch) && Char.IsWhiteSpace(ch))
|
||||
{
|
||||
// consume whitespace
|
||||
}
|
||||
|
||||
if (ch == '}')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (containsRuleSets)
|
||||
{
|
||||
// includes @media
|
||||
CssStatement statement = this.ParseStatement();
|
||||
atRule.Block.Values.Add(statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
// includes @font-face, @page
|
||||
this.PutBack();
|
||||
CssDeclaration declaration = this.ParseDeclaration();
|
||||
atRule.Block.Values.Add(declaration);
|
||||
}
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
this.errors.Add(ex);
|
||||
|
||||
while (this.Read(out ch) && ch != '}')
|
||||
{
|
||||
// restabilize on block end
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return atRule;
|
||||
}
|
||||
case ';': //At-Rule End
|
||||
{
|
||||
atRule.Value = this.Copy(start);
|
||||
return atRule;
|
||||
}
|
||||
}
|
||||
} while (this.Read(out ch));
|
||||
|
||||
throw new UnexpectedEndOfFile("Unclosed At-Rule", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
#endregion At-Rule
|
||||
|
||||
#region RuleSet
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) ruleset : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssRuleSet ParseRuleSet()
|
||||
{
|
||||
char ch;
|
||||
CssRuleSet ruleSet = new CssRuleSet();
|
||||
|
||||
ParseSelectors:
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
CssSelector selector = this.ParseSelector();
|
||||
if (selector == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
ruleSet.Selectors.Add(selector);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
this.errors.Add(ex);
|
||||
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
// restabalize on next rulset
|
||||
switch (ch)
|
||||
{
|
||||
case ',':
|
||||
{
|
||||
// continue parsing rest of Selectors
|
||||
goto ParseSelectors;
|
||||
}
|
||||
case '{':
|
||||
{
|
||||
goto ParseDeclarations;
|
||||
}
|
||||
//case ':':// keep going
|
||||
case ';':
|
||||
case '}':
|
||||
{
|
||||
throw new SyntaxError("Invalid selector list", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParseDeclarations:
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
CssDeclaration declaration = this.ParseDeclaration();
|
||||
if (declaration == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
ruleSet.Declarations.Add(declaration);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
this.errors.Add(ex);
|
||||
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
// restabalize on next declaration
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
{
|
||||
throw new SyntaxError("Invalid ruleset", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
//case ':':// keep going
|
||||
case ';':
|
||||
{
|
||||
// continue parsing rest of delcarations
|
||||
goto ParseDeclarations;
|
||||
}
|
||||
case '}':
|
||||
{
|
||||
// no more declarations
|
||||
return ruleSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ruleSet;
|
||||
}
|
||||
|
||||
#endregion RuleSet
|
||||
|
||||
#region Selector
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) selector: any+;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssSelector ParseSelector()
|
||||
{
|
||||
CssSelector selector = new CssSelector();
|
||||
char ch;
|
||||
|
||||
while (this.Read(out ch) && (Char.IsWhiteSpace(ch) || ch == ','))
|
||||
{
|
||||
// skip whitespace, and empty selectors
|
||||
}
|
||||
|
||||
// consume property name
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
{
|
||||
// no more declarations
|
||||
return null;
|
||||
}
|
||||
//case ':':// pseudoclass
|
||||
case ';':
|
||||
case '}':
|
||||
{
|
||||
throw new SyntaxError("Invalid chars in selector", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
}
|
||||
|
||||
int start = this.Position;// start with current char
|
||||
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
// continue consuming selector
|
||||
switch (ch)
|
||||
{
|
||||
case ',':
|
||||
case '{':
|
||||
{
|
||||
selector.Value = this.Copy(start);
|
||||
if (ch == '{')
|
||||
{
|
||||
this.PutBack();
|
||||
}
|
||||
return selector;
|
||||
}
|
||||
//case ':':// pseudoclass
|
||||
case ';':
|
||||
case '}':
|
||||
{
|
||||
throw new SyntaxError("Invalid selector", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new UnexpectedEndOfFile("Unclosed ruleset", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
#endregion Selector
|
||||
|
||||
#region Declaration
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) declaration : property ':' S* value;
|
||||
/// (BNF) property : IDENT S*;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssDeclaration ParseDeclaration()
|
||||
{
|
||||
CssDeclaration declaration = new CssDeclaration();
|
||||
char ch;
|
||||
|
||||
while (this.Read(out ch) && (Char.IsWhiteSpace(ch) || ch == ';'))
|
||||
{
|
||||
// skip whitespace, and empty declarations
|
||||
}
|
||||
|
||||
// consume property name
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
case ':':
|
||||
//case ';':
|
||||
{
|
||||
throw new SyntaxError("Declaration missing property name", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
case '}':
|
||||
{
|
||||
// no more declarations
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// read property, starting with current char
|
||||
int start = this.Position;
|
||||
while (this.Read(out ch) && !Char.IsWhiteSpace(ch) && ch != ':')
|
||||
{
|
||||
// consume property name
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
//case ':':
|
||||
case ';':
|
||||
{
|
||||
throw new SyntaxError("Invalid CSS property name: " + this.Copy(start), this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
case '}':
|
||||
{
|
||||
this.PutBack();
|
||||
goto case ';';
|
||||
}
|
||||
}
|
||||
}
|
||||
declaration.Property = this.Copy(start);
|
||||
|
||||
if (Char.IsWhiteSpace(ch))
|
||||
{
|
||||
while (this.Read(out ch) && (Char.IsWhiteSpace(ch)))
|
||||
{
|
||||
// skip whitespace
|
||||
}
|
||||
}
|
||||
|
||||
if (ch != ':')
|
||||
{
|
||||
// missing the property delim and value
|
||||
|
||||
if (ch == ';' || ch == '}')
|
||||
{
|
||||
// these are good chars for resyncing
|
||||
// so put them back on the stream to
|
||||
// not create subsequent errors
|
||||
this.PutBack();
|
||||
}
|
||||
throw new SyntaxError("Expected <property> : <value>", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
CssValueList value = this.ParseValue();
|
||||
declaration.Value = value;
|
||||
|
||||
return declaration;
|
||||
}
|
||||
|
||||
#endregion Declaration
|
||||
|
||||
#region Value
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) value : [ any | block | ATKEYWORD S* ]+;
|
||||
/// (BNF) any : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
|
||||
/// | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
|
||||
/// | FUNCTION S* any* ')' | DASHMATCH | '(' S* any* ')'
|
||||
/// | '[' S* any* ']' ] S*;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssValueList ParseValue()
|
||||
{
|
||||
CssValueList value = new CssValueList();
|
||||
char ch;
|
||||
|
||||
while (this.Read(out ch) && Char.IsWhiteSpace(ch))
|
||||
{
|
||||
// skip whitespace, and empty declarations
|
||||
}
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
case ':':
|
||||
case ';':
|
||||
case '}':
|
||||
{
|
||||
throw new SyntaxError("Invalid char in CSS property value: '" + ch + "'", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
}
|
||||
|
||||
// read value, starting with current char
|
||||
int start = this.Position;
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
// consume declaration value
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
//case ':':// leave in for "filter: progid:DXImageTransform.Microsoft..."
|
||||
{
|
||||
throw new SyntaxError("Invalid CSS property value: " + this.Copy(start), this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
case '}':
|
||||
case ';':
|
||||
{
|
||||
//Should this parse the value further?
|
||||
|
||||
CssString any = new CssString();
|
||||
any.Value = this.Copy(start);
|
||||
value.Values.Add(any);
|
||||
if (ch == '}')
|
||||
{
|
||||
this.PutBack();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new UnexpectedEndOfFile("Unclosed declaration", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
#endregion Value
|
||||
|
||||
#endregion Parse Methods
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
this.StyleSheet.Write(writer, options);
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region Reader Methods
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ch"></param>
|
||||
/// <returns>Success</returns>
|
||||
private bool Read(out char ch)
|
||||
{
|
||||
if (this.reader.EndOfFile)
|
||||
{
|
||||
throw new UnexpectedEndOfFile("Unexpected end of file", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
int c = this.reader.Read();
|
||||
if (c < 0)
|
||||
{
|
||||
ch = '\0';
|
||||
return false;
|
||||
}
|
||||
ch = (char)c;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies chars from start until the position before the current position
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string Copy(int start)
|
||||
{
|
||||
// read block
|
||||
return this.reader.Copy(start, this.reader.Position - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Put one character back
|
||||
/// </summary>
|
||||
private void PutBack()
|
||||
{
|
||||
this.reader.PutBack();
|
||||
}
|
||||
|
||||
#endregion Reader Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
#region Base Types
|
||||
|
||||
/// <summary>
|
||||
/// CSS3 inconsistently specifies more than one grammar:
|
||||
/// http://www.w3.org/TR/css3-syntax/#style
|
||||
/// http://www.w3.org/TR/css3-syntax/#detailed-grammar
|
||||
/// </summary>
|
||||
internal abstract class CssSyntax
|
||||
{
|
||||
#region Methods
|
||||
|
||||
public abstract void Write(TextWriter writer, CssCompactor.Options options);
|
||||
|
||||
protected static bool IsPrettyPrint(CssCompactor.Options options)
|
||||
{
|
||||
return (options & CssCompactor.Options.PrettyPrint) > 0;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region Object Overrides
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var writer = new StringWriter();
|
||||
|
||||
this.Write(writer, CssCompactor.Options.PrettyPrint);
|
||||
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
#endregion Object Overrides
|
||||
}
|
||||
|
||||
internal interface ICssValue
|
||||
{
|
||||
#region Methods
|
||||
|
||||
void Write(TextWriter writer, CssCompactor.Options options);
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssString : CssSyntax
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private string value;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public virtual string Value
|
||||
{
|
||||
get { return this.value; }
|
||||
set { this.value = value; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
writer.Write(this.Value);
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
#endregion Base Types
|
||||
|
||||
#region Grammar
|
||||
|
||||
internal class CssStyleSheet : CssSyntax
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<CssStatement> statements = new List<CssStatement>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<CssStatement> Statements
|
||||
{
|
||||
get { return this.statements; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
|
||||
foreach (CssStatement statement in this.statements)
|
||||
{
|
||||
statement.Write(writer, options);
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal abstract class CssStatement : CssSyntax, ICssValue
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: each at-rule might parse differently according to CSS3
|
||||
/// The @media block for example contains a block of statements
|
||||
/// while other at-rules with a block contain a block of declarations
|
||||
/// </remarks>
|
||||
internal class CssAtRule : CssStatement
|
||||
{
|
||||
#region Constants
|
||||
|
||||
internal const string MediaIdent = "media";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Fields
|
||||
|
||||
private string ident;
|
||||
private string value;
|
||||
|
||||
private CssBlock block;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public string Ident
|
||||
{
|
||||
get { return this.ident; }
|
||||
set { this.ident = value; }
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
get { return this.value; }
|
||||
set { this.value = value; }
|
||||
}
|
||||
|
||||
public CssBlock Block
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.block == null)
|
||||
{
|
||||
this.block = new CssBlock();
|
||||
}
|
||||
return this.block;
|
||||
}
|
||||
set { this.block = value; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
|
||||
writer.Write('@');
|
||||
writer.Write(this.ident);
|
||||
|
||||
if (!String.IsNullOrEmpty(this.value))
|
||||
{
|
||||
writer.Write(' ');
|
||||
writer.Write(this.value);
|
||||
}
|
||||
|
||||
if (this.block != null)
|
||||
{
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
this.block.Write(writer, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(';');
|
||||
}
|
||||
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssBlock : CssSyntax, ICssValue
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<ICssValue> values = new List<ICssValue>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<ICssValue> Values
|
||||
{
|
||||
get { return this.values; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
|
||||
writer.Write('{');
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
foreach (ICssValue value in this.Values)
|
||||
{
|
||||
value.Write(writer, options);
|
||||
}
|
||||
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
writer.Write('}');
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssRuleSet : CssStatement
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<CssSelector> selectors = new List<CssSelector>();
|
||||
private readonly List<CssDeclaration> declarations = new List<CssDeclaration>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<CssSelector> Selectors
|
||||
{
|
||||
get { return this.selectors; }
|
||||
}
|
||||
|
||||
public List<CssDeclaration> Declarations
|
||||
{
|
||||
get { return this.declarations; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
|
||||
bool comma = false;
|
||||
|
||||
foreach (CssString selector in this.Selectors)
|
||||
{
|
||||
if (comma)
|
||||
{
|
||||
writer.Write(",");
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
comma = true;
|
||||
}
|
||||
|
||||
selector.Write(writer, options);
|
||||
}
|
||||
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
writer.Write("{");
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
foreach (CssDeclaration dec in this.Declarations)
|
||||
{
|
||||
dec.Write(writer, options);
|
||||
}
|
||||
|
||||
writer.Write("}");
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssSelector : CssString
|
||||
{
|
||||
}
|
||||
|
||||
internal class CssDeclaration : CssSyntax, ICssValue
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private string property;
|
||||
private CssValueList value;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public string Property
|
||||
{
|
||||
get { return this.property; }
|
||||
set { this.property = value; }
|
||||
}
|
||||
|
||||
public CssValueList Value
|
||||
{
|
||||
get { return this.value; }
|
||||
set { this.value = value; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.Write('\t');
|
||||
}
|
||||
writer.Write(this.Property);
|
||||
writer.Write(':');
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.Write(" ");
|
||||
}
|
||||
this.Value.Write(writer, options);
|
||||
writer.Write(";");
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssValueList : CssSyntax
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<CssString> values = new List<CssString>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<CssString> Values
|
||||
{
|
||||
get { return this.values; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool space = false;
|
||||
|
||||
foreach (CssString value in this.Values)
|
||||
{
|
||||
if (space)
|
||||
{
|
||||
writer.Write(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
space = true;
|
||||
}
|
||||
|
||||
value.Write(writer, options);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
#endregion Grammar
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal class FileUtility
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private static readonly char[] IllegalChars;
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Init
|
||||
|
||||
static FileUtility()
|
||||
{
|
||||
var chars = new List<char>(Path.GetInvalidPathChars());
|
||||
foreach (char ch in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
if (!chars.Contains(ch) && ch != Path.DirectorySeparatorChar)
|
||||
{
|
||||
chars.Add(ch);
|
||||
}
|
||||
}
|
||||
IllegalChars = chars.ToArray();
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Makes sure directory exists and if file exists is not readonly.
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns>if valid path</returns>
|
||||
internal static bool PrepSavePath(string filename)
|
||||
{
|
||||
if (System.IO.File.Exists(filename))
|
||||
{
|
||||
// make sure not readonly
|
||||
FileAttributes attributes = System.IO.File.GetAttributes(filename);
|
||||
attributes &= ~FileAttributes.ReadOnly;
|
||||
System.IO.File.SetAttributes(filename, attributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
string dir = Path.GetDirectoryName(filename);
|
||||
if (!String.IsNullOrEmpty(dir) && dir.IndexOfAny(IllegalChars) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!String.IsNullOrEmpty(dir) && !Directory.Exists(dir))
|
||||
{
|
||||
// make sure path exists
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
string file = Path.GetFileName(filename);
|
||||
if (!String.IsNullOrEmpty(file) && file.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a character sequence to filter out when reading.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the sequence exists in the read source, it will be read out as if it was never there.
|
||||
/// </remarks>
|
||||
internal struct ReadFilter
|
||||
{
|
||||
#region Fields
|
||||
|
||||
public readonly string StartToken;
|
||||
public readonly string EndToken;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
public ReadFilter(string start, string end)
|
||||
{
|
||||
if (String.IsNullOrEmpty(start))
|
||||
{
|
||||
throw new ArgumentNullException("start");
|
||||
}
|
||||
if (String.IsNullOrEmpty(end))
|
||||
{
|
||||
throw new ArgumentNullException("end");
|
||||
}
|
||||
|
||||
this.StartToken = start;
|
||||
this.EndToken = end;
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Trie out of ReadFilters
|
||||
/// </summary>
|
||||
internal class FilterTrie : TrieNode<char, string>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const int DefaultTrieWidth = 1;
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Init
|
||||
|
||||
internal FilterTrie(IEnumerable<ReadFilter> filters)
|
||||
: base(DefaultTrieWidth)
|
||||
{
|
||||
// load trie
|
||||
foreach (ReadFilter filter in filters)
|
||||
{
|
||||
TrieNode<char, string> node = this;
|
||||
|
||||
// build out the path for StartToken
|
||||
foreach (char ch in filter.StartToken)
|
||||
{
|
||||
if (!node.Contains(ch))
|
||||
{
|
||||
node[ch] = new TrieNode<char, string>(DefaultTrieWidth);
|
||||
}
|
||||
|
||||
node = (TrieNode<char, string>)node[ch];
|
||||
}
|
||||
|
||||
// at the end of StartToken path is the EndToken
|
||||
node.Value = filter.EndToken;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal class LineReader : TextReader
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private int line = 1;
|
||||
private int column = 0;
|
||||
private int position = -1;
|
||||
|
||||
private string filePath;
|
||||
private string source;
|
||||
|
||||
private readonly FilterTrie trie;
|
||||
|
||||
private bool normalizeWhiteSpace = false;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="filters"></param>
|
||||
internal LineReader(string filePath, IEnumerable<ReadFilter> filters) : this(filePath, null, filters) { }
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="filters"></param>
|
||||
internal LineReader(string filePath, string source, IEnumerable<ReadFilter> filters)
|
||||
{
|
||||
this.trie = new FilterTrie(filters);
|
||||
this.source = source;
|
||||
this.filePath = filePath;
|
||||
|
||||
if (this.source == null)
|
||||
{
|
||||
this.source = filePath;//Changed to direct content string instead of file.
|
||||
/*if (System.IO.File.Exists(filePath))
|
||||
{
|
||||
this.source = System.IO.File.ReadAllText(filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileError("File not found", filePath, 0, 0);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="source"></param>
|
||||
internal LineReader(string filePath, string source)
|
||||
: this(filePath, source, new ReadFilter[0])
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the source file
|
||||
/// </summary>
|
||||
public string FilePath
|
||||
{
|
||||
get { return this.filePath; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of source file in chars
|
||||
/// </summary>
|
||||
public int Length
|
||||
{
|
||||
get { return this.source.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current line number
|
||||
/// </summary>
|
||||
public int Line
|
||||
{
|
||||
get { return this.line; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current col number
|
||||
/// </summary>
|
||||
public int Column
|
||||
{
|
||||
get { return this.column; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current char position
|
||||
/// </summary>
|
||||
public int Position
|
||||
{
|
||||
get { return this.position; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets if at end the end of file
|
||||
/// </summary>
|
||||
public bool EndOfFile
|
||||
{
|
||||
get { return this.position >= this.source.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets if whitespace is normalized while reading
|
||||
/// </summary>
|
||||
public bool NormalizeWhiteSpace
|
||||
{
|
||||
get { return this.normalizeWhiteSpace; }
|
||||
set { this.normalizeWhiteSpace = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current char
|
||||
/// </summary>
|
||||
public int Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.EndOfFile)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return this.source[this.position];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region TextReader Members
|
||||
|
||||
/// <summary>
|
||||
/// Unfiltered look ahead
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int Peek()
|
||||
{
|
||||
return this.Peek(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filtered read of the next source char. Counters are incremented.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// NewLine sequences (CR/LF, LF, CR) are normalized to LF.
|
||||
/// </remarks>
|
||||
public override int Read()
|
||||
{
|
||||
return this.Read(true);
|
||||
}
|
||||
|
||||
#endregion TextReader Members
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
/// <summary>
|
||||
/// Backs the current position up one.
|
||||
/// </summary>
|
||||
public void PutBack()
|
||||
{
|
||||
if (this.position < 0)
|
||||
{
|
||||
throw new InvalidOperationException("Already at start of source");
|
||||
}
|
||||
switch (this.source[this.position])
|
||||
{
|
||||
case '\r': //CR
|
||||
{
|
||||
// manipulate CR/LF as one char
|
||||
if ((this.position + 1 < this.Length) && this.source[this.position + 1] == '\n')
|
||||
{
|
||||
this.position--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '\n': //LF
|
||||
case '\f': //FF
|
||||
{
|
||||
this.line--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.column--;
|
||||
this.position--;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies a range from the source
|
||||
/// </summary>
|
||||
/// <param name="start">starting position, inclusive</param>
|
||||
/// <param name="end">ending position, inclusive</param>
|
||||
/// <returns></returns>
|
||||
public string Copy(int start, int end)
|
||||
{
|
||||
if (start < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("start");
|
||||
}
|
||||
if (end < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("end");
|
||||
}
|
||||
if (end < 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// set to just before read, next char is start
|
||||
int copyPosition = start - 1;
|
||||
|
||||
// allocate the full range but may not use due to filtering
|
||||
char[] buffer = new char[end - start + 1];
|
||||
|
||||
int count = 0;
|
||||
while (copyPosition < end)
|
||||
{
|
||||
int ch = this.CopyRead(ref copyPosition);
|
||||
if (ch == -1)
|
||||
{
|
||||
throw new UnexpectedEndOfFile("Read past end of file", this.FilePath, this.Line, this.Column);
|
||||
}
|
||||
buffer[count] = (char)ch;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new String(buffer, 0, count).Trim();
|
||||
}
|
||||
|
||||
#endregion Utility Methods
|
||||
|
||||
#region Filter Methods
|
||||
|
||||
/// <summary>
|
||||
/// Peeks with n chars of lookahead.
|
||||
/// </summary>
|
||||
/// <param name="lookahead"></param>
|
||||
/// <returns>unfiltered read</returns>
|
||||
protected int Peek(int lookahead)
|
||||
{
|
||||
int pos = this.position + lookahead;
|
||||
if (pos >= this.source.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return this.source[pos];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next char
|
||||
/// </summary>
|
||||
/// <param name="filter">if filtering</param>
|
||||
/// <returns>the next char, or -1 if at EOF</returns>
|
||||
protected int Read(bool filter)
|
||||
{
|
||||
if (this.position + 1 >= this.source.Length)
|
||||
{
|
||||
this.position = this.source.Length;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// increment counters
|
||||
this.position++;
|
||||
this.column++;
|
||||
char ch = this.source[this.position];
|
||||
|
||||
if (Char.IsWhiteSpace(ch))
|
||||
{
|
||||
ch = this.NormalizeSpaces(ch, ref this.position, ref this.line, ref this.column);
|
||||
}
|
||||
|
||||
return filter ? this.Filter(ch) : ch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalized CR/CRLF/LF/FF to LF, or all whitespace to SPACE if NormalizeWhiteSpace is true
|
||||
/// </summary>
|
||||
/// <param name="ch"></param>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="col"></param>
|
||||
/// <returns></returns>
|
||||
private char NormalizeSpaces(char ch, ref int pos, ref int line, ref int col)
|
||||
{
|
||||
int length = this.source.Length;
|
||||
if (this.normalizeWhiteSpace)
|
||||
{
|
||||
// normalize runs of WhiteSpace to ' '
|
||||
while ((pos + 1 < length) && Char.IsWhiteSpace(this.source, pos + 1))
|
||||
{
|
||||
pos++;
|
||||
col++;
|
||||
|
||||
// increment line count
|
||||
switch (this.source[pos])
|
||||
{
|
||||
case '\r': //CR
|
||||
{
|
||||
// manipulate CR/LF as one char
|
||||
if ((pos + 1 < length) && this.source[pos + 1] == '\n')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
goto case '\n';
|
||||
}
|
||||
case '\n': //LF
|
||||
case '\f': //FF
|
||||
{
|
||||
line++;
|
||||
col = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ch = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
// normalize NewLines to '\n', increment line count
|
||||
switch (ch)
|
||||
{
|
||||
case '\r': //CR
|
||||
{
|
||||
// manipulate CR/LF as one char
|
||||
if ((pos + 1 < length) && this.source[pos + 1] == '\n')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
goto case '\n';
|
||||
}
|
||||
case '\n': //LF
|
||||
case '\f': //FF
|
||||
{
|
||||
line++;
|
||||
col = 0;
|
||||
ch = '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read for Copying (doesn't reset line.col counters)
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
protected int CopyRead(ref int copyPosition)
|
||||
{
|
||||
if (copyPosition + 1 >= this.source.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// increment counters
|
||||
copyPosition++;
|
||||
char ch = this.source[copyPosition];
|
||||
|
||||
if (Char.IsWhiteSpace(ch))
|
||||
{
|
||||
int dummyLine = 0, dummyCol = 0;
|
||||
ch = this.NormalizeSpaces(ch, ref copyPosition, ref dummyLine, ref dummyCol);
|
||||
}
|
||||
|
||||
return this.Filter(ch);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters based upon an internal Trie
|
||||
/// </summary>
|
||||
/// <param name="ch"></param>
|
||||
/// <returns></returns>
|
||||
private int Filter(char ch)
|
||||
{
|
||||
int lookAhead = 0;
|
||||
ITrieNode<char, string> node = this.trie[ch];
|
||||
|
||||
while (node != null)
|
||||
{
|
||||
if (node.HasValue)
|
||||
{
|
||||
// found StartToken
|
||||
string endToken = node.Value;
|
||||
int length = endToken.Length;
|
||||
|
||||
// move to end of StartToken
|
||||
this.position += lookAhead;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int ch2 = this.Read(false);
|
||||
if (ch < 0)
|
||||
{
|
||||
throw new UnexpectedEndOfFile("Expected " + endToken, this.FilePath, this.Line, this.Column);
|
||||
}
|
||||
if (ch2 != endToken[i])
|
||||
{
|
||||
// reset search
|
||||
while (i > 0)
|
||||
{
|
||||
i--;
|
||||
this.PutBack();
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return this.Read(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
lookAhead++;
|
||||
int pk = this.Peek(lookAhead);
|
||||
if (pk < 0)
|
||||
{
|
||||
return ch;
|
||||
}
|
||||
node = node[(char)pk];
|
||||
}
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#endregion Filter Methods
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Free source resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
this.source = null;
|
||||
}
|
||||
|
||||
#endregion IDisposable Members
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal enum ParseExceptionType
|
||||
{
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal abstract class ParseException : ApplicationException
|
||||
{
|
||||
#region Constants
|
||||
|
||||
// this cannot change every char is important or Visual Studio will not list as error/warning
|
||||
// http://blogs.msdn.com/msbuild/archive/2006/11/03/msbuild-visual-studio-aware-error-messages-and-message-formats.aspx
|
||||
private const string MSBuildErrorFormat = "{0}({1},{2}): {3} {4}: {5}";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Fields
|
||||
|
||||
private string file;
|
||||
private int line;
|
||||
private int column;
|
||||
private int code = 0;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
public ParseException(string message, string file, int line, int column)
|
||||
: base(message)
|
||||
{
|
||||
this.file = file;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public ParseException(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
this.file = file;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public abstract ParseExceptionType Type
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public virtual int Code
|
||||
{
|
||||
get { return this.code; }
|
||||
}
|
||||
|
||||
public string ErrorCode
|
||||
{
|
||||
get
|
||||
{
|
||||
string ext = System.IO.Path.GetExtension(file);
|
||||
if (ext == null || ext.Length < 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ext.Substring(1).ToUpperInvariant() + this.Code.ToString("####0000");
|
||||
}
|
||||
}
|
||||
|
||||
public string File
|
||||
{
|
||||
get { return this.file; }
|
||||
}
|
||||
|
||||
public int Line
|
||||
{
|
||||
get { return this.line; }
|
||||
}
|
||||
|
||||
public int Column
|
||||
{
|
||||
get { return this.column; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public virtual string GetCompilerMessage()
|
||||
{
|
||||
return this.GetCompilerMessage(this.Type == ParseExceptionType.Warning);
|
||||
}
|
||||
|
||||
public virtual string GetCompilerMessage(bool isWarning)
|
||||
{
|
||||
// format exception as a VS2005 error/warning
|
||||
return String.Format(
|
||||
ParseException.MSBuildErrorFormat,
|
||||
this.File,
|
||||
(this.Line > 0) ? this.Line : 1,
|
||||
(this.Column > 0) ? this.Column : 1,
|
||||
isWarning ? "warning" : "error",
|
||||
this.ErrorCode,
|
||||
this.Message);
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class ParseWarning : ParseException
|
||||
{
|
||||
#region Init
|
||||
|
||||
public ParseWarning(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public ParseWarning(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public override ParseExceptionType Type
|
||||
{
|
||||
get { return ParseExceptionType.Warning; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class ParseError : ParseException
|
||||
{
|
||||
#region Init
|
||||
|
||||
public ParseError(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public ParseError(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public override ParseExceptionType Type
|
||||
{
|
||||
get { return ParseExceptionType.Error; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class UnexpectedEndOfFile : ParseError
|
||||
{
|
||||
#region Init
|
||||
|
||||
public UnexpectedEndOfFile(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public UnexpectedEndOfFile(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class FileError : ParseWarning
|
||||
{
|
||||
#region Init
|
||||
|
||||
public FileError(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public FileError(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class SyntaxError : ParseError
|
||||
{
|
||||
#region Init
|
||||
|
||||
public SyntaxError(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public SyntaxError(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic node for building a Trie
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">the Type used for the node path</typeparam>
|
||||
/// <typeparam name="TValue">the Type used for the node value</typeparam>
|
||||
/// <remarks>
|
||||
/// http://en.wikipedia.org/wiki/Trie
|
||||
/// </remarks>
|
||||
internal class TrieNode<TKey, TValue> : ITrieNode<TKey, TValue>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly IDictionary<TKey, ITrieNode<TKey, TValue>> Children;
|
||||
private TValue value = default(TValue);
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// </summary>
|
||||
public TrieNode()
|
||||
: this(-1)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="capacity"></param>
|
||||
public TrieNode(int capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
{
|
||||
this.Children = new Dictionary<TKey, ITrieNode<TKey, TValue>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Children = new Dictionary<TKey, ITrieNode<TKey, TValue>>(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public ITrieNode<TKey, TValue> this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.Children.ContainsKey(key))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return this.Children[key];
|
||||
}
|
||||
|
||||
// added "internal" to get around change in C# 3.0 modifiers
|
||||
// this worked fine in C# 2.0 but they fixed that bug
|
||||
// http://blogs.msdn.com/ericlippert/archive/2008/03/28/why-can-t-i-access-a-protected-member-from-a-derived-class-part-two-why-can-i.aspx
|
||||
protected internal set { this.Children[key] = value; }
|
||||
}
|
||||
|
||||
public TValue Value
|
||||
{
|
||||
get { return this.value; }
|
||||
|
||||
// added "internal" to get around change in C# 3.0 modifiers
|
||||
// this worked fine in C# 2.0 but they fixed that bug
|
||||
// http://blogs.msdn.com/ericlippert/archive/2008/03/28/why-can-t-i-access-a-protected-member-from-a-derived-class-part-two-why-can-i.aspx
|
||||
protected internal set
|
||||
{
|
||||
if (!EqualityComparer<TValue>.Default.Equals(this.value, default(TValue)))
|
||||
{
|
||||
throw new InvalidOperationException("Trie path collision: the value for TrieNode<" + value.GetType().Name + "> has already been assigned.");
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return !EqualityComparer<TValue>.Default.Equals(this.value, default(TValue));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Determines if child exists
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(TKey key)
|
||||
{
|
||||
return this.Children.ContainsKey(key);
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal interface ITrieNode<TKey, TValue>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
ITrieNode<TKey, TValue> this[TKey key]
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
TValue Value
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
bool HasValue
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region Methods
|
||||
|
||||
bool Contains(TKey key);
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ namespace Umbraco.Core.Models
|
||||
private DataTypeDatabaseType _databaseType;
|
||||
|
||||
[Obsolete("Property editor's are defined by a string alias from version 7 onwards, use the alternative contructor that specifies an alias")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public DataTypeDefinition(int parentId, Guid controlId)
|
||||
{
|
||||
_parentId = parentId;
|
||||
@@ -48,9 +47,6 @@ namespace Umbraco.Core.Models
|
||||
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
[Obsolete("Don't use this, parentId is always -1 for data types")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public DataTypeDefinition(int parentId, string propertyEditorAlias)
|
||||
{
|
||||
_parentId = parentId;
|
||||
@@ -59,14 +55,6 @@ namespace Umbraco.Core.Models
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public DataTypeDefinition(string propertyEditorAlias)
|
||||
{
|
||||
_parentId = -1;
|
||||
_propertyEditorAlias = propertyEditorAlias;
|
||||
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<DataTypeDefinition, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<DataTypeDefinition, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<DataTypeDefinition, int>(x => x.SortOrder);
|
||||
|
||||
@@ -7,6 +7,25 @@ using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to attribute properties that have a setter and are a reference type
|
||||
/// that should be ignored for cloning when using the DeepCloneHelper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// This attribute must be used:
|
||||
/// * when the property is backed by a field but the result of the property is the un-natural data stored in the field
|
||||
///
|
||||
/// This attribute should not be used:
|
||||
/// * when the property is virtual
|
||||
/// * when the setter performs additional required logic other than just setting the underlying field
|
||||
///
|
||||
/// </remarks>
|
||||
internal class DoNotCloneAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static class DeepCloneHelper
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Models
|
||||
private IEnumerable<IDictionaryTranslation> _translations;
|
||||
|
||||
public DictionaryItem(string itemKey)
|
||||
: this(new Guid(Constants.Conventions.Localization.DictionaryItemRootId), itemKey)
|
||||
: this(new Guid("41c7638d-f529-4bff-853e-59a0c2fb1bde"), itemKey)
|
||||
{}
|
||||
|
||||
public DictionaryItem(Guid parentId, string itemKey)
|
||||
@@ -99,7 +99,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
//If ParentId is not set we should default to the root parent id
|
||||
if(ParentId == Guid.Empty)
|
||||
_parentId = new Guid(Constants.Conventions.Localization.DictionaryItemRootId);
|
||||
_parentId = new Guid("41c7638d-f529-4bff-853e-59a0c2fb1bde");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,14 +18,12 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public DictionaryTranslation(ILanguage language, string value)
|
||||
{
|
||||
if (language == null) throw new ArgumentNullException("language");
|
||||
_language = language;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public DictionaryTranslation(ILanguage language, string value, Guid uniqueId)
|
||||
{
|
||||
if (language == null) throw new ArgumentNullException("language");
|
||||
_language = language;
|
||||
_value = value;
|
||||
Key = uniqueId;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to attribute properties that have a setter and are a reference type
|
||||
/// that should be ignored for cloning when using the DeepCloneHelper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// This attribute must be used:
|
||||
/// * when the property is backed by a field but the result of the property is the un-natural data stored in the field
|
||||
///
|
||||
/// This attribute should not be used:
|
||||
/// * when the property is virtual
|
||||
/// * when the setter performs additional required logic other than just setting the underlying field
|
||||
///
|
||||
/// </remarks>
|
||||
internal class DoNotCloneAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -14,13 +14,11 @@ namespace Umbraco.Core.Models
|
||||
public abstract class File : Entity, IFile
|
||||
{
|
||||
private string _path;
|
||||
private string _originalPath;
|
||||
private string _content = string.Empty; //initialize to empty string, not null
|
||||
|
||||
protected File(string path)
|
||||
{
|
||||
_path = path;
|
||||
_originalPath = _path;
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo<File, string>(x => x.Content);
|
||||
@@ -34,7 +32,14 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
public virtual string Name
|
||||
{
|
||||
get { return _name ?? (_name = System.IO.Path.GetFileName(Path)); }
|
||||
get
|
||||
{
|
||||
if (_name == null)
|
||||
{
|
||||
_name = System.IO.Path.GetFileName(Path);
|
||||
}
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -77,22 +82,6 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the original path of the file
|
||||
/// </summary>
|
||||
public string OriginalPath
|
||||
{
|
||||
get { return _originalPath; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to re-set the OriginalPath to the Path
|
||||
/// </summary>
|
||||
public void ResetOriginalPath()
|
||||
{
|
||||
_originalPath = _path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Content of a File
|
||||
/// </summary>
|
||||
@@ -115,11 +104,11 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public string VirtualPath { get; set; }
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in future versions")]
|
||||
public virtual bool IsValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the file could be validated
|
||||
/// </summary>
|
||||
/// <returns>True if file is valid, otherwise false</returns>
|
||||
public abstract bool IsValid();
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
|
||||
@@ -20,7 +20,12 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
bool Published { get; }
|
||||
|
||||
[Obsolete("This will be removed in future versions")]
|
||||
/// <summary>
|
||||
/// Language of the data contained within this Content object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Left internal until multilingual support is implemented.
|
||||
/// </remarks>
|
||||
string Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -73,15 +78,5 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IContent DeepCloneWithResetIdentities();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content has a published version.
|
||||
/// </summary>
|
||||
bool HasPublishedVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique identifier of the published version, if any.
|
||||
/// </summary>
|
||||
Guid PublishedVersionGuid { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IDomain : IAggregateRoot, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
ILanguage Language { get; set; }
|
||||
string DomainName { get; set; }
|
||||
IContent RootContent { get; set; }
|
||||
bool IsWildcard { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -24,16 +23,6 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the original path of the file
|
||||
/// </summary>
|
||||
string OriginalPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called to re-set the OriginalPath to the Path
|
||||
/// </summary>
|
||||
void ResetOriginalPath();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Content of a File
|
||||
/// </summary>
|
||||
@@ -44,7 +33,10 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
string VirtualPath { get; set; }
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in future versions")]
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the file could be validated
|
||||
/// </summary>
|
||||
/// <returns>True if file is valid, otherwise false</returns>
|
||||
bool IsValid();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -9,31 +7,10 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public interface ITemplate : IFile, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Name of the File including extension
|
||||
/// </summary>
|
||||
new string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Alias of the File, which is the name without the extension
|
||||
/// </summary>
|
||||
new string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the template is used as a layout for other templates (i.e. it has 'children')
|
||||
/// </summary>
|
||||
bool IsMasterTemplate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// returns the master template alias
|
||||
/// </summary>
|
||||
string MasterTemplateAlias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="RenderingEngine"/> that corresponds to the template file
|
||||
/// </summary>
|
||||
/// <returns><see cref="RenderingEngine"/></returns>
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in future versions, use the IFileSystem DetermineRenderingEngine method instead")]
|
||||
RenderingEngine GetTypeOfRenderingEngine();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
public class BackOfficeIdentityUser : IdentityUser<int, IIdentityUserLogin, IdentityUserRole<string>, IdentityUserClaim<int>>
|
||||
{
|
||||
|
||||
public virtual async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager manager)
|
||||
{
|
||||
// NOTE the authenticationType must match the umbraco one
|
||||
// defined in CookieAuthenticationOptions.AuthenticationType
|
||||
var userIdentity = await manager.CreateIdentityAsync(this, Constants.Security.BackOfficeAuthenticationType);
|
||||
return userIdentity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the user's real name
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public int StartContentId { get; set; }
|
||||
public int StartMediaId { get; set; }
|
||||
public string[] AllowedSections { get; set; }
|
||||
public string Culture { get; set; }
|
||||
|
||||
public string UserTypeAlias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Overridden to make the retrieval lazy
|
||||
/// </summary>
|
||||
public override ICollection<IIdentityUserLogin> Logins
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_getLogins != null && _getLogins.IsValueCreated == false)
|
||||
{
|
||||
_logins = new ObservableCollection<IIdentityUserLogin>();
|
||||
foreach (var l in _getLogins.Value)
|
||||
{
|
||||
_logins.Add(l);
|
||||
}
|
||||
//now assign events
|
||||
_logins.CollectionChanged += Logins_CollectionChanged;
|
||||
}
|
||||
return _logins;
|
||||
}
|
||||
}
|
||||
|
||||
public bool LoginsChanged { get; private set; }
|
||||
|
||||
void Logins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
LoginsChanged = true;
|
||||
}
|
||||
|
||||
private ObservableCollection<IIdentityUserLogin> _logins;
|
||||
private Lazy<IEnumerable<IIdentityUserLogin>> _getLogins;
|
||||
|
||||
/// <summary>
|
||||
/// Used to set a lazy call back to populate the user's Login list
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
public void SetLoginsCallback(Lazy<IEnumerable<IIdentityUserLogin>> callback)
|
||||
{
|
||||
if (callback == null) throw new ArgumentNullException("callback");
|
||||
_getLogins = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
public interface IIdentityUserLogin : IAggregateRoot, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// The login provider for the login (i.e. facebook, google)
|
||||
///
|
||||
/// </summary>
|
||||
string LoginProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key representing the login for the provider
|
||||
///
|
||||
/// </summary>
|
||||
string ProviderKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this login
|
||||
///
|
||||
/// </summary>
|
||||
int UserId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
public class IdentityModelMappings : MapperConfiguration
|
||||
{
|
||||
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
|
||||
{
|
||||
config.CreateMap<IUser, BackOfficeIdentityUser>()
|
||||
.ForMember(user => user.Email, expression => expression.MapFrom(user => user.Email))
|
||||
.ForMember(user => user.Id, expression => expression.MapFrom(user => user.Id))
|
||||
.ForMember(user => user.LockoutEnabled, expression => expression.MapFrom(user => user.IsLockedOut))
|
||||
.ForMember(user => user.LockoutEndDateUtc, expression => expression.UseValue(DateTime.MaxValue.ToUniversalTime()))
|
||||
.ForMember(user => user.UserName, expression => expression.MapFrom(user => user.Username))
|
||||
.ForMember(user => user.PasswordHash, expression => expression.MapFrom(user => GetPasswordHash(user.RawPasswordValue)))
|
||||
.ForMember(user => user.Culture, expression => expression.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
|
||||
.ForMember(user => user.Name, expression => expression.MapFrom(user => user.Name))
|
||||
.ForMember(user => user.StartMediaId, expression => expression.MapFrom(user => user.StartMediaId))
|
||||
.ForMember(user => user.StartContentId, expression => expression.MapFrom(user => user.StartContentId))
|
||||
.ForMember(user => user.UserTypeAlias, expression => expression.MapFrom(user => user.UserType.Alias))
|
||||
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()));
|
||||
}
|
||||
|
||||
private string GetPasswordHash(string storedPass)
|
||||
{
|
||||
return storedPass.StartsWith("___UIDEMPTYPWORD__") ? null : storedPass;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Identity;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Default IUser implementation
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"/><typeparam name="TLogin"/><typeparam name="TRole"/><typeparam name="TClaim"/>
|
||||
/// <remarks>
|
||||
/// This class normally exists inside of the EntityFramework library, not sure why MS chose to explicitly put it there but we don't want
|
||||
/// references to that so we will create our own here
|
||||
/// </remarks>
|
||||
public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
|
||||
where TLogin : IIdentityUserLogin
|
||||
//NOTE: Making our role id a string
|
||||
where TRole : IdentityUserRole<string>
|
||||
where TClaim : IdentityUserClaim<TKey>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
///
|
||||
/// </summary>
|
||||
public IdentityUser()
|
||||
{
|
||||
this.Claims = new List<TClaim>();
|
||||
this.Roles = new List<TRole>();
|
||||
this.Logins = new List<TLogin>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Email
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the email is confirmed, default is false
|
||||
///
|
||||
/// </summary>
|
||||
public virtual bool EmailConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The salted/hashed form of the user password
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string PasswordHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A random value that should change whenever a users credentials have changed (password changed, login removed)
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string SecurityStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PhoneNumber for the user
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string PhoneNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the phone number is confirmed, default is false
|
||||
///
|
||||
/// </summary>
|
||||
public virtual bool PhoneNumberConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is two factor enabled for the user
|
||||
///
|
||||
/// </summary>
|
||||
public virtual bool TwoFactorEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DateTime in UTC when lockout ends, any time in the past is considered not locked out.
|
||||
///
|
||||
/// </summary>
|
||||
public virtual DateTime? LockoutEndDateUtc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is lockout enabled for this user
|
||||
///
|
||||
/// </summary>
|
||||
public virtual bool LockoutEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to record failures for the purposes of lockout
|
||||
///
|
||||
/// </summary>
|
||||
public virtual int AccessFailedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for user roles
|
||||
///
|
||||
/// </summary>
|
||||
public virtual ICollection<TRole> Roles { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for user claims
|
||||
///
|
||||
/// </summary>
|
||||
public virtual ICollection<TClaim> Claims { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for user logins
|
||||
///
|
||||
/// </summary>
|
||||
public virtual ICollection<TLogin> Logins { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// User ID (Primary Key)
|
||||
///
|
||||
/// </summary>
|
||||
public virtual TKey Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User name
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string UserName { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityType that represents one specific user claim
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"/>
|
||||
/// <remarks>
|
||||
/// This class normally exists inside of the EntityFramework library, not sure why MS chose to explicitly put it there but we don't want
|
||||
/// references to that so we will create our own here
|
||||
/// </remarks>
|
||||
public class IdentityUserClaim<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// Primary key
|
||||
///
|
||||
/// </summary>
|
||||
public virtual int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this login
|
||||
///
|
||||
/// </summary>
|
||||
public virtual TKey UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Claim type
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string ClaimType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Claim value
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string ClaimValue { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity type for a user's login (i.e. facebook, google)
|
||||
///
|
||||
/// </summary>
|
||||
public class IdentityUserLogin : Entity, IIdentityUserLogin
|
||||
{
|
||||
public IdentityUserLogin(string loginProvider, string providerKey, int userId)
|
||||
{
|
||||
LoginProvider = loginProvider;
|
||||
ProviderKey = providerKey;
|
||||
UserId = userId;
|
||||
}
|
||||
|
||||
public IdentityUserLogin(int id, string loginProvider, string providerKey, int userId, DateTime createDate)
|
||||
{
|
||||
Id = id;
|
||||
LoginProvider = loginProvider;
|
||||
ProviderKey = providerKey;
|
||||
UserId = userId;
|
||||
CreateDate = createDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The login provider for the login (i.e. facebook, google)
|
||||
///
|
||||
/// </summary>
|
||||
public string LoginProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key representing the login for the provider
|
||||
///
|
||||
/// </summary>
|
||||
public string ProviderKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this login
|
||||
///
|
||||
/// </summary>
|
||||
public int UserId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityType that represents a user belonging to a role
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"/>
|
||||
/// <remarks>
|
||||
/// This class normally exists inside of the EntityFramework library, not sure why MS chose to explicitly put it there but we don't want
|
||||
/// references to that so we will create our own here
|
||||
/// </remarks>
|
||||
public class IdentityUserRole<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// UserId for the user that is in the role
|
||||
///
|
||||
/// </summary>
|
||||
public virtual TKey UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RoleId for the role
|
||||
///
|
||||
/// </summary>
|
||||
public virtual TKey RoleId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,4 @@ namespace Umbraco.Core.Models.Mapping
|
||||
{
|
||||
public abstract void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user