diff --git a/README.md b/README.md
index 5988cc2a19..5fb4cb868b 100644
--- a/README.md
+++ b/README.md
@@ -15,11 +15,11 @@ If you're interested in making changes to Belle make sure to read the [Belle Rea
**More than 177,000 sites trust Umbraco**
-For the first time on the Microsoft platform a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box. It's a developers dream and your users will love it too.
+For the first time on the Microsoft platform, there is a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box. It's a developer's dream and your users will love it too.
-Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales.
+Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)), you can be sure that the technology is proven, stable and scales.
-To view more examples please visit [http://umbraco.com/why-umbraco/#caseStudies](http://umbraco.com/why-umbraco/#caseStudies)
+To view more examples, please visit [http://umbraco.com/why-umbraco/#caseStudies](http://umbraco.com/why-umbraco/#caseStudies)
## Downloading ##
@@ -35,6 +35,6 @@ If you want to contribute back to Umbraco you should check out our [guide to con
## Found a bug? ##
-Another way you can contribute to Umbraco is by providing issue reports, for information on how to submit an issue report refer to our [online guide for reporting issues](http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature).
+Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature).
-To view existing issues please visit [http://issues.umbraco.org](http://issues.umbraco.org)
+To view existing issues, please visit [http://issues.umbraco.org](http://issues.umbraco.org).
diff --git a/build/Build.bat b/build/Build.bat
index bd18f719ad..1167d9fcb6 100644
--- a/build/Build.bat
+++ b/build/Build.bat
@@ -21,14 +21,6 @@ ECHO Building Umbraco %version%
ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %release%
-ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice
-SET nuGetFolder=%CD%\..\src\packages\
-..\src\.nuget\NuGet.exe sources Remove -Name MyGetUmbracoCore >NUL
-..\src\.nuget\NuGet.exe sources Add -Name MyGetUmbracoCore -Source https://www.myget.org/F/umbracocore/api/v2/ >NUL
-..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
-..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
-..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
-
ECHO Removing the belle build folder and bower_components folder to make sure everything is clean as a whistle
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
RD ..\src\Umbraco.Web.UI.Client\bower_components /Q /S
diff --git a/build/Build.proj b/build/Build.proj
index e937df15bd..9413b49d15 100644
--- a/build/Build.proj
+++ b/build/Build.proj
@@ -175,8 +175,8 @@
diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec
index 686fe16faf..72733c5800 100644
--- a/build/NuSpecs/UmbracoCms.Core.nuspec
+++ b/build/NuSpecs/UmbracoCms.Core.nuspec
@@ -17,7 +17,6 @@
-
@@ -31,14 +30,13 @@
-
+
-
-
+
+
-
-
+
diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec
index 4127ea702e..66e82ac488 100644
--- a/build/NuSpecs/UmbracoCms.nuspec
+++ b/build/NuSpecs/UmbracoCms.nuspec
@@ -16,8 +16,8 @@
umbraco
-
-
+
+
diff --git a/build/NuSpecs/tools/Dashboard.config.install.xdt b/build/NuSpecs/tools/Dashboard.config.install.xdt
index 197f9c1b6f..a77632926c 100644
--- a/build/NuSpecs/tools/Dashboard.config.install.xdt
+++ b/build/NuSpecs/tools/Dashboard.config.install.xdt
@@ -77,4 +77,8 @@
+
+
\ No newline at end of file
diff --git a/build/NuSpecs/tools/Readme.txt b/build/NuSpecs/tools/Readme.txt
index 53d9c3c7da..b6b55c1c4f 100644
--- a/build/NuSpecs/tools/Readme.txt
+++ b/build/NuSpecs/tools/Readme.txt
@@ -10,6 +10,7 @@
Don't forget to build!
+
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
diff --git a/build/NuSpecs/tools/ReadmeUpgrade.txt b/build/NuSpecs/tools/ReadmeUpgrade.txt
index 894f5e5f93..e0d660a795 100644
--- a/build/NuSpecs/tools/ReadmeUpgrade.txt
+++ b/build/NuSpecs/tools/ReadmeUpgrade.txt
@@ -10,6 +10,7 @@
Don't forget to build!
+
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
diff --git a/build/NuSpecs/tools/Web.config.install.xdt b/build/NuSpecs/tools/Web.config.install.xdt
index 1cf886b312..dfb9925840 100644
--- a/build/NuSpecs/tools/Web.config.install.xdt
+++ b/build/NuSpecs/tools/Web.config.install.xdt
@@ -7,8 +7,8 @@
-
-
+
+
@@ -21,8 +21,10 @@
+
+
-
+
@@ -37,7 +39,7 @@
-
+
@@ -48,13 +50,15 @@
-
+
-
+
-
+
+
+
>
@@ -63,8 +67,7 @@
-
+
@@ -78,6 +81,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -86,11 +139,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -125,6 +280,8 @@
+
+
@@ -149,16 +306,14 @@
-
-
-
+
-
+
@@ -171,7 +326,7 @@
-
+
@@ -180,7 +335,7 @@
-
+
@@ -191,12 +346,12 @@
-
+
-
+
@@ -208,16 +363,16 @@
-
+
-
+
-
-
+
+
@@ -225,19 +380,19 @@
-
+
-
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/build/NuSpecs/tools/install.core.ps1 b/build/NuSpecs/tools/install.core.ps1
index ba6416028b..c4f213ba01 100644
--- a/build/NuSpecs/tools/install.core.ps1
+++ b/build/NuSpecs/tools/install.core.ps1
@@ -1,18 +1,30 @@
-param($rootPath, $toolsPath, $package, $project)
+param($installPath, $toolsPath, $package, $project)
+
+Write-Host "installPath:" "${installPath}"
+Write-Host "toolsPath:" "${toolsPath}"
+
+Write-Host " "
if ($project) {
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
- $backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
+
+ # Create paths and list them
+ $projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
+ Write-Host "projectPath:" "${projectPath}"
+ $backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
+ Write-Host "backupPath:" "${backupPath}"
$copyLogsPath = Join-Path $backupPath "CopyLogs"
- $projectDestinationPath = Split-Path $project.FullName -Parent
-
+ Write-Host "copyLogsPath:" "${copyLogsPath}"
+ $umbracoBinFolder = Join-Path $projectPath "bin"
+ Write-Host "umbracoBinFolder:" "${umbracoBinFolder}"
+
# Create backup folder and logs folder if it doesn't exist yet
New-Item -ItemType Directory -Force -Path $backupPath
New-Item -ItemType Directory -Force -Path $copyLogsPath
# After backing up, remove all umbraco dlls from bin folder in case dll files are included in the VS project
# See: http://issues.umbraco.org/issue/U4-4930
- $umbracoBinFolder = Join-Path $projectDestinationPath "bin"
+
if(Test-Path $umbracoBinFolder) {
$umbracoBinBackupPath = Join-Path $backupPath "bin"
@@ -20,7 +32,7 @@ if ($project) {
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
- # Delete files Umbraco brings in
+ # Delete files Umbraco ships with
if(Test-Path $umbracoBinFolder\businesslogic.dll) { Remove-Item $umbracoBinFolder\businesslogic.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\cms.dll) { Remove-Item $umbracoBinFolder\cms.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\controls.dll) { Remove-Item $umbracoBinFolder\controls.dll -Force -Confirm:$false }
@@ -36,16 +48,18 @@ if ($project) {
if(Test-Path $umbracoBinFolder\umbraco.DataLayer.dll) { Remove-Item $umbracoBinFolder\umbraco.DataLayer.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\umbraco.editorControls.dll) { Remove-Item $umbracoBinFolder\umbraco.editorControls.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\umbraco.MacroEngines.dll) { Remove-Item $umbracoBinFolder\umbraco.MacroEngines.dll -Force -Confirm:$false }
+ if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.dll -Force -Confirm:$false }
+ if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\umbraco.providers.dll) { Remove-Item $umbracoBinFolder\umbraco.providers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\UmbracoExamine.dll) { Remove-Item $umbracoBinFolder\UmbracoExamine.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll) { Remove-Item $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll -Force -Confirm:$false }
# Delete files Umbraco depends upon
- $amd64Folder = Join-Path $projectDestinationPath "bin\amd64"
+ $amd64Folder = Join-Path $umbracoBinFolder "amd64"
if(Test-Path $amd64Folder) { Remove-Item $amd64Folder -Force -Recurse -Confirm:$false }
- $x86Folder = Join-Path $projectDestinationPath "bin\x86"
- if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
+ $x86Folder = Join-Path $umbracoBinFolder "x86"
+ if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
if(Test-Path $umbracoBinFolder\AutoMapper.dll) { Remove-Item $umbracoBinFolder\AutoMapper.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\AutoMapper.Net4.dll) { Remove-Item $umbracoBinFolder\AutoMapper.Net4.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ClientDependency.Core.dll) { Remove-Item $umbracoBinFolder\ClientDependency.Core.dll -Force -Confirm:$false }
@@ -59,6 +73,8 @@ if ($project) {
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
+ if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll -Force -Confirm:$false }
+ if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.dll -Force -Confirm:$false }
@@ -72,6 +88,8 @@ if ($project) {
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Owin.dll) { Remove-Item $umbracoBinFolder\Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Semver.dll) { Remove-Item $umbracoBinFolder\Semver.dll -Force -Confirm:$false }
+ if(Test-Path $umbracoBinFolder\System.Collections.Immutable.dll) { Remove-Item $umbracoBinFolder\System.Collections.Immutable.dll -Force -Confirm:$false }
+ if(Test-Path $umbracoBinFolder\System.Reflection.Metadata.dll) { Remove-Item $umbracoBinFolder\System.Reflection.Metadata.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Extensions.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Extensions.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Primitives.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Primitives.dll -Force -Confirm:$false }
@@ -82,6 +100,6 @@ if ($project) {
if(Test-Path $umbracoBinFolder\System.Web.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.Razor.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.WebPages.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Deployment.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Deployment.dll -Force -Confirm:$false }
- if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
+ if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
}
}
\ No newline at end of file
diff --git a/build/NuSpecs/tools/install.ps1 b/build/NuSpecs/tools/install.ps1
index 49b49f6cfe..de7a6cc16e 100644
--- a/build/NuSpecs/tools/install.ps1
+++ b/build/NuSpecs/tools/install.ps1
@@ -1,21 +1,33 @@
-param($rootPath, $toolsPath, $package, $project)
+param($installPath, $toolsPath, $package, $project)
+
+Write-Host "installPath:" "${installPath}"
+Write-Host "toolsPath:" "${toolsPath}"
+
+Write-Host " "
if ($project) {
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
- $backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
+
+ # Create paths and list them
+ $projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
+ Write-Host "projectPath:" "${projectPath}"
+ $backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
+ Write-Host "backupPath:" "${backupPath}"
$copyLogsPath = Join-Path $backupPath "CopyLogs"
- $projectDestinationPath = Split-Path $project.FullName -Parent
+ Write-Host "copyLogsPath:" "${copyLogsPath}"
+ $webConfigSource = Join-Path $projectPath "Web.config"
+ Write-Host "webConfigSource:" "${webConfigSource}"
+ $configFolder = Join-Path $projectPath "Config"
+ Write-Host "configFolder:" "${configFolder}"
# Create backup folder and logs folder if it doesn't exist yet
New-Item -ItemType Directory -Force -Path $backupPath
New-Item -ItemType Directory -Force -Path $copyLogsPath
# Create a backup of original web.config
- $webConfigSource = Join-Path $projectDestinationPath "Web.config"
Copy-Item $webConfigSource $backupPath -Force
- # Backup config files folder
- $configFolder = Join-Path $projectDestinationPath "Config"
+ # Backup config files folder
if(Test-Path $configFolder) {
$umbracoBackupPath = Join-Path $backupPath "Config"
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
@@ -24,32 +36,24 @@ if ($project) {
}
# Copy umbraco and umbraco_files from package to project folder
- # This is only done when these folders already exist because we
- # only want to do this for upgrades
- $umbracoFolder = Join-Path $projectDestinationPath "Umbraco"
- if(Test-Path $umbracoFolder) {
- $umbracoFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco"
-
- $umbracoBackupPath = Join-Path $backupPath "Umbraco"
- New-Item -ItemType Directory -Force -Path $umbracoBackupPath
-
- robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
- robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
- }
+ $umbracoFolder = Join-Path $projectPath "Umbraco"
+ New-Item -ItemType Directory -Force -Path $umbracoFolder
+ $umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
+ $umbracoBackupPath = Join-Path $backupPath "Umbraco"
+ New-Item -ItemType Directory -Force -Path $umbracoBackupPath
+ robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
+ robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
- $umbracoClientFolder = Join-Path $projectDestinationPath "Umbraco_Client"
- if(Test-Path $umbracoClientFolder) {
- $umbracoClientFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco_Client"
-
- $umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
- New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
-
- robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
- robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
- }
+ $umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
+ New-Item -ItemType Directory -Force -Path $umbracoClientFolder
+ $umbracoClientFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco_Client"
+ $umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
+ New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
+ robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
+ robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
$copyWebconfig = $true
- $destinationWebConfig = Join-Path $projectDestinationPath "Web.config"
+ $destinationWebConfig = Join-Path $projectPath "Web.config"
if(Test-Path $destinationWebConfig)
{
@@ -71,11 +75,11 @@ if ($project) {
if($copyWebconfig -eq $true)
{
- $packageWebConfigSource = Join-Path $rootPath "UmbracoFiles\Web.config"
+ $packageWebConfigSource = Join-Path $installPath "UmbracoFiles\Web.config"
Copy-Item $packageWebConfigSource $destinationWebConfig -Force
}
- $installFolder = Join-Path $projectDestinationPath "Install"
+ $installFolder = Join-Path $projectPath "Install"
if(Test-Path $installFolder) {
Remove-Item $installFolder -Force -Recurse -Confirm:$false
}
diff --git a/build/UmbracoVersion.txt b/build/UmbracoVersion.txt
index 2a8a3618d4..4846f08fcf 100644
--- a/build/UmbracoVersion.txt
+++ b/build/UmbracoVersion.txt
@@ -1,3 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
-7.4.0
-beta4
\ No newline at end of file
+7.4.2
\ No newline at end of file
diff --git a/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj b/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj
index 73983e7e30..86796e1dd7 100644
--- a/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj
+++ b/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj
@@ -47,13 +47,15 @@
-
- True
- ..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.dll
+
+ ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll
+ False
+ False
-
- True
- ..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.Entity.dll
+
+ ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll
+ False
+ False
diff --git a/src/SQLCE4Umbraco/packages.config b/src/SQLCE4Umbraco/packages.config
index 5d2d5789e7..e2435f3e8b 100644
--- a/src/SQLCE4Umbraco/packages.config
+++ b/src/SQLCE4Umbraco/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs
index f385151454..39a59f898c 100644
--- a/src/SolutionInfo.cs
+++ b/src/SolutionInfo.cs
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyFileVersion("7.4.0")]
-[assembly: AssemblyInformationalVersion("7.4.0-beta4")]
\ No newline at end of file
+[assembly: AssemblyFileVersion("7.4.2")]
+[assembly: AssemblyInformationalVersion("7.4.2")]
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs
index 861c6b803e..0ae721943d 100644
--- a/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs
@@ -7,14 +7,22 @@ using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
+ ///
+ /// Interface describing this cache provider as a wrapper for another
+ ///
+ internal interface IRuntimeCacheProviderWrapper
+ {
+ IRuntimeCacheProvider InnerProvider { get; }
+ }
+
///
/// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns
/// are a deep cloned copy of the item when the item is IDeepCloneable and that tracks changes are
/// reset if the object is TracksChangesEntityBase
///
- internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider
+ internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider, IRuntimeCacheProviderWrapper
{
- internal IRuntimeCacheProvider InnerProvider { get; private set; }
+ public IRuntimeCacheProvider InnerProvider { get; private set; }
public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider)
{
diff --git a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
index 66d9b2ac25..1f51fc3ccc 100644
--- a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
@@ -11,35 +11,35 @@ namespace Umbraco.Core.Cache
///
///
///
- internal class DefaultRepositoryCachePolicy : DisposableObject, IRepositoryCachePolicy
+ ///
+ /// This cache policy uses sliding expiration and caches instances for 5 minutes. However if allow zero count is true, then we use the
+ /// default policy with no expiry.
+ ///
+ internal class DefaultRepositoryCachePolicy : RepositoryCachePolicyBase
where TEntity : class, IAggregateRoot
{
private readonly RepositoryCachePolicyOptions _options;
- protected IRuntimeCacheProvider Cache { get; private set; }
- private Action _action;
public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
- {
- if (cache == null) throw new ArgumentNullException("cache");
+ : base(cache)
+ {
if (options == null) throw new ArgumentNullException("options");
-
- _options = options;
- Cache = cache;
+ _options = options;
}
- public string GetCacheIdKey(object id)
+ protected string GetCacheIdKey(object id)
{
if (id == null) throw new ArgumentNullException("id");
return string.Format("{0}{1}", GetCacheTypeKey(), id);
}
- public string GetCacheTypeKey()
+ protected string GetCacheTypeKey()
{
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
}
- public void CreateOrUpdate(TEntity entity, Action persistMethod)
+ public override void CreateOrUpdate(TEntity entity, Action persistMethod)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
@@ -54,7 +54,9 @@ namespace Umbraco.Core.Cache
//just to be safe, we cannot cache an item without an identity
if (entity.HasIdentity)
{
- Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity);
+ Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity,
+ timeout: TimeSpan.FromMinutes(5),
+ isSliding: true);
}
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
@@ -79,24 +81,29 @@ namespace Umbraco.Core.Cache
}
}
- public void Remove(TEntity entity, Action persistMethod)
+ public override void Remove(TEntity entity, Action persistMethod)
{
if (entity == null) throw new ArgumentNullException("entity");
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
- persistMethod(entity);
-
- //set the disposal action
- var cacheKey = GetCacheIdKey(entity.Id);
- SetCacheAction(() =>
+ try
{
- Cache.ClearCacheItem(cacheKey);
- //If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.ClearCacheItem(GetCacheTypeKey());
- });
+ persistMethod(entity);
+ }
+ finally
+ {
+ //set the disposal action
+ var cacheKey = GetCacheIdKey(entity.Id);
+ SetCacheAction(() =>
+ {
+ Cache.ClearCacheItem(cacheKey);
+ //If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.ClearCacheItem(GetCacheTypeKey());
+ });
+ }
}
- public TEntity Get(TId id, Func getFromRepo)
+ public override TEntity Get(TId id, Func getFromRepo)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
@@ -113,13 +120,13 @@ namespace Umbraco.Core.Cache
return entity;
}
- public TEntity Get(TId id)
+ public override TEntity Get(TId id)
{
var cacheKey = GetCacheIdKey(id);
return Cache.GetCacheItem(cacheKey);
}
- public bool Exists(TId id, Func getFromRepo)
+ public override bool Exists(TId id, Func getFromRepo)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
@@ -128,7 +135,7 @@ namespace Umbraco.Core.Cache
return fromCache != null || getFromRepo(id);
}
- public virtual TEntity[] GetAll(TId[] ids, Func> getFromRepo)
+ public override TEntity[] GetAll(TId[] ids, Func> getFromRepo)
{
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
@@ -182,7 +189,7 @@ namespace Umbraco.Core.Cache
/// Looks up the zero count cache, must return null if it doesn't exist
///
///
- protected virtual bool HasZeroCountCache()
+ protected bool HasZeroCountCache()
{
var zeroCount = Cache.GetCacheItem(GetCacheTypeKey());
return (zeroCount != null && zeroCount.Any() == false);
@@ -192,24 +199,13 @@ namespace Umbraco.Core.Cache
/// Performs the lookup for all entities of this type from the cache
///
///
- protected virtual TEntity[] GetAllFromCache()
+ protected TEntity[] GetAllFromCache()
{
var allEntities = Cache.GetCacheItemsByKeySearch(GetCacheTypeKey())
.WhereNotNull()
.ToArray();
return allEntities.Any() ? allEntities : new TEntity[] {};
- }
-
- ///
- /// The disposal performs the caching
- ///
- protected override void DisposeResources()
- {
- if (_action != null)
- {
- _action();
- }
- }
+ }
///
/// Sets the action to execute on disposal for a single entity
@@ -225,7 +221,9 @@ namespace Umbraco.Core.Cache
//just to be safe, we cannot cache an item without an identity
if (entity.HasIdentity)
{
- Cache.InsertCacheItem(cacheKey, () => entity);
+ Cache.InsertCacheItem(cacheKey, () => entity,
+ timeout: TimeSpan.FromMinutes(5),
+ isSliding: true);
}
});
}
@@ -244,6 +242,7 @@ namespace Umbraco.Core.Cache
{
//there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache
// to signify that there is a zero count cache
+ //NOTE: Don't set expiry/sliding for a zero count
Cache.InsertCacheItem(GetCacheTypeKey(), () => new TEntity[] {});
}
else
@@ -256,20 +255,14 @@ namespace Umbraco.Core.Cache
//just to be safe, we cannot cache an item without an identity
if (localCopy.HasIdentity)
{
- Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy);
+ Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy,
+ timeout: TimeSpan.FromMinutes(5),
+ isSliding: true);
}
}
}
});
}
-
- ///
- /// Sets the action to execute on disposal
- ///
- ///
- protected void SetCacheAction(Action action)
- {
- _action = action;
- }
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs
index 40b100ef67..9b37d1861f 100644
--- a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs
@@ -11,46 +11,190 @@ namespace Umbraco.Core.Cache
///
///
///
- internal class FullDataSetRepositoryCachePolicy : DefaultRepositoryCachePolicy
+ internal class FullDataSetRepositoryCachePolicy : RepositoryCachePolicyBase
where TEntity : class, IAggregateRoot
{
- public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache) : base(cache,
- new RepositoryCachePolicyOptions
- {
- //Definitely allow zero'd cache entires since this is a full set, in many cases there will be none,
- // and we must cache this!
- GetAllCacheAllowZeroCount = true
- })
+ private readonly Func _getEntityId;
+ private readonly Func> _getAllFromRepo;
+ private readonly bool _expires;
+
+ public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func getEntityId, Func> getAllFromRepo, bool expires)
+ : base(cache)
{
+ _getEntityId = getEntityId;
+ _getAllFromRepo = getAllFromRepo;
+ _expires = expires;
}
private bool? _hasZeroCountCache;
+
+ protected string GetCacheTypeKey()
+ {
+ return string.Format("uRepo_{0}_", typeof(TEntity).Name);
+ }
+
+ public override void CreateOrUpdate(TEntity entity, Action persistMethod)
+ {
+ if (entity == null) throw new ArgumentNullException("entity");
+ if (persistMethod == null) throw new ArgumentNullException("persistMethod");
+
+ try
+ {
+ persistMethod(entity);
+
+ //set the disposal action
+ SetCacheAction(() =>
+ {
+ //Clear all
+ Cache.ClearCacheItem(GetCacheTypeKey());
+ });
+ }
+ catch
+ {
+ //set the disposal action
+ SetCacheAction(() =>
+ {
+ //Clear all
+ Cache.ClearCacheItem(GetCacheTypeKey());
+ });
+ throw;
+ }
+ }
+
+ public override void Remove(TEntity entity, Action persistMethod)
+ {
+ if (entity == null) throw new ArgumentNullException("entity");
+ if (persistMethod == null) throw new ArgumentNullException("persistMethod");
+
+ try
+ {
+ persistMethod(entity);
+ }
+ finally
+ {
+ //set the disposal action
+ SetCacheAction(() =>
+ {
+ //Clear all
+ Cache.ClearCacheItem(GetCacheTypeKey());
+ });
+ }
+ }
+
+ public override TEntity Get(TId id, Func getFromRepo)
+ {
+ //Force get all with cache
+ var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
+
+ //we don't have anything in cache (this should never happen), just return from the repo
+ if (found == null) return getFromRepo(id);
+ var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
+ if (entity == null) return null;
+
+ //We must ensure to deep clone each one out manually since the deep clone list only clones one way
+ return (TEntity)entity.DeepClone();
+ }
+
+ public override TEntity Get(TId id)
+ {
+ //Force get all with cache
+ var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
+
+ //we don't have anything in cache (this should never happen), just return null
+ if (found == null) return null;
+ var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
+ if (entity == null) return null;
+
+ //We must ensure to deep clone each one out manually since the deep clone list only clones one way
+ return (TEntity)entity.DeepClone();
+ }
+
+ public override bool Exists(TId id, Func getFromRepo)
+ {
+ //Force get all with cache
+ var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
+
+ //we don't have anything in cache (this should never happen), just return from the repo
+ return found == null
+ ? getFromRepo(id)
+ : found.Any(x => _getEntityId(x).Equals(id));
+ }
+
+ public override TEntity[] GetAll(TId[] ids, Func> getFromRepo)
+ {
+ //process getting all including setting the cache callback
+ var result = PerformGetAll(getFromRepo);
+
+ //now that the base result has been calculated, they will all be cached.
+ // Now we can just filter by ids if they have been supplied
+
+ return (ids.Any()
+ ? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
+ : result)
+ //We must ensure to deep clone each one out manually since the deep clone list only clones one way
+ .Select(x => (TEntity)x.DeepClone())
+ .ToArray();
+ }
+
+ private TEntity[] PerformGetAll(Func> getFromRepo)
+ {
+ var allEntities = GetAllFromCache();
+ if (allEntities.Any())
+ {
+ return allEntities;
+ }
+
+ //check the zero count cache
+ if (HasZeroCountCache())
+ {
+ //there is a zero count cache so return an empty list
+ return new TEntity[] { };
+ }
+
+ //we need to do the lookup from the repo
+ var entityCollection = getFromRepo(new TId[] { })
+ //ensure we don't include any null refs in the returned collection!
+ .WhereNotNull()
+ .ToArray();
+
+ //set the disposal action
+ SetCacheAction(entityCollection);
+
+ return entityCollection;
+ }
+
///
/// For this type of caching policy, we don't cache individual items
///
///
///
- protected override void SetCacheAction(string cacheKey, TEntity entity)
+ protected void SetCacheAction(string cacheKey, TEntity entity)
{
- //do nothing
+ //No-op
}
///
/// Sets the action to execute on disposal for an entity collection
///
- ///
///
- protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
+ protected void SetCacheAction(TEntity[] entityCollection)
{
- //for this type of caching policy, we don't want to cache any GetAll request containing specific Ids
- if (ids.Any()) return;
-
//set the disposal action
SetCacheAction(() =>
{
//We want to cache the result as a single collection
- Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList(entityCollection));
+
+ if (_expires)
+ {
+ Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList(entityCollection),
+ timeout: TimeSpan.FromMinutes(5),
+ isSliding: true);
+ }
+ else
+ {
+ Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList(entityCollection));
+ }
});
}
@@ -58,7 +202,7 @@ namespace Umbraco.Core.Cache
/// Looks up the zero count cache, must return null if it doesn't exist
///
///
- protected override bool HasZeroCountCache()
+ protected bool HasZeroCountCache()
{
if (_hasZeroCountCache.HasValue)
return _hasZeroCountCache.Value;
@@ -71,14 +215,15 @@ namespace Umbraco.Core.Cache
/// This policy will cache the full data set as a single collection
///
///
- protected override TEntity[] GetAllFromCache()
+ protected TEntity[] GetAllFromCache()
{
var found = Cache.GetCacheItem>(GetCacheTypeKey());
-
+
//This method will get called before checking for zero count cache, so we'll just set the flag here
_hasZeroCountCache = found != null;
return found == null ? new TEntity[] { } : found.WhereNotNull().ToArray();
}
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicyFactory.cs b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicyFactory.cs
index 75bdae7e83..e4addcf355 100644
--- a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicyFactory.cs
+++ b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicyFactory.cs
@@ -1,3 +1,5 @@
+using System;
+using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
@@ -11,15 +13,21 @@ namespace Umbraco.Core.Cache
where TEntity : class, IAggregateRoot
{
private readonly IRuntimeCacheProvider _runtimeCache;
-
- public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache)
+ private readonly Func _getEntityId;
+ private readonly Func> _getAllFromRepo;
+ private readonly bool _expires;
+
+ public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func getEntityId, Func> getAllFromRepo, bool expires)
{
- _runtimeCache = runtimeCache;
+ _runtimeCache = runtimeCache;
+ _getEntityId = getEntityId;
+ _getAllFromRepo = getAllFromRepo;
+ _expires = expires;
}
public virtual IRepositoryCachePolicy CreatePolicy()
{
- return new FullDataSetRepositoryCachePolicy(_runtimeCache);
+ return new FullDataSetRepositoryCachePolicy(_runtimeCache, _getEntityId, _getAllFromRepo, _expires);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
index 97844933b7..215487c3be 100644
--- a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
@@ -10,9 +10,7 @@ namespace Umbraco.Core.Cache
TEntity Get(TId id, Func getFromRepo);
TEntity Get(TId id);
bool Exists(TId id, Func getFromRepo);
-
- string GetCacheIdKey(object id);
- string GetCacheTypeKey();
+
void CreateOrUpdate(TEntity entity, Action persistMethod);
void Remove(TEntity entity, Action persistMethod);
TEntity[] GetAll(TId[] ids, Func> getFromRepo);
diff --git a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs
new file mode 100644
index 0000000000..b939cd14e6
--- /dev/null
+++ b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using Umbraco.Core.Models.EntityBase;
+
+namespace Umbraco.Core.Cache
+{
+ internal abstract class RepositoryCachePolicyBase : DisposableObject, IRepositoryCachePolicy
+ where TEntity : class, IAggregateRoot
+ {
+ private Action _action;
+
+ protected RepositoryCachePolicyBase(IRuntimeCacheProvider cache)
+ {
+ if (cache == null) throw new ArgumentNullException("cache");
+
+ Cache = cache;
+ }
+
+ protected IRuntimeCacheProvider Cache { get; private set; }
+
+ ///
+ /// The disposal performs the caching
+ ///
+ protected override void DisposeResources()
+ {
+ if (_action != null)
+ {
+ _action();
+ }
+ }
+
+ ///
+ /// Sets the action to execute on disposal
+ ///
+ ///
+ protected void SetCacheAction(Action action)
+ {
+ _action = action;
+ }
+
+ public abstract TEntity Get(TId id, Func getFromRepo);
+ public abstract TEntity Get(TId id);
+ public abstract bool Exists(TId id, Func getFromRepo);
+ public abstract void CreateOrUpdate(TEntity entity, Action persistMethod);
+ public abstract void Remove(TEntity entity, Action persistMethod);
+ public abstract TEntity[] GetAll(TId[] ids, Func> getFromRepo);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
index 9566cd6e7f..28ac4ee2d1 100644
--- a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
@@ -18,7 +18,7 @@ namespace Umbraco.Core.Cache
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
{
- //do nothing
+ //no-op
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs
index 4b009e5f86..0dc5f5b00f 100644
--- a/src/Umbraco.Core/CacheHelper.cs
+++ b/src/Umbraco.Core/CacheHelper.cs
@@ -290,7 +290,7 @@ namespace Umbraco.Core
TimeSpan timeout,
Func getCacheItem)
{
- var cache = RuntimeCache as HttpRuntimeCacheProvider;
+ var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
if (cache != null)
{
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
@@ -314,7 +314,7 @@ namespace Umbraco.Core
CacheDependency cacheDependency,
Func getCacheItem)
{
- var cache = RuntimeCache as HttpRuntimeCacheProvider;
+ var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
if (cache != null)
{
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency);
@@ -374,7 +374,7 @@ namespace Umbraco.Core
TimeSpan timeout,
Func getCacheItem)
{
- var cache = RuntimeCache as HttpRuntimeCacheProvider;
+ var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
if (cache != null)
{
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency);
@@ -400,7 +400,7 @@ namespace Umbraco.Core
TimeSpan? timeout,
Func getCacheItem)
{
- var cache = RuntimeCache as HttpRuntimeCacheProvider;
+ var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
if (cache != null)
{
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
@@ -409,6 +409,20 @@ namespace Umbraco.Core
}
#endregion
- }
+ private HttpRuntimeCacheProvider GetHttpRuntimeCacheProvider(IRuntimeCacheProvider runtimeCache)
+ {
+ HttpRuntimeCacheProvider cache;
+ var wrapper = RuntimeCache as IRuntimeCacheProviderWrapper;
+ if (wrapper != null)
+ {
+ cache = wrapper.InnerProvider as HttpRuntimeCacheProvider;
+ }
+ else
+ {
+ cache = RuntimeCache as HttpRuntimeCacheProvider;
+ }
+ return cache;
+ }
+ }
}
diff --git a/src/Umbraco.Core/Collections/DeepCloneableList.cs b/src/Umbraco.Core/Collections/DeepCloneableList.cs
index 365bf53b06..5067562aa7 100644
--- a/src/Umbraco.Core/Collections/DeepCloneableList.cs
+++ b/src/Umbraco.Core/Collections/DeepCloneableList.cs
@@ -14,18 +14,24 @@ namespace Umbraco.Core.Collections
///
internal class DeepCloneableList : List, IDeepCloneable, IRememberBeingDirty
{
- ///
- /// Initializes a new instance of the class that is empty and has the default initial capacity.
- ///
- public DeepCloneableList()
+ private readonly ListCloneBehavior _listCloneBehavior;
+
+ public DeepCloneableList(ListCloneBehavior listCloneBehavior)
{
+ _listCloneBehavior = listCloneBehavior;
+ }
+
+ public DeepCloneableList(IEnumerable collection, ListCloneBehavior listCloneBehavior) : base(collection)
+ {
+ _listCloneBehavior = listCloneBehavior;
}
///
- /// Initializes a new instance of the class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
+ /// Default behavior is CloneOnce
///
- /// The collection whose elements are copied to the new list. is null.
- public DeepCloneableList(IEnumerable collection) : base(collection)
+ ///
+ public DeepCloneableList(IEnumerable collection)
+ : this(collection, ListCloneBehavior.CloneOnce)
{
}
@@ -35,20 +41,47 @@ namespace Umbraco.Core.Collections
///
public object DeepClone()
{
- var newList = new DeepCloneableList();
- foreach (var item in this)
+ switch (_listCloneBehavior)
{
- var dc = item as IDeepCloneable;
- if (dc != null)
- {
- newList.Add((T) dc.DeepClone());
- }
- else
- {
- newList.Add(item);
- }
+ case ListCloneBehavior.CloneOnce:
+ //we are cloning once, so create a new list in none mode
+ // and deep clone all items into it
+ var newList = new DeepCloneableList(ListCloneBehavior.None);
+ foreach (var item in this)
+ {
+ var dc = item as IDeepCloneable;
+ if (dc != null)
+ {
+ newList.Add((T)dc.DeepClone());
+ }
+ else
+ {
+ newList.Add(item);
+ }
+ }
+ return newList;
+ case ListCloneBehavior.None:
+ //we are in none mode, so just return a new list with the same items
+ return new DeepCloneableList(this, ListCloneBehavior.None);
+ case ListCloneBehavior.Always:
+ //always clone to new list
+ var newList2 = new DeepCloneableList(ListCloneBehavior.Always);
+ foreach (var item in this)
+ {
+ var dc = item as IDeepCloneable;
+ if (dc != null)
+ {
+ newList2.Add((T)dc.DeepClone());
+ }
+ else
+ {
+ newList2.Add(item);
+ }
+ }
+ return newList2;
+ default:
+ throw new ArgumentOutOfRangeException();
}
- return newList;
}
public bool IsDirty()
diff --git a/src/Umbraco.Core/Collections/ListCloneBehavior.cs b/src/Umbraco.Core/Collections/ListCloneBehavior.cs
new file mode 100644
index 0000000000..4fe935f7ff
--- /dev/null
+++ b/src/Umbraco.Core/Collections/ListCloneBehavior.cs
@@ -0,0 +1,20 @@
+namespace Umbraco.Core.Collections
+{
+ internal enum ListCloneBehavior
+ {
+ ///
+ /// When set, DeepClone will clone the items one time and the result list behavior will be None
+ ///
+ CloneOnce,
+
+ ///
+ /// When set, DeepClone will not clone any items
+ ///
+ None,
+
+ ///
+ /// When set, DeepClone will always clone all items
+ ///
+ Always
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs
index 4039ab7db0..c424d1fc21 100644
--- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
- private static readonly Version Version = new Version("7.4.0");
+ private static readonly Version Version = new Version("7.4.2");
///
/// Gets the current version of Umbraco.
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
///
/// The version comment.
- public static string CurrentComment { get { return "beta4"; } }
+ 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
diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs
index 60fba0ae40..f596820506 100644
--- a/src/Umbraco.Core/Constants-Web.cs
+++ b/src/Umbraco.Core/Constants-Web.cs
@@ -10,6 +10,12 @@ namespace Umbraco.Core
///
public static class Web
{
+ public const string UmbracoContextDataToken = "umbraco-context";
+ public const string UmbracoDataToken = "umbraco";
+ public const string PublishedDocumentRequestDataToken = "umbraco-doc-request";
+ public const string CustomRouteDataToken = "umbraco-custom-route";
+ public const string UmbracoRouteDefinitionDataToken = "umbraco-route-def";
+
///
/// The preview cookie name
///
diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs
index d2dea09698..4da740f458 100644
--- a/src/Umbraco.Core/CoreBootManager.cs
+++ b/src/Umbraco.Core/CoreBootManager.cs
@@ -136,7 +136,10 @@ namespace Umbraco.Core
{
try
{
- x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
+ using (ProfilingLogger.DebugDuration(string.Format("Executing {0} in ApplicationInitialized", x.GetType())))
+ {
+ x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
+ }
}
catch (Exception ex)
{
@@ -299,7 +302,10 @@ namespace Umbraco.Core
{
try
{
- x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
+ using (ProfilingLogger.DebugDuration(string.Format("Executing {0} in ApplicationStarting", x.GetType())))
+ {
+ x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
+ }
}
catch (Exception ex)
{
@@ -350,7 +356,10 @@ namespace Umbraco.Core
{
try
{
- x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
+ using (ProfilingLogger.DebugDuration(string.Format("Executing {0} in ApplicationStarted", x.GetType())))
+ {
+ x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
+ }
}
catch (Exception ex)
{
diff --git a/src/Umbraco.Core/Dynamics/CaseInsensitiveDynamicObject.cs b/src/Umbraco.Core/Dynamics/CaseInsensitiveDynamicObject.cs
new file mode 100644
index 0000000000..43d7adc647
--- /dev/null
+++ b/src/Umbraco.Core/Dynamics/CaseInsensitiveDynamicObject.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq;
+using System.Reflection;
+
+namespace Umbraco.Core.Dynamics
+{
+ ///
+ /// This will check enable dynamic access to properties and methods in a case insensitive manner
+ ///
+ ///
+ ///
+ /// This works by using reflection on the type - the reflection lookup is lazy so it will not execute unless a dynamic method needs to be accessed
+ ///
+ public abstract class CaseInsensitiveDynamicObject : DynamicObject
+ where T: class
+ {
+ ///
+ /// Used for dynamic access for case insensitive property access
+ /// `
+ private static readonly Lazy>> CaseInsensitivePropertyAccess = new Lazy>>(() =>
+ {
+ var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
+ .DistinctBy(x => x.Name);
+ return props.Select(propInfo =>
+ {
+ var name = propInfo.Name.ToLowerInvariant();
+ Func getVal = propInfo.GetValue;
+ return new KeyValuePair>(name, getVal);
+
+ }).ToDictionary(x => x.Key, x => x.Value);
+ });
+
+ ///
+ /// Used for dynamic access for case insensitive property access
+ ///
+ private static readonly Lazy>>> CaseInsensitiveMethodAccess
+ = new Lazy>>>(() =>
+ {
+ var props = typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public)
+ .Where(x => x.IsSpecialName == false && x.IsVirtual == false)
+ .DistinctBy(x => x.Name);
+ return props.Select(methodInfo =>
+ {
+ var name = methodInfo.Name.ToLowerInvariant();
+ Func getVal = methodInfo.Invoke;
+ var val = new Tuple>(methodInfo.GetParameters(), getVal);
+ return new KeyValuePair>>(name, val);
+
+ }).ToDictionary(x => x.Key, x => x.Value);
+ });
+
+ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
+ {
+ var name = binder.Name.ToLowerInvariant();
+ if (CaseInsensitiveMethodAccess.Value.ContainsKey(name) == false)
+ return base.TryInvokeMember(binder, args, out result);
+
+ var val = CaseInsensitiveMethodAccess.Value[name];
+ var parameters = val.Item1;
+ var callback = val.Item2;
+ var fullArgs = new List