Compare commits
462 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| add2f57397 | |||
| cd3c17d73f | |||
| fe6d783222 | |||
| fc8b0f1822 | |||
| 6102c970c8 | |||
| 29903058a9 | |||
| b3940dea1b | |||
| 3dac630d05 | |||
| 10108d75b8 | |||
| 24cb64579b | |||
| 86239cc777 | |||
| 685aea1728 | |||
| eb4e041682 | |||
| 477aa754b3 | |||
| 48bff0aa6c | |||
| 4ea9fec9e2 | |||
| f3a965841b | |||
| 08ddb5f4c4 | |||
| 4ec63ffd0d | |||
| 4cb3e82972 | |||
| 0a20741f39 | |||
| 4575748f16 | |||
| 028ee831b8 | |||
| 54981cd57c | |||
| 0aab8cacaa | |||
| 15b4d33e00 | |||
| 367ba5cddf | |||
| ff64efbcdf | |||
| 5bc0c499d8 | |||
| f667318b58 | |||
| 87c9d15ad5 | |||
| 127736d188 | |||
| 139ab8d4df | |||
| 4abb8035b8 | |||
| 0ca1807d64 | |||
| 5ae90d201c | |||
| 6c416009d7 | |||
| 50da9bcb50 | |||
| 9e6a2d8a7c | |||
| cfb84cae44 | |||
| 4239833713 | |||
| 4fa1a3948e | |||
| 1b78e854f0 | |||
| c62a2362d2 | |||
| eb1855fcb7 | |||
| d4863239cd | |||
| 4b7ddb9c15 | |||
| e5bb35b335 | |||
| 7eabd09b3a | |||
| 087f0c0ede | |||
| db9d6d9109 | |||
| 700e180522 | |||
| 8584997f5f | |||
| 4710b3b641 | |||
| 227e2489c1 | |||
| 91a5b19378 | |||
| 4c20441c4e | |||
| edfe1e6d54 | |||
| 7869f77704 | |||
| 34fd405bca | |||
| f03ee9f908 | |||
| b053638204 | |||
| d790194682 | |||
| 3fec2b9756 | |||
| bc7a31d791 | |||
| 05d84c6673 | |||
| f6645e3928 | |||
| 50b00b12b0 | |||
| 569371ffff | |||
| f7b72b225a | |||
| d1bed54cf1 | |||
| ba868887d4 | |||
| 3a7853dcbe | |||
| 60af7deacd | |||
| 49bc3151b0 | |||
| d6b7bae38a | |||
| 715cc22722 | |||
| 88b23e09b6 | |||
| 612484c0b6 | |||
| 0e4974babe | |||
| 5fdd7d8bd6 | |||
| b5c87ccfb7 | |||
| 2efe6ae7a4 | |||
| 5775984730 | |||
| cbab70fd7c | |||
| cfa2a30006 | |||
| 09a3b0d155 | |||
| ca9cd77ded | |||
| 812601217a | |||
| 3a6ec5ef0c | |||
| 4197a7654f | |||
| 3133014650 | |||
| 4bce945946 | |||
| 2d15c9c01c | |||
| 58e648828b | |||
| d87b268a40 | |||
| 5174645059 | |||
| e4286bc35b | |||
| cf4d13da31 | |||
| a89b064e29 | |||
| 1e41973eb5 | |||
| b4e496fceb | |||
| bb94fc7d71 | |||
| 959378c456 | |||
| 787e128d5c | |||
| b7912a7be7 | |||
| 0bc7aa6ba7 | |||
| 367da39bbb | |||
| 6d8ffb903f | |||
| 0e992f897f | |||
| 3f19878c18 | |||
| 308f64a7e2 | |||
| 1eab92b299 | |||
| 7a8b8f138f | |||
| 926ea54c39 | |||
| b44494a093 | |||
| a6094a82cb | |||
| 07f58d191b | |||
| 51eae92a5a | |||
| 0be3f3fb76 | |||
| 9f000eb90c | |||
| b7926bfa19 | |||
| fa76ffa5ca | |||
| 5ed8ade862 | |||
| 7a31ce16e2 | |||
| 16c9ca9e4b | |||
| 00c13b9939 | |||
| dbced8bef7 | |||
| 9552922795 | |||
| de53c8886b | |||
| 3672d13215 | |||
| 5ab036e9d3 | |||
| accf52ca38 | |||
| 51d14a7a01 | |||
| db0defb93f | |||
| 1fca0d22bf | |||
| 7d7e92432e | |||
| 86ad3f6b05 | |||
| 615ab564e5 | |||
| ee36a46d51 | |||
| 293568228c | |||
| 8b86276011 | |||
| 9406675bf2 | |||
| aa08a4ca37 | |||
| abf8777b0a | |||
| a6a2b02cd8 | |||
| 445dff7c5e | |||
| 37076fa4eb | |||
| 8c871a6172 | |||
| 3e42358f2a | |||
| 9bdb91b3c0 | |||
| 7f1f090a10 | |||
| 5c91c204fa | |||
| 11c7955b1e | |||
| 72d4457a24 | |||
| 9606cab81e | |||
| 7cd47114e0 | |||
| cd578b7b19 | |||
| f3d9b4a9f3 | |||
| b0fb892b16 | |||
| 66ca4e48bb | |||
| 96cd4daca5 | |||
| a1f08ad1b4 | |||
| 44c3140b20 | |||
| 7fac2b811b | |||
| 201512d5f2 | |||
| c1f5d8392d | |||
| 1aaeb75e0e | |||
| 0bbe1c6cdc | |||
| b78f75775d | |||
| 34f44b02a2 | |||
| 93c1321b99 | |||
| 73cb9ab3e5 | |||
| e402768212 | |||
| 6095f0233e | |||
| 9b1f4ecff9 | |||
| 3c884b583e | |||
| ea653cbd18 | |||
| b2679f3f17 | |||
| 231a7fa7c4 | |||
| a3936d69cb | |||
| a273584cc8 | |||
| 62c4e404b3 | |||
| d1b6b5c76f | |||
| b5cf3e9f59 | |||
| d97c772c70 | |||
| d5460068d4 | |||
| 5ac34a700f | |||
| a40762f09d | |||
| 0f00eaed78 | |||
| 01653f60f9 | |||
| d8b6f1fef1 | |||
| 1ecd0af268 | |||
| c2dc896fce | |||
| 2f714d0b3e | |||
| 0bbcaca067 | |||
| 55d3d8437a | |||
| 9e2ab8507f | |||
| 6ee6c77d6e | |||
| 9b5d4e5b08 | |||
| 49f8b530b7 | |||
| 56176d0e36 | |||
| ab41c900da | |||
| 92e0e5e570 | |||
| 90645e5e85 | |||
| 872c345ac9 | |||
| b4e0ddb7ad | |||
| a1f40a3e6e | |||
| 28df1af226 | |||
| 195953d63c | |||
| a93684f1f2 | |||
| 18e8f09654 | |||
| 85ebcadcdd | |||
| 0efeba3744 | |||
| 2a63519e8c | |||
| ba1d546579 | |||
| 8baaae4da6 | |||
| ed05a3223f | |||
| 25e3134e35 | |||
| f1b9b98f5d | |||
| d2f7eda074 | |||
| a5d5809385 | |||
| d9d38b9cc1 | |||
| 1e147f97e1 | |||
| db0cfad6b9 | |||
| 3062eedb4f | |||
| 1e3dd4c5cd | |||
| a7871abbd9 | |||
| effa632fab | |||
| 161f2eda86 | |||
| bf3a08cf85 | |||
| 7bc208e490 | |||
| a4dbc33b9a | |||
| 6b2e042e76 | |||
| b4bb15c66f | |||
| 7bf28a20e7 | |||
| d386c069ee | |||
| d83fdb48c9 | |||
| 6aa633c8c5 | |||
| eddd643249 | |||
| 9be2f99e7b | |||
| 2d5bfc0fe2 | |||
| c01f864e37 | |||
| a8be796d68 | |||
| 4acbdbe896 | |||
| 34a9eef8b8 | |||
| 0f56fa4baa | |||
| 82a8404b2e | |||
| bce8affe16 | |||
| 4bbd8097a2 | |||
| da9c810d78 | |||
| 431d066300 | |||
| 6d50bd891a | |||
| 1d00e3c5d8 | |||
| 97533e7c3d | |||
| e69422c8d8 | |||
| a277ac2fe4 | |||
| 1067b1e245 | |||
| 7987f13a11 | |||
| ccda1bdd73 | |||
| 76a6f2d2d0 | |||
| 69428b2281 | |||
| 7cd39918a0 | |||
| 9a626c9da6 | |||
| 0520797c09 | |||
| 9b85ba5b90 | |||
| 993a5bbc92 | |||
| ca738979ce | |||
| c9489bb912 | |||
| fce688f47f | |||
| 8cfb56adf4 | |||
| 6833c195c1 | |||
| 053346d79b | |||
| 044c9c95f8 | |||
| b23ea69b3e | |||
| 46f9c5ff05 | |||
| 3bc4b50d74 | |||
| 1a2849dfb0 | |||
| bcb5883230 | |||
| 18080c1cfb | |||
| 2600a3887e | |||
| 45bec2a67d | |||
| da7456fd2a | |||
| 275ba00e24 | |||
| d00bf4649d | |||
| 04976f8063 | |||
| 3e7c9fc81e | |||
| a1f4d7b16f | |||
| 811ef4a444 | |||
| 69ac621f5a | |||
| 610582df38 | |||
| cf16692b5a | |||
| 5d60440a6f | |||
| 0fe96e80c9 | |||
| a712726065 | |||
| 253b9dab27 | |||
| 1ffde1e9a6 | |||
| f6e0dfe9dc | |||
| 30dfd2772b | |||
| f93364ab96 | |||
| b903e0503f | |||
| b0ccb040a1 | |||
| db030ffa31 | |||
| cf90e9a6b8 | |||
| 7c451411cb | |||
| bf19d61d14 | |||
| 2cd5551913 | |||
| 3a3917c1fc | |||
| 7e798e18e8 | |||
| 9cb5026a0a | |||
| 39a9d68f43 | |||
| 8c54f2edc9 | |||
| d26b12137b | |||
| 081d6f9158 | |||
| b52439f8f1 | |||
| d63f83f7c7 | |||
| 85158abb5f | |||
| c917fc37ae | |||
| f68cdf43e1 | |||
| f0742c9d7c | |||
| 32e21b0314 | |||
| 22c035c9b9 | |||
| 4257d85aa7 | |||
| 9c50c67319 | |||
| d0c4b2ab72 | |||
| 53a0c55b14 | |||
| d76b8d91b1 | |||
| 44943e367f | |||
| 89c3c71251 | |||
| 7e7725f0f5 | |||
| 7b881a2110 | |||
| ccb078c8f2 | |||
| 974f827e8b | |||
| 048a8683dd | |||
| bdd7d7280d | |||
| 671026cfc9 | |||
| 56315768e9 | |||
| 309675dce7 | |||
| b42959f663 | |||
| 30979f92cc | |||
| 623e8e3979 | |||
| 42b2b16f0e | |||
| f14989f7fd | |||
| acf7fa7907 | |||
| aa9751afff | |||
| 3be714d786 | |||
| bcd1395e08 | |||
| 96199caa11 | |||
| 73de12037e | |||
| 1a8c89b99a | |||
| fdf53b8550 | |||
| 5487ec1d5f | |||
| 7b28e64c9e | |||
| 88a0189f23 | |||
| 95d8fe239e | |||
| 8ad814a3b6 | |||
| b5fb6bc2d5 | |||
| 9901b2ee3d | |||
| 346d13174a | |||
| 79ad33dd6e | |||
| 805d743f69 | |||
| a85f3bfc16 | |||
| 84cac6ac90 | |||
| e758bf2eca | |||
| 1f0a4490a6 | |||
| 85a4a4fa81 | |||
| aaf49667ec | |||
| a7029e4733 | |||
| 18b1857539 | |||
| 4f5c24d2e3 | |||
| f82d8a5df1 | |||
| cb3ed7ed8d | |||
| 1cade7f8c7 | |||
| 7503a83219 | |||
| 869e0dcbd2 | |||
| a814b51682 | |||
| c204741fb9 | |||
| 5f64b2cf37 | |||
| 9efa67224e | |||
| b00776901c | |||
| 37211b9a2c | |||
| 40c35e5851 | |||
| 68073fdb8b | |||
| 5eb9138775 | |||
| cb6b8434f0 | |||
| ff7bdb0f5b | |||
| 38953212a3 | |||
| 8e1e7a8676 | |||
| a296437547 | |||
| 012c3289cd | |||
| 48dd3fe0c7 | |||
| 367d82d103 | |||
| b7aadaa3d2 | |||
| 05d59bba73 | |||
| d5baa586cf | |||
| a1d7f2d8b3 | |||
| 3496a064c9 | |||
| 7c96f95491 | |||
| 7fc474d62b | |||
| 6a7229e983 | |||
| f4d507eaa0 | |||
| c962a9331a | |||
| b175177770 | |||
| 08ff284121 | |||
| 221183d791 | |||
| be84db097a | |||
| eaaccdad75 | |||
| 4fcadc7e94 | |||
| d77f95f29b | |||
| 2751a4a02d | |||
| 437a9cf2b3 | |||
| aef1fb13b1 | |||
| db5697c455 | |||
| 10d368696d | |||
| ef2e86b271 | |||
| 1c0188351c | |||
| 6d3377cc6e | |||
| fd6caf5cee | |||
| 20e265491f | |||
| 10c8645b5f | |||
| 3c353fc7f9 | |||
| bc04f578e3 | |||
| 03a8ee437d | |||
| ee0297bb69 | |||
| 9765e9cf3a | |||
| 6d9aba0952 | |||
| 1b137bb785 | |||
| d57561b0e3 | |||
| d2dc4efed8 | |||
| 4f02a13a46 | |||
| 52c33055af | |||
| bef6b8cd4c | |||
| 8d1cdf020b | |||
| 29b64965ed | |||
| 1e5a7a13dd | |||
| e6cc90f6dd | |||
| c29af1df48 | |||
| 8451a020dd | |||
| b413d717e2 | |||
| dafaca414c | |||
| b1fda57e50 | |||
| 4cd8522921 | |||
| 4574aa2173 | |||
| 226f8f60ca | |||
| a3d4ccc062 | |||
| 7ca323d8d3 | |||
| d35b47b960 | |||
| 00ad45f436 | |||
| d75179b742 | |||
| 6be183f11b | |||
| a979f7ab12 | |||
| e639869bb1 | |||
| 09552d282f | |||
| afe09c0850 | |||
| 181f7c1819 | |||
| 3c21ccab78 | |||
| 3f0ea176e3 | |||
| 73fbe7d78c | |||
| 5d1340e864 | |||
| c867f609f1 | |||
| 69879dc8f8 | |||
| f663a13391 |
@@ -129,3 +129,4 @@ src/*.boltdata/
|
||||
/src/Umbraco.Web.UI/Umbraco/Js/canvasdesigner.front.js
|
||||
src/umbraco.sln.ide/*
|
||||
build/UmbracoCms.*/
|
||||
src/.vs/
|
||||
|
||||
+8
-6
@@ -25,9 +25,9 @@ ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise
|
||||
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%
|
||||
..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder%
|
||||
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder%
|
||||
..\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
|
||||
@@ -43,7 +43,7 @@ DEL /F /Q webpihash.txt
|
||||
ECHO Making sure Git is in the path so that the build can succeed
|
||||
CALL InstallGit.cmd
|
||||
ECHO Performing MSBuild and producing Umbraco binaries zip files
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment%
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment% /verbosity:minimal
|
||||
|
||||
ECHO Setting node_modules folder to hidden to prevent VS13 from crashing on it while loading the websites project
|
||||
attrib +h ..\src\Umbraco.Web.UI.Client\node_modules
|
||||
@@ -53,11 +53,13 @@ REN .\_BuildOutput\WebApp\Views\Web.config Web.config.transform
|
||||
REN .\_BuildOutput\WebApp\Xslt\Web.config Web.config.transform
|
||||
|
||||
ECHO Packing the NuGet release files
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %version% -Symbols
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.nuspec -Version %version%
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %version% -Symbols -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.nuspec -Version %version% -Verbosity quiet
|
||||
|
||||
IF ERRORLEVEL 1 GOTO :showerror
|
||||
|
||||
ECHO No errors were detected but you still may see some in the output, then it's time to investigate.
|
||||
ECHO You might see some warnings but that is completely normal.
|
||||
GOTO :EOF
|
||||
|
||||
:showerror
|
||||
|
||||
+44
-13
@@ -68,6 +68,12 @@
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!='' AND '$(BUILD_COMMENT)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)-$(BUILD_COMMENT)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!='' AND '$(BUILD_NIGHTLY)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)-$(BUILD_NIGHTLY)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!='' AND '$(BUILD_COMMENT)'!='' AND '$(BUILD_NIGHTLY)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)-$(BUILD_COMMENT)-$(BUILD_NIGHTLY)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BuildConfiguration>Release</BuildConfiguration>
|
||||
@@ -91,15 +97,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SystemFolders Include="$(WebAppFolder)App_Plugins" />
|
||||
<SystemFolders Include="$(WebAppFolder)App_Code" />
|
||||
<SystemFolders Include="$(WebAppFolder)App_Data" />
|
||||
<SystemFolders Include="$(WebAppFolder)Media" />
|
||||
<SystemFolders Include="$(WebAppFolder)Masterpages" />
|
||||
<SystemFolders Include="$(WebAppFolder)Scripts" />
|
||||
<SystemFolders Include="$(WebAppFolder)Css" />
|
||||
<SystemFolders Include="$(WebAppFolder)Xslt" />
|
||||
<SystemFolders Include="$(WebAppFolder)UserControls" />
|
||||
<SystemFolders Include="$(WebAppFolder)Views" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -145,14 +144,14 @@
|
||||
DestinationFiles="@(WebPiFiles->'$(WebPiFolder)%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
|
||||
<!-- Zip the files -->
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22 -x!dotLess.Core.dll" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22 -x!dotLess.Core.dll -x![Content_Types].xml >NUL" />
|
||||
</Target>
|
||||
|
||||
<Target Name="ZipWebApp" DependsOnTargets="CreateSystemFolders" >
|
||||
<Message Text="Starting to zip to $(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameBin)%22 %22$(SolutionBinFolderAbsolutePath)*%22 -x!dotLess.Core.dll" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileName)%22 %22$(WebAppFolderAbsolutePath)*%22 -x!dotLess.Core.dll" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameBin)%22 %22$(SolutionBinFolderAbsolutePath)*%22 -x!dotLess.Core.dll >NUL" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileName)%22 %22$(WebAppFolderAbsolutePath)*%22 -x!dotLess.Core.dll -x![Content_Types].xml >NUL" />
|
||||
|
||||
<Message Text="Finished zipping to build\$(BuildFolder)\$(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
</Target>
|
||||
@@ -219,6 +218,7 @@
|
||||
<Target Name="CopyTransformedConfig" DependsOnTargets="CopyXmlDocumentation">
|
||||
<ItemGroup>
|
||||
<ConfigFiles Include="$(WebAppFolder)config\*.config;$(WebAppFolder)config\*.js" />
|
||||
<CustomLanguageFiles Include="$(WebAppFolder)config\lang\*.xml" />
|
||||
<WebConfigTransformFile Include="$(WebAppFolder)Web.config" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -227,6 +227,11 @@
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
|
||||
<Copy SourceFiles="@(CustomLanguageFiles)"
|
||||
DestinationFiles="@(CustomLanguageFiles->'$(ConfigsFolder)Lang\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
|
||||
<Copy SourceFiles="@(WebConfigTransformFile)"
|
||||
DestinationFiles="$(ConfigsFolder)Web.config.transform"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
@@ -259,7 +264,7 @@
|
||||
<Message Text="Compiling web project to build\$(BuildFolder)" Importance="high" />
|
||||
<!-- For UseWPP_CopyWebApplication=True see http://stackoverflow.com/questions/1983575/copywebapplication-with-web-config-transformations -->
|
||||
<!-- Build the Umbraco.Web.UI project -->
|
||||
<MSBuild Projects="..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);UseWPP_CopyWebApplication=True;PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);WebProjectOutputDir=$(WebAppFolderAbsolutePath)" Targets="Clean;Rebuild;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
|
||||
<MSBuild Projects="..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);UseWPP_CopyWebApplication=True;PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);WebProjectOutputDir=$(WebAppFolderAbsolutePath);Verbosity=minimal" Targets="Clean;Rebuild;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
|
||||
</MSBuild>
|
||||
|
||||
<!-- DONE -->
|
||||
@@ -271,9 +276,11 @@
|
||||
<PropertyGroup>
|
||||
<NewVersion>$(BUILD_RELEASE)</NewVersion>
|
||||
<NewVersion Condition="'$(BUILD_COMMENT)'!=''">$(BUILD_RELEASE)-$(BUILD_COMMENT)</NewVersion>
|
||||
<NewVersion Condition="'$(BUILD_NIGHTLY)'!=''">$(BUILD_RELEASE)-$(BUILD_NIGHTLY)</NewVersion>
|
||||
<NewVersion Condition="'$(BUILD_COMMENT)'!='' And '$(BUILD_NIGHTLY)'!=''">$(BUILD_RELEASE)-$(BUILD_COMMENT)-$(BUILD_NIGHTLY)</NewVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Match & replace 3 and 4 digit version numbers and -beta (if it's there) -->
|
||||
<!-- Match & replace 3 and 4 digit version numbers and -beta and +nightly (if they're there) -->
|
||||
<FileUpdate
|
||||
Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="(\d+)\.(\d+)\.(\d+)(.(\d+))?"
|
||||
@@ -283,6 +290,16 @@
|
||||
Regex="CurrentComment { get { return "(.+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_COMMENT)""/>
|
||||
|
||||
<FileUpdate Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Condition="'$(BUILD_NIGHTLY)'!=''"
|
||||
Regex="CurrentComment { get { return "(.+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_NIGHTLY)""/>
|
||||
|
||||
<FileUpdate Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Condition="'$(BUILD_COMMENT)'!='' AND '$(BUILD_NIGHTLY)'!=''"
|
||||
Regex="CurrentComment { get { return "(.+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_COMMENT)-$(BUILD_NIGHTLY)""/>
|
||||
|
||||
<!--This updates the AssemblyFileVersion for the solution to the umbraco version-->
|
||||
<FileUpdate
|
||||
Files="..\src\SolutionInfo.cs"
|
||||
@@ -300,10 +317,24 @@
|
||||
Files="..\src\SolutionInfo.cs"
|
||||
Regex="AssemblyInformationalVersion\("(.+)?"\)"
|
||||
ReplacementText="AssemblyInformationalVersion("$(BUILD_RELEASE)")"/>
|
||||
<FileUpdate
|
||||
Condition="'$(BUILD_NIGHTLY)'!=''"
|
||||
Files="..\src\SolutionInfo.cs"
|
||||
Regex="AssemblyInformationalVersion\("(.+)?"\)"
|
||||
ReplacementText="AssemblyInformationalVersion("$(BUILD_RELEASE)-$(BUILD_NIGHTLY)")"/>
|
||||
<FileUpdate
|
||||
Condition="'$(BUILD_COMMENT)'!='' AND '$(BUILD_NIGHTLY)'!=''"
|
||||
Files="..\src\SolutionInfo.cs"
|
||||
Regex="AssemblyInformationalVersion\("(.+)?"\)"
|
||||
ReplacementText="AssemblyInformationalVersion("$(BUILD_RELEASE)-$(BUILD_COMMENT)-$(BUILD_NIGHTLY)")"/>
|
||||
<FileUpdate
|
||||
Condition="'$(BUILD_COMMENT)'=='' AND '$(BUILD_NIGHTLY)'==''"
|
||||
Files="..\src\SolutionInfo.cs"
|
||||
Regex="AssemblyInformationalVersion\("(.+)?"\)"
|
||||
ReplacementText="AssemblyInformationalVersion("$(BUILD_RELEASE)")"/>
|
||||
|
||||
<!--This updates the copyright year-->
|
||||
<FileUpdate
|
||||
Condition="'$(BUILD_COMMENT)'==''"
|
||||
Files="..\src\SolutionInfo.cs"
|
||||
Regex="AssemblyCopyright\("Copyright © Umbraco (\d{4})"\)"
|
||||
ReplacementText="AssemblyCopyright("Copyright © Umbraco $([System.DateTime]::Now.ToString(`yyyy`))")"/>
|
||||
|
||||
@@ -6,7 +6,7 @@ SET nuGetFolder=%CD%\..\src\packages\
|
||||
ECHO Configured packages folder: %nuGetFolder%
|
||||
ECHO Current folder: %CD%
|
||||
|
||||
%CD%\..\src\.nuget\NuGet.exe install Npm.js -OutputDirectory %nuGetFolder%
|
||||
%CD%\..\src\.nuget\NuGet.exe install Npm.js -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
|
||||
for /f "delims=" %%A in ('dir %nuGetFolder%node.js.* /b') do set "nodePath=%nuGetFolder%%%A\"
|
||||
for /f "delims=" %%A in ('dir %nuGetFolder%npm.js.* /b') do set "npmPath=%nuGetFolder%%%A\tools\"
|
||||
@@ -24,9 +24,9 @@ ECHO Change directory to %CD%\..\src\Umbraco.Web.UI.Client\
|
||||
CD %CD%\..\src\Umbraco.Web.UI.Client\
|
||||
|
||||
ECHO Do npm install and the grunt build of Belle
|
||||
call npm install
|
||||
call npm install -g grunt-cli
|
||||
call npm install -g bower
|
||||
call npm install --quiet
|
||||
call npm install -g grunt-cli --quiet
|
||||
call npm install -g bower --quiet
|
||||
call grunt build --buildversion=%release%
|
||||
|
||||
ECHO Reset path to what it was before
|
||||
|
||||
@@ -15,27 +15,29 @@
|
||||
<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.Mvc" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,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.Net.Http" version="[2.2.29, 3.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1, 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="HtmlAgilityPack" version="[1.4.9, 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="MySql.Data" version="[6.9.7, 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-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="ClientDependency" version="[1.8.4, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 7.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.68, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 2.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebHelpers" version="[3.2.3, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebPages.Data" version="[3.2.3, 4.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<file src="..\_BuildOutput\WebApp\Global.asax" target="Content\Global.asax" />
|
||||
<file src="..\_BuildOutput\WebApp\Web.config" target="UmbracoFiles\Web.config" />
|
||||
<file src="..\_BuildOutput\WebApp\App_Browsers\**" target="UmbracoFiles\App_Browsers" />
|
||||
<file src="..\_BuildOutput\WebApp\App_Plugins\**" target="UmbracoFiles\App_Plugins" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\amd64\**" target="UmbracoFiles\bin\amd64" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\x86\**" target="UmbracoFiles\bin\x86" />
|
||||
<file src="..\_BuildOutput\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
|
||||
@@ -41,6 +40,7 @@
|
||||
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
|
||||
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
|
||||
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
|
||||
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
|
||||
<file src="build\**" target="build" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -35,6 +35,11 @@
|
||||
views/dashboard/developer/examinemanagement.html
|
||||
</control>
|
||||
</tab>
|
||||
<tab caption="Xml Data Integrity Report" xdt:Transform="InsertIfMissing">
|
||||
<control>
|
||||
views/dashboard/developer/xmldataintegrityreport.html
|
||||
</control>
|
||||
</tab>
|
||||
</section>
|
||||
|
||||
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)">
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<configSections>
|
||||
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(name)"
|
||||
xdt:Transform="SetAttributes(type)">
|
||||
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(name)"
|
||||
xdt:Transform="SetAttributes(type)" />
|
||||
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(name)"
|
||||
xdt:Transform="SetAttributes(type)" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<system.web.webPages.razor>
|
||||
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(factoryType)"
|
||||
xdt:Transform="SetAttributes(factoryType)" />
|
||||
</system.web.webPages.razor>
|
||||
|
||||
<system.web>
|
||||
<pages
|
||||
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(pageParserFilterType,pageBaseType,userControlBaseType)"
|
||||
xdt:Transform="SetAttributes(pageParserFilterType,pageBaseType,userControlBaseType)">
|
||||
<controls>
|
||||
<add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc"
|
||||
xdt:Locator="Match(namespace)"
|
||||
xdt:Transform="SetAttributes(assembly)" />
|
||||
</controls>
|
||||
</pages>
|
||||
</system.web>
|
||||
|
||||
</configuration>
|
||||
@@ -20,9 +20,11 @@
|
||||
|
||||
<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>
|
||||
<appSettings>
|
||||
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="SetAttributes" />
|
||||
</appSettings>
|
||||
|
||||
<umbracoConfiguration xdt:Transform="InsertIfMissing">
|
||||
<settings configSource="config\umbracoSettings.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
@@ -49,6 +51,8 @@
|
||||
<system.web xdt:Transform="InsertIfMissing" />
|
||||
<system.web>
|
||||
<siteMap xdt:Transform="Remove" />
|
||||
<httpRuntime xdt:Transform="InsertIfMissing" />
|
||||
<httpRuntime targetFramework="4.5" xdt:Transform="SetAttributes(targetFramework)" />
|
||||
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
|
||||
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>
|
||||
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>>
|
||||
@@ -144,7 +148,12 @@
|
||||
<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" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Http')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.OAuth')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.Cookies')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
@@ -160,12 +169,32 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
|
||||
</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>
|
||||
<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>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\ImageProcessor.Web.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.Web.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Web.Infrastructure.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Infrastructure.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Helpers.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\MiniProfiler.dll) { Remove-Item $umbracoBinFolder\MiniProfiler.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\MySql.Data.dll) { Remove-Item $umbracoBinFolder\MySql.Data.dll -Force -Confirm:$false }
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0"?>
|
||||
<log4net xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
|
||||
<appender name="AsynchronousLog4NetAppender" xdt:Transform="Remove" xdt:Locator="Match(name)" />
|
||||
<appender name="AsynchronousLog4NetAppender" type="Umbraco.Core.Logging.ParallelForwardingAppender,Umbraco.Core" xdt:Transform="Insert" >
|
||||
<appender-ref ref="rollingFile" />
|
||||
</appender>
|
||||
|
||||
<appender name="rollingFile" type="log4net.Appender.RollingFileAppender" xdt:Transform="InsertIfMissing">
|
||||
<file value="App_Data\Logs\UmbracoTraceLog.txt" />
|
||||
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
|
||||
<appendToFile value="true" />
|
||||
<rollingStyle value="Date" />
|
||||
<maximumFileSize value="5MB" />
|
||||
<layout type="log4net.Layout.PatternLayout">
|
||||
<conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
|
||||
</layout>
|
||||
<encoding value="utf-8" />
|
||||
</appender>
|
||||
</log4net>
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
<add initialize="false" sortOrder="0" alias="mediaRecycleBin" application="media" title="Recycle Bin" iconClosed="icon-folder" iconOpen="icon-folder" type="umbraco.cms.presentation.Trees.MediaRecycleBin, umbraco" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="stylesheets" title="Stylesheets" type="umbraco.loadStylesheets, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="0" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="stylesheetProperty" title="Stylesheet Property" type="umbraco.loadStylesheetProperty, umbraco" iconClosed="" iconOpen="" initialize="false" sortOrder="0" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="templates" title="Templates" type="umbraco.loadTemplates, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="1" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="templates" title="Templates" type="Umbraco.Web.Trees.TemplatesTreeController, umbraco" iconClosed="icon-folder" iconOpen="icon-folder-open" sortOrder="1" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="partialViews" title="Partial Views" silent="false" initialize="true" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.PartialViewsTree, umbraco" sortOrder="2" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="scripts" title="Scripts" type="umbraco.loadScripts, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="3" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="dictionary" title="Dictionary" type="umbraco.loadDictionary, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add alias="dictionary" xdt:Locator="Match(alias)" xdt:Transform="RemoveAttributes(action)" />
|
||||
<add application="settings" alias="languages" title="Languages" type="umbraco.loadLanguages, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="5" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="languages" title="Languages" type="Umbraco.Web.Trees.LanguageTreeController, umbraco" iconClosed="icon-folder" iconOpen="icon-folder-open" sortOrder="5" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="mediaTypes" title="Media Types" type="umbraco.loadMediaTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="6" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="nodeTypes" title="Document Types" type="umbraco.loadNodeTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="7" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
<add initialize="true" sortOrder="0" alias="datatype" application="developer" title="Data Types" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.DataTypeTreeController, umbraco" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes()" />
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.3.0
|
||||
beta
|
||||
RC
|
||||
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp50</s:String></wpf:ResourceDictionary>
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.3.0-beta")]
|
||||
[assembly: AssemblyInformationalVersion("7.3.0-RC")]
|
||||
@@ -1,16 +1,13 @@
|
||||
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
|
||||
{
|
||||
@@ -34,10 +31,13 @@ namespace Umbraco.Core
|
||||
if (dbContext == null) throw new ArgumentNullException("dbContext");
|
||||
if (serviceContext == null) throw new ArgumentNullException("serviceContext");
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_databaseContext = dbContext;
|
||||
_services = serviceContext;
|
||||
ApplicationCache = cache;
|
||||
ProfilingLogger = logger;
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -46,7 +46,7 @@ namespace Umbraco.Core
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <param name="cache"></param>
|
||||
[Obsolete("Use the other constructor specifying an ILogger instead")]
|
||||
[Obsolete("Use the other constructor specifying a ProfilingLogger instead")]
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
|
||||
: this(dbContext, serviceContext, cache,
|
||||
new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler))
|
||||
@@ -57,9 +57,27 @@ namespace Umbraco.Core
|
||||
/// Creates a basic app context
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
[Obsolete("Use the other constructor specifying a ProfilingLogger instead")]
|
||||
public ApplicationContext(CacheHelper cache)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
ApplicationCache = cache;
|
||||
ProfilingLogger = new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler);
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a basic app context
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
public ApplicationContext(CacheHelper cache, ProfilingLogger logger)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
ApplicationCache = cache;
|
||||
ProfilingLogger = logger;
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -75,13 +93,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>
|
||||
@@ -101,14 +119,14 @@ namespace Umbraco.Core
|
||||
[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;
|
||||
Current = ctx;
|
||||
return Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -128,14 +146,14 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, ProfilingLogger logger, bool replaceContext)
|
||||
{
|
||||
if (ApplicationContext.Current != null)
|
||||
if (Current != null)
|
||||
{
|
||||
if (!replaceContext)
|
||||
return ApplicationContext.Current;
|
||||
return Current;
|
||||
}
|
||||
var ctx = new ApplicationContext(dbContext, serviceContext, cache, logger);
|
||||
ApplicationContext.Current = ctx;
|
||||
return ApplicationContext.Current;
|
||||
Current = ctx;
|
||||
return Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -190,16 +208,10 @@ 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;
|
||||
}
|
||||
get { return _configured.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -222,47 +234,94 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The original/first url that the web application executes
|
||||
/// The application url.
|
||||
/// </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
|
||||
/// 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 OriginalRequestUrl { get; set; }
|
||||
internal string UmbracoApplicationUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
// if initialized, return
|
||||
if (_umbracoApplicationUrl != null) return _umbracoApplicationUrl;
|
||||
|
||||
private bool _versionsDifferenceReported;
|
||||
// try settings
|
||||
ServerEnvironmentHelper.TrySetApplicationUrlFromSettings(this, ProfilingLogger.Logger, UmbracoConfig.For.UmbracoSettings());
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the version configured matches the assembly version
|
||||
/// </summary>
|
||||
private bool Configured
|
||||
// and return what we have, may be null
|
||||
return _umbracoApplicationUrl;
|
||||
}
|
||||
set
|
||||
{
|
||||
_umbracoApplicationUrl = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal string _umbracoApplicationUrl; // internal for tests
|
||||
|
||||
private Lazy<bool> _configured;
|
||||
internal MainDom MainDom { get; private set; }
|
||||
|
||||
private void Init()
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var configStatus = ConfigurationStatus;
|
||||
var currentVersion = UmbracoVersion.Current.ToString(3);
|
||||
var ok = configStatus == currentVersion;
|
||||
MainDom = new MainDom(ProfilingLogger.Logger);
|
||||
MainDom.Acquire();
|
||||
|
||||
//Create the lazy value to resolve whether or not the application is 'configured'
|
||||
_configured = new Lazy<bool>(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var configStatus = ConfigurationStatus;
|
||||
var currentVersion = UmbracoVersion.GetSemanticVersion();
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
//The versions are the same in config, but are they the same in the database. We can only check this
|
||||
// if we have a db context available, if we don't then we are not installed anyways
|
||||
if (DatabaseContext.IsDatabaseConfigured && DatabaseContext.CanConnect)
|
||||
{
|
||||
var found = Services.MigrationEntryService.FindEntry(GlobalSettings.UmbracoMigrationName, UmbracoVersion.GetSemanticVersion());
|
||||
if (found == null)
|
||||
{
|
||||
//we haven't executed this migration in this environment, so even though the config versions match,
|
||||
// this db has not been updated.
|
||||
ProfilingLogger.Logger.Debug<ApplicationContext>(string.Format("The migration for version: '{0} has not been executed, there is no record in the database", currentVersion.ToSemanticString()));
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProfilingLogger.Logger.Debug<ApplicationContext>(string.Format("CurrentVersion different from configStatus: '{0}','{1}'", currentVersion.ToSemanticString(), configStatus));
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private string ConfigurationStatus
|
||||
@@ -280,12 +339,6 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertIsReady()
|
||||
{
|
||||
if (!this.IsReady)
|
||||
throw new Exception("ApplicationContext is not ready yet.");
|
||||
}
|
||||
|
||||
private void AssertIsNotReady()
|
||||
{
|
||||
if (this.IsReady)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
if (MemoryCache[key] == null) return;
|
||||
MemoryCache.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ClearCacheObjectTypes(string typeName)
|
||||
@@ -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,5 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -242,6 +242,7 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Move these to constants!
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";
|
||||
public const string UmbracoMigrationName = "Umbraco";
|
||||
|
||||
@@ -420,14 +421,15 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets a value indicating whether the current version of umbraco is configured.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if configured; otherwise, <c>false</c>.</value>
|
||||
public static bool Configured
|
||||
[Obsolete("Do not use this, it is no longer in use and will be removed from the codebase in future versions")]
|
||||
internal static bool Configured
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
string configStatus = ConfigurationStatus;
|
||||
string currentVersion = UmbracoVersion.Current.ToString(3);
|
||||
string currentVersion = UmbracoVersion.GetSemanticVersion().ToSemanticString();
|
||||
|
||||
|
||||
if (currentVersion != configStatus)
|
||||
@@ -594,10 +596,7 @@ namespace Umbraco.Core.Configuration
|
||||
[Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)]
|
||||
public static string CurrentVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return UmbracoVersion.Current.ToString(3);
|
||||
}
|
||||
get { return UmbracoVersion.GetSemanticVersion().ToSemanticString(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.IO;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Grid
|
||||
{
|
||||
class GridConfig : IGridConfig
|
||||
{
|
||||
public GridConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug)
|
||||
{
|
||||
EditorsConfig = new GridEditorsConfig(logger, runtimeCache, appPlugins, configFolder, isDebug);
|
||||
}
|
||||
|
||||
public IGridEditorsConfig EditorsConfig { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Grid
|
||||
{
|
||||
class GridEditorsConfig : IGridEditorsConfig
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IRuntimeCacheProvider _runtimeCache;
|
||||
private readonly DirectoryInfo _appPlugins;
|
||||
private readonly DirectoryInfo _configFolder;
|
||||
private readonly bool _isDebug;
|
||||
|
||||
public GridEditorsConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug)
|
||||
{
|
||||
_logger = logger;
|
||||
_runtimeCache = runtimeCache;
|
||||
_appPlugins = appPlugins;
|
||||
_configFolder = configFolder;
|
||||
_isDebug = isDebug;
|
||||
}
|
||||
|
||||
public IEnumerable<IGridEditorConfig> Editors
|
||||
{
|
||||
get
|
||||
{
|
||||
Func<List<GridEditor>> getResult = () =>
|
||||
{
|
||||
var editors = new List<GridEditor>();
|
||||
var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js");
|
||||
if (File.Exists(gridConfig))
|
||||
{
|
||||
try
|
||||
{
|
||||
var arr = JArray.Parse(File.ReadAllText(gridConfig));
|
||||
//ensure the contents parse correctly to objects
|
||||
var parsed = ManifestParser.GetGridEditors(arr);
|
||||
editors.AddRange(parsed);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<GridEditorsConfig>("Could not parse the contents of grid.editors.config.js into a JSON array", ex);
|
||||
}
|
||||
}
|
||||
|
||||
var parser = new ManifestParser(_appPlugins, _runtimeCache);
|
||||
var builder = new ManifestBuilder(_runtimeCache, parser);
|
||||
foreach (var gridEditor in builder.GridEditors)
|
||||
{
|
||||
//no duplicates! (based on alias)
|
||||
if (editors.Contains(gridEditor) == false)
|
||||
{
|
||||
editors.Add(gridEditor);
|
||||
}
|
||||
}
|
||||
return editors;
|
||||
};
|
||||
|
||||
//cache the result if debugging is disabled
|
||||
var result = _isDebug
|
||||
? getResult()
|
||||
: _runtimeCache.GetCacheItem<List<GridEditor>>(
|
||||
typeof(GridEditorsConfig) + "Editors",
|
||||
() => getResult(),
|
||||
TimeSpan.FromMinutes(10));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Grid
|
||||
{
|
||||
public interface IGridConfig
|
||||
{
|
||||
|
||||
IGridEditorsConfig EditorsConfig { get; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Grid
|
||||
{
|
||||
public interface IGridEditorConfig
|
||||
{
|
||||
string Name { get; }
|
||||
string Alias { get; }
|
||||
string View { get; }
|
||||
string Render { get; }
|
||||
string Icon { get; }
|
||||
IDictionary<string, object> Config { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Grid
|
||||
{
|
||||
public interface IGridEditorsConfig
|
||||
{
|
||||
IEnumerable<IGridEditorConfig> Editors { get; }
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,13 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.BaseRest;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Configuration.Grid;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -67,6 +70,7 @@ namespace Umbraco.Core.Configuration
|
||||
private IDashboardSection _dashboardSection;
|
||||
private IUmbracoSettingsSection _umbracoSettings;
|
||||
private IBaseRestSection _baseRestExtensions;
|
||||
private IGridConfig _gridConfig;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IDashboardSection
|
||||
@@ -140,6 +144,28 @@ namespace Umbraco.Core.Configuration
|
||||
return _baseRestExtensions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetGridConfig(IGridConfig value)
|
||||
{
|
||||
_gridConfig = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IGridConfig
|
||||
/// </summary>
|
||||
public IGridConfig GridConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug)
|
||||
{
|
||||
if (_gridConfig == null)
|
||||
{
|
||||
_gridConfig = new GridConfig(logger, runtimeCache, appPlugins, configFolder, isDebug);
|
||||
}
|
||||
|
||||
return _gridConfig;
|
||||
}
|
||||
|
||||
//TODO: Add other configurations here !
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@
|
||||
bool DisableFindContentByIdPath { get; }
|
||||
|
||||
string UrlProviderMode { get; }
|
||||
|
||||
string UmbracoApplicationUrl { get; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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"]; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Semver;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
@@ -23,10 +24,20 @@ 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 "RC"; } }
|
||||
|
||||
// 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
|
||||
public static string AssemblyVersion { get { return new AssemblyName(typeof(ActionsResolver).Assembly.FullName).Version.ToString(); } }
|
||||
|
||||
public static SemVersion GetSemanticVersion()
|
||||
{
|
||||
return new SemVersion(
|
||||
Current.Major,
|
||||
Current.Minor,
|
||||
Current.Build,
|
||||
CurrentComment.IsNullOrWhiteSpace() ? null : CurrentComment,
|
||||
Current.Revision > 0 ? Current.Revision.ToInvariantString() : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// The root id for all top level dictionary items
|
||||
/// </summary>
|
||||
[Obsolete("There is no dictionary root item id anymore, it is simply null")]
|
||||
public const string DictionaryItemRootId = "41c7638d-f529-4bff-853e-59a0c2fb1bde";
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
public const string BackOfficeExternalAuthenticationType = "UmbracoExternalCookie";
|
||||
public const string BackOfficeExternalCookieName = "UMB_EXTLOGIN";
|
||||
public const string BackOfficeTokenAuthenticationType = "UmbracoBackOfficeToken";
|
||||
public const string BackOfficeTwoFactorAuthenticationType = "UmbracoTwoFactorCookie";
|
||||
|
||||
/// <summary>
|
||||
/// The prefix used for external identity providers for their authentication type
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
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.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
@@ -39,15 +42,15 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public class CoreBootManager : IBootManager
|
||||
{
|
||||
private ProfilingLogger _profilingLogger;
|
||||
protected ProfilingLogger ProfilingLogger { get; private set; }
|
||||
private DisposableTimer _timer;
|
||||
private bool _isInitialized = false;
|
||||
private bool _isStarted = false;
|
||||
private bool _isComplete = false;
|
||||
private readonly IServiceProvider _serviceProvider = new ActivatorServiceProvider();
|
||||
private readonly UmbracoApplicationBase _umbracoApplication;
|
||||
protected ApplicationContext ApplicationContext { get; set; }
|
||||
protected CacheHelper ApplicationCache { get; set; }
|
||||
protected ApplicationContext ApplicationContext { get; private set; }
|
||||
protected CacheHelper ApplicationCache { get; private set; }
|
||||
protected PluginManager PluginManager { get; private set; }
|
||||
|
||||
protected UmbracoApplicationBase UmbracoApplication
|
||||
@@ -66,6 +69,14 @@ namespace Umbraco.Core
|
||||
_umbracoApplication = umbracoApplication;
|
||||
}
|
||||
|
||||
internal CoreBootManager(UmbracoApplicationBase umbracoApplication, ProfilingLogger logger)
|
||||
{
|
||||
if (umbracoApplication == null) throw new ArgumentNullException("umbracoApplication");
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_umbracoApplication = umbracoApplication;
|
||||
ProfilingLogger = logger;
|
||||
}
|
||||
|
||||
public virtual IBootManager Initialize()
|
||||
{
|
||||
if (_isInitialized)
|
||||
@@ -74,15 +85,17 @@ namespace Umbraco.Core
|
||||
InitializeLoggerResolver();
|
||||
InitializeProfilerResolver();
|
||||
|
||||
_profilingLogger = new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler);
|
||||
ProfilingLogger = ProfilingLogger?? new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler);
|
||||
|
||||
_timer = _profilingLogger.TraceDuration<CoreBootManager>("Umbraco application starting", "Umbraco application startup complete");
|
||||
_timer = ProfilingLogger.TraceDuration<CoreBootManager>(
|
||||
string.Format("Umbraco {0} application starting on {1}", UmbracoVersion.GetSemanticVersion().ToSemanticString(), NetworkHelper.MachineName),
|
||||
"Umbraco application startup complete");
|
||||
|
||||
CreateApplicationCache();
|
||||
ApplicationCache = 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 = new PluginManager(ServiceProvider, ApplicationCache.RuntimeCache, ProfilingLogger);
|
||||
PluginManager.Current = PluginManager;
|
||||
|
||||
//Create the legacy prop-eds mapping
|
||||
@@ -90,38 +103,48 @@ namespace Umbraco.Core
|
||||
LegacyParameterEditorAliasConverter.CreateMappingsForCoreEditors();
|
||||
|
||||
//create database and service contexts for the app context
|
||||
var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, LoggerResolver.Current.Logger);
|
||||
var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, ProfilingLogger.Logger);
|
||||
Database.Mapper = new PetaPocoMapper();
|
||||
|
||||
var dbContext = new DatabaseContext(
|
||||
dbFactory,
|
||||
LoggerResolver.Current.Logger,
|
||||
SqlSyntaxProviders.CreateDefault(LoggerResolver.Current.Logger));
|
||||
ProfilingLogger.Logger,
|
||||
SqlSyntaxProviders.CreateDefault(ProfilingLogger.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);
|
||||
|
||||
CreateApplicationContext(dbContext, serviceContext);
|
||||
//get the service context
|
||||
var serviceContext = CreateServiceContext(dbContext, dbFactory);
|
||||
|
||||
//set property and singleton from response
|
||||
ApplicationContext.Current = ApplicationContext = CreateApplicationContext(dbContext, serviceContext);
|
||||
|
||||
InitializeApplicationEventsResolver();
|
||||
|
||||
InitializeResolvers();
|
||||
|
||||
|
||||
|
||||
InitializeModelMappers();
|
||||
|
||||
//now we need to call the initialize methods
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext));
|
||||
using (ProfilingLogger.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)
|
||||
{
|
||||
ProfilingLogger.Logger.Error<CoreBootManager>("An error occurred running OnApplicationInitialized for handler " + x.GetType(), ex);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
|
||||
@@ -129,28 +152,48 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and assigns the application context singleton
|
||||
/// Creates and returns the service context for the app
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
protected virtual void CreateApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
|
||||
/// <param name="dbFactory"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual ServiceContext CreateServiceContext(DatabaseContext dbContext, IDatabaseFactory dbFactory)
|
||||
{
|
||||
//create the ApplicationContext
|
||||
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext, ApplicationCache, _profilingLogger);
|
||||
//default transient factory
|
||||
var msgFactory = new TransientMessagesFactory();
|
||||
return new ServiceContext(
|
||||
new RepositoryFactory(ApplicationCache, ProfilingLogger.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
|
||||
new PetaPocoUnitOfWorkProvider(dbFactory),
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy(msgFactory, ProfilingLogger.Logger),
|
||||
ApplicationCache,
|
||||
ProfilingLogger.Logger,
|
||||
msgFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and assigns the ApplicationCache based on a new instance of System.Web.Caching.Cache
|
||||
/// Creates and returns the application context for the app
|
||||
/// </summary>
|
||||
protected virtual void CreateApplicationCache()
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
protected virtual ApplicationContext CreateApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
|
||||
{
|
||||
//create the ApplicationContext
|
||||
return new ApplicationContext(dbContext, serviceContext, ApplicationCache, ProfilingLogger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and returns the CacheHelper for the app
|
||||
/// </summary>
|
||||
protected virtual CacheHelper CreateApplicationCache()
|
||||
{
|
||||
var cacheHelper = new CacheHelper(
|
||||
new ObjectCacheRuntimeCacheProvider(),
|
||||
new StaticCacheProvider(),
|
||||
new ObjectCacheRuntimeCacheProvider(),
|
||||
new StaticCacheProvider(),
|
||||
//we have no request based cache when not running in web-based context
|
||||
new NullCacheProvider());
|
||||
new NullCacheProvider());
|
||||
|
||||
ApplicationCache = cacheHelper;
|
||||
return cacheHelper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -176,7 +219,7 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
protected virtual void InitializeLoggerResolver()
|
||||
{
|
||||
LoggerResolver.Current = new LoggerResolver(Logger.CreateWithDefaultLog4NetConfiguration())
|
||||
LoggerResolver.Current = new LoggerResolver(ProfilingLogger == null ? Logger.CreateWithDefaultLog4NetConfiguration() : ProfilingLogger.Logger)
|
||||
{
|
||||
//This is another special resolver that needs to be resolvable before resolution is frozen
|
||||
//since it is used for profiling the application startup
|
||||
@@ -190,7 +233,7 @@ namespace Umbraco.Core
|
||||
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))
|
||||
ProfilerResolver.Current = new ProfilerResolver(ProfilingLogger == null ? new LogProfiler(LoggerResolver.Current.Logger) : ProfilingLogger.Profiler)
|
||||
{
|
||||
//This is another special resolver that needs to be resolvable before resolution is frozen
|
||||
//since it is used for profiling the application startup
|
||||
@@ -211,7 +254,7 @@ namespace Umbraco.Core
|
||||
//... and set the special flag to let us resolve before frozen resolution
|
||||
ApplicationEventsResolver.Current = new ApplicationEventsResolver(
|
||||
ServiceProvider,
|
||||
LoggerResolver.Current.Logger,
|
||||
ProfilingLogger.Logger,
|
||||
PluginManager.ResolveApplicationStartupHandlers())
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
@@ -226,7 +269,7 @@ namespace Umbraco.Core
|
||||
/// <param name="rootPath">Absolute</param>
|
||||
protected virtual void InitializeApplicationRootPath(string rootPath)
|
||||
{
|
||||
Umbraco.Core.IO.IOHelper.SetRootDirectory(rootPath);
|
||||
IOHelper.SetRootDirectory(rootPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -240,11 +283,27 @@ namespace Umbraco.Core
|
||||
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 (ProfilingLogger.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)
|
||||
{
|
||||
ProfilingLogger.Logger.Error<CoreBootManager>("An error occurred running OnApplicationStarting for handler " + x.GetType(), ex);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (afterStartup != null)
|
||||
if (afterStartup != null)
|
||||
{
|
||||
afterStartup(ApplicationContext.Current);
|
||||
}
|
||||
@@ -263,12 +322,37 @@ namespace Umbraco.Core
|
||||
{
|
||||
if (_isComplete)
|
||||
throw new InvalidOperationException("The boot manager has already been completed");
|
||||
|
||||
|
||||
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();
|
||||
|
||||
|
||||
//This is a special case for the user service, we need to tell it if it's an upgrade, if so we need to ensure that
|
||||
// exceptions are bubbled up if a user is attempted to be persisted during an upgrade (i.e. when they auth to login)
|
||||
((UserService) ApplicationContext.Services.UserService).IsUpgrading = true;
|
||||
|
||||
|
||||
using (ProfilingLogger.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)
|
||||
{
|
||||
ProfilingLogger.Logger.Error<CoreBootManager>("An error occurred running OnApplicationStarted for handler " + x.GetType(), ex);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Now, startup all of our legacy startup handler
|
||||
ApplicationEventsResolver.Current.InstantiateLegacyStartupHandlers();
|
||||
@@ -286,6 +370,36 @@ namespace Umbraco.Core
|
||||
//stop the timer and log the output
|
||||
_timer.Dispose();
|
||||
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;
|
||||
|
||||
//try now
|
||||
if (ApplicationContext.DatabaseContext.CanConnect)
|
||||
return;
|
||||
|
||||
var currentTry = 0;
|
||||
while (currentTry < 5)
|
||||
{
|
||||
//first wait, then retry
|
||||
Thread.Sleep(1000);
|
||||
|
||||
if (ApplicationContext.DatabaseContext.CanConnect)
|
||||
break;
|
||||
|
||||
currentTry++;
|
||||
}
|
||||
|
||||
if (currentTry == 5)
|
||||
{
|
||||
throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but the Umbraco cannot connect to the database.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -305,12 +419,12 @@ namespace Umbraco.Core
|
||||
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(ServiceProvider, ProfilingLogger.Logger, () => PluginManager.ResolvePropertyEditors(), builder);
|
||||
ParameterEditorResolver.Current = new ParameterEditorResolver(ServiceProvider, ProfilingLogger.Logger, () => PluginManager.ResolveParameterEditors(), builder);
|
||||
|
||||
//setup the validators resolver with our predefined validators
|
||||
ValidatorsResolver.Current = new ValidatorsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger, new[]
|
||||
ServiceProvider, ProfilingLogger.Logger, new[]
|
||||
{
|
||||
new Lazy<Type>(() => typeof (RequiredManifestValueValidator)),
|
||||
new Lazy<Type>(() => typeof (RegexValidator)),
|
||||
@@ -319,67 +433,76 @@ namespace Umbraco.Core
|
||||
new Lazy<Type>(() => typeof (IntegerValidator)),
|
||||
});
|
||||
|
||||
//by default we'll use the standard configuration based sync
|
||||
ServerRegistrarResolver.Current = new ServerRegistrarResolver(
|
||||
new ConfigServerRegistrar());
|
||||
//by default we'll use the db server registrar unless the developer has the legacy
|
||||
// dist calls enabled, in which case we'll use the config server registrar
|
||||
if (UmbracoConfig.For.UmbracoSettings().DistributedCall.Enabled)
|
||||
{
|
||||
ServerRegistrarResolver.Current = new ServerRegistrarResolver(new ConfigServerRegistrar());
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerRegistrarResolver.Current = new ServerRegistrarResolver(
|
||||
new DatabaseServerRegistrar(
|
||||
new Lazy<IServerRegistrationService>(() => ApplicationContext.Services.ServerRegistrationService),
|
||||
new DatabaseServerRegistrarOptions()));
|
||||
}
|
||||
|
||||
|
||||
//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
|
||||
//by default we'll use the database server messenger with default options (no callbacks),
|
||||
// this will be overridden in the web startup
|
||||
ServerMessengerResolver.Current = new ServerMessengerResolver(
|
||||
new WebServiceServerMessenger());
|
||||
new DatabaseServerMessenger(ApplicationContext, true, new DatabaseServerMessengerOptions()));
|
||||
|
||||
MappingResolver.Current = new MappingResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolveAssignedMapperTypes());
|
||||
|
||||
|
||||
|
||||
//RepositoryResolver.Current = new RepositoryResolver(
|
||||
// new RepositoryFactory(ApplicationCache));
|
||||
|
||||
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolveCacheRefreshers());
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolveDataTypes());
|
||||
|
||||
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolveMacroRenderings());
|
||||
|
||||
PackageActionsResolver.Current = new PackageActionsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolvePackageActions());
|
||||
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolveActions());
|
||||
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(
|
||||
LoggerResolver.Current.Logger,
|
||||
ProfilingLogger.Logger,
|
||||
() => PluginManager.ResolveTypes<IMigration>());
|
||||
|
||||
// todo: remove once we drop IPropertyEditorValueConverter support.
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
PluginManager.ResolvePropertyEditorValueConverters());
|
||||
|
||||
// need to filter out the ones we dont want!!
|
||||
PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
PluginManager.ResolveTypes<IPropertyValueConverter>());
|
||||
|
||||
// use the new DefaultShortStringHelper
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
//new LegacyShortStringHelper());
|
||||
new DefaultShortStringHelper().WithDefaultConfig());
|
||||
new DefaultShortStringHelper(UmbracoConfig.For.UmbracoSettings()).WithDefaultConfig());
|
||||
|
||||
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
ServiceProvider, ProfilingLogger.Logger,
|
||||
typeof(DefaultUrlSegmentProvider));
|
||||
|
||||
// by default, no factory is activated
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Xml.Linq;
|
||||
using Semver;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -13,6 +14,7 @@ using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -28,8 +30,6 @@ namespace Umbraco.Core
|
||||
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;
|
||||
@@ -90,7 +90,7 @@ namespace Umbraco.Core
|
||||
/// This should not be used for CRUD operations or queries against the
|
||||
/// standard Umbraco tables! Use the Public services for that.
|
||||
/// </remarks>
|
||||
public UmbracoDatabase Database
|
||||
public virtual UmbracoDatabase Database
|
||||
{
|
||||
get { return _factory.CreateDatabase(); }
|
||||
}
|
||||
@@ -98,7 +98,7 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the database has been configured
|
||||
/// </summary>
|
||||
public bool IsDatabaseConfigured
|
||||
public virtual bool IsDatabaseConfigured
|
||||
{
|
||||
get { return _configured; }
|
||||
}
|
||||
@@ -106,33 +106,21 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Determines if the db can be connected to
|
||||
/// </summary>
|
||||
public bool CanConnect
|
||||
public virtual bool CanConnect
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configured umbraco db connection string.
|
||||
/// </summary>
|
||||
public string ConnectionString
|
||||
public virtual string ConnectionString
|
||||
{
|
||||
get { return _connectionString; }
|
||||
}
|
||||
@@ -150,7 +138,7 @@ namespace Umbraco.Core
|
||||
_providerName = "System.Data.SqlClient";
|
||||
if (ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName] != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName))
|
||||
if (string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName) == false)
|
||||
_providerName = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName;
|
||||
}
|
||||
else
|
||||
@@ -164,7 +152,7 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Returns the Type of DatabaseProvider used
|
||||
/// </summary>
|
||||
public DatabaseProviders DatabaseProvider
|
||||
public virtual DatabaseProviders DatabaseProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -541,7 +529,7 @@ namespace Umbraco.Core
|
||||
return _result;
|
||||
}
|
||||
|
||||
internal Result CreateDatabaseSchemaAndData()
|
||||
internal Result CreateDatabaseSchemaAndData(ApplicationContext applicationContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -578,12 +566,15 @@ namespace Umbraco.Core
|
||||
message = GetResultMessageForMySql();
|
||||
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedVersion = schemaResult.DetermineInstalledVersion();
|
||||
|
||||
var installedSchemaVersion = schemaResult.DetermineInstalledVersion();
|
||||
|
||||
//If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedVersion.Equals(new Version(0, 0, 0)))
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedSchemaVersion.Equals(new Version(0, 0, 0)))
|
||||
{
|
||||
database.CreateDatabaseSchema();
|
||||
var helper = new DatabaseSchemaHelper(database, _logger, SqlSyntax);
|
||||
helper.CreateDatabaseSchema(true, applicationContext);
|
||||
|
||||
message = message + "<p>Installation completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
@@ -612,7 +603,7 @@ namespace Umbraco.Core
|
||||
/// This assumes all of the previous checks are done!
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal Result UpgradeSchemaAndData()
|
||||
internal Result UpgradeSchemaAndData(IMigrationEntryService migrationEntryService)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -631,16 +622,56 @@ namespace Umbraco.Core
|
||||
var message = GetResultMessageForMySql();
|
||||
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedVersion = schemaResult.DetermineInstalledVersion();
|
||||
|
||||
var installedSchemaVersion = new SemVersion(schemaResult.DetermineInstalledVersion());
|
||||
|
||||
var installedMigrationVersion = new SemVersion(0);
|
||||
//we cannot check the migrations table if it doesn't exist, this will occur when upgrading to 7.3
|
||||
if (schemaResult.ValidTables.Any(x => x.InvariantEquals("umbracoMigration")))
|
||||
{
|
||||
installedMigrationVersion = schemaResult.DetermineInstalledVersionByMigrations(migrationEntryService);
|
||||
}
|
||||
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
|
||||
//In some cases - like upgrading from 7.2.6 -> 7.3, there will be no migration information in the database and therefore it will
|
||||
// return a version of 0.0.0 and we don't necessarily want to run all migrations from 0 -> 7.3, so we'll just ensure that the
|
||||
// migrations are run for the target version
|
||||
if (installedMigrationVersion == new SemVersion(new Version(0, 0, 0)) && installedSchemaVersion > new SemVersion(new Version(0, 0, 0)))
|
||||
{
|
||||
//set the installedMigrationVersion to be one less than the target so the latest migrations are guaranteed to execute
|
||||
installedMigrationVersion = new SemVersion(targetVersion.SubtractRevision());
|
||||
}
|
||||
|
||||
//Figure out what our current installed version is. If the web.config doesn't have a version listed, then we'll use the minimum
|
||||
// version detected between the schema installed and the migrations listed in the migration table.
|
||||
// If there is a version in the web.config, we'll take the minimum between the listed migration in the db and what
|
||||
// is declared in the web.config.
|
||||
|
||||
var currentInstalledVersion = string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus)
|
||||
//Take the minimum version between the detected schema version and the installed migration version
|
||||
? new[] {installedSchemaVersion, installedMigrationVersion}.Min()
|
||||
//Take the minimum version between the installed migration version and the version specified in the config
|
||||
: new[] { SemVersion.Parse(GlobalSettings.ConfigurationStatus), installedMigrationVersion }.Min();
|
||||
|
||||
//Ok, another edge case here. If the current version is a pre-release,
|
||||
// then we want to ensure all migrations for the current release are executed.
|
||||
if (currentInstalledVersion.Prerelease.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
currentInstalledVersion = new SemVersion(currentInstalledVersion.GetVersion().SubtractRevision());
|
||||
}
|
||||
|
||||
//DO the upgrade!
|
||||
|
||||
var currentVersion = string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus)
|
||||
? installedVersion
|
||||
: new Version(GlobalSettings.ConfigurationStatus);
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
var runner = new MigrationRunner(_logger, currentVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
|
||||
var runner = new MigrationRunner(migrationEntryService, _logger, currentInstalledVersion, UmbracoVersion.GetSemanticVersion(), GlobalSettings.UmbracoMigrationName);
|
||||
|
||||
var upgraded = runner.Execute(database, true);
|
||||
|
||||
if (upgraded == false)
|
||||
{
|
||||
throw new ApplicationException("Upgrading failed, either an error occurred during the upgrade process or an event canceled the upgrade process, see log for full details");
|
||||
}
|
||||
|
||||
message = message + "<p>Upgrade completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static class DelegateExtensions
|
||||
{
|
||||
public static Attempt<T> RetryUntilSuccessOrTimeout<T>(this Func<Attempt<T>> task, TimeSpan timeout, TimeSpan pause)
|
||||
{
|
||||
if (pause.TotalMilliseconds < 0)
|
||||
{
|
||||
throw new ArgumentException("pause must be >= 0 milliseconds");
|
||||
}
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
do
|
||||
{
|
||||
var result = task();
|
||||
if (result) { return result; }
|
||||
Thread.Sleep((int)pause.TotalMilliseconds);
|
||||
}
|
||||
while (stopwatch.Elapsed < timeout);
|
||||
return Attempt<T>.Fail();
|
||||
}
|
||||
|
||||
public static Attempt<T> RetryUntilSuccessOrMaxAttempts<T>(this Func<int, Attempt<T>> task, int totalAttempts, TimeSpan pause)
|
||||
{
|
||||
if (pause.TotalMilliseconds < 0)
|
||||
{
|
||||
throw new ArgumentException("pause must be >= 0 milliseconds");
|
||||
}
|
||||
int attempts = 0;
|
||||
do
|
||||
{
|
||||
attempts++;
|
||||
var result = task(attempts);
|
||||
if (result) { return result; }
|
||||
Thread.Sleep((int)pause.TotalMilliseconds);
|
||||
}
|
||||
while (attempts < totalAttempts);
|
||||
return Attempt<T>.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,7 @@ namespace Umbraco.Core
|
||||
/// <param name="f">The select child.</param>
|
||||
/// <typeparam name="T">Item type</typeparam>
|
||||
/// <returns>list of TItem</returns>
|
||||
[Obsolete("Do not use, use SelectRecursive instead which has far less potential of re-iterating an iterator which may cause significantly more SQL queries")]
|
||||
public static IEnumerable<T> FlattenList<T>(this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
|
||||
{
|
||||
return e.SelectMany(c => f(c).FlattenList(f)).Concat(e);
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Security.Permissions;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Event args for that can support cancellation
|
||||
/// </summary>
|
||||
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
|
||||
@@ -11,15 +11,30 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
private bool _cancel;
|
||||
|
||||
public CancellableEventArgs(bool canCancel)
|
||||
public CancellableEventArgs(bool canCancel, EventMessages eventMessages)
|
||||
{
|
||||
if (eventMessages == null) throw new ArgumentNullException("eventMessages");
|
||||
CanCancel = canCancel;
|
||||
Messages = eventMessages;
|
||||
}
|
||||
|
||||
public CancellableEventArgs(bool canCancel)
|
||||
{
|
||||
CanCancel = canCancel;
|
||||
}
|
||||
//create a standalone messages
|
||||
Messages = new EventMessages();
|
||||
}
|
||||
|
||||
public CancellableEventArgs()
|
||||
public CancellableEventArgs(EventMessages eventMessages)
|
||||
: this(true, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
public CancellableEventArgs()
|
||||
: this(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flag to determine if this instance will support being cancellable
|
||||
/// </summary>
|
||||
@@ -32,7 +47,7 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!CanCancel)
|
||||
if (CanCancel == false)
|
||||
{
|
||||
throw new InvalidOperationException("This event argument class does not support cancelling.");
|
||||
}
|
||||
@@ -40,12 +55,28 @@ namespace Umbraco.Core.Events
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!CanCancel)
|
||||
if (CanCancel == false)
|
||||
{
|
||||
throw new InvalidOperationException("This event argument class does not support cancelling.");
|
||||
}
|
||||
_cancel = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// if this instance supports cancellation, this will set Cancel to true with an affiliated cancellation message
|
||||
/// </summary>
|
||||
/// <param name="cancelationMessage"></param>
|
||||
public void CancelOperation(EventMessage cancelationMessage)
|
||||
{
|
||||
Cancel = true;
|
||||
cancelationMessage.IsDefaultEventMessage = true;
|
||||
Messages.Add(cancelationMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the EventMessages object which is used to add messages to the message collection for this event
|
||||
/// </summary>
|
||||
public EventMessages Messages { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,18 @@ namespace Umbraco.Core.Events
|
||||
public class CancellableObjectEventArgs<T> : CancellableEventArgs
|
||||
{
|
||||
|
||||
public CancellableObjectEventArgs(T eventObject, bool canCancel)
|
||||
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages eventMessages)
|
||||
: base(canCancel, eventMessages)
|
||||
{
|
||||
EventObject = eventObject;
|
||||
}
|
||||
|
||||
public CancellableObjectEventArgs(T eventObject, EventMessages eventMessages)
|
||||
: this(eventObject, true, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
public CancellableObjectEventArgs(T eventObject, bool canCancel)
|
||||
: base(canCancel)
|
||||
{
|
||||
EventObject = eventObject;
|
||||
|
||||
@@ -4,12 +4,56 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
public class DeleteEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
public DeleteEventArgs(IEnumerable<TEntity> eventObject, bool canCancel) : base(eventObject, canCancel)
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public DeleteEventArgs(IEnumerable<TEntity> eventObject, bool canCancel, EventMessages eventMessages) : base(eventObject, canCancel, eventMessages)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public DeleteEventArgs(IEnumerable<TEntity> eventObject, EventMessages eventMessages) : base(eventObject, eventMessages)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public DeleteEventArgs(TEntity eventObject, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, eventMessages)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public DeleteEventArgs(TEntity eventObject, bool canCancel, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, canCancel, eventMessages)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
public DeleteEventArgs(IEnumerable<TEntity> eventObject, bool canCancel) : base(eventObject, canCancel)
|
||||
{
|
||||
MediaFilesToDelete = new List<string>();
|
||||
}
|
||||
@@ -60,7 +104,13 @@ namespace Umbraco.Core.Events
|
||||
|
||||
public class DeleteEventArgs : CancellableEventArgs
|
||||
{
|
||||
public DeleteEventArgs(int id, bool canCancel)
|
||||
public DeleteEventArgs(int id, bool canCancel, EventMessages eventMessages)
|
||||
: base(canCancel, eventMessages)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public DeleteEventArgs(int id, bool canCancel)
|
||||
: base(canCancel)
|
||||
{
|
||||
Id = id;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
@@ -7,16 +8,16 @@ namespace Umbraco.Core.Events
|
||||
/// </summary>
|
||||
public static class EventExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Raises the event and returns a boolean value indicating if the event was cancelled
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender"></typeparam>
|
||||
/// <typeparam name="TArgs"></typeparam>
|
||||
/// <param name="eventHandler"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <param name="sender"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsRaisedEventCancelled<TSender, TArgs>(
|
||||
/// <summary>
|
||||
/// Raises the event and returns a boolean value indicating if the event was cancelled
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender"></typeparam>
|
||||
/// <typeparam name="TArgs"></typeparam>
|
||||
/// <param name="eventHandler"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <param name="sender"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsRaisedEventCancelled<TSender, TArgs>(
|
||||
this TypedEventHandler<TSender, TArgs> eventHandler,
|
||||
TArgs args,
|
||||
TSender sender)
|
||||
@@ -27,16 +28,16 @@ namespace Umbraco.Core.Events
|
||||
|
||||
return args.Cancel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the event
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender"></typeparam>
|
||||
/// <typeparam name="TArgs"></typeparam>
|
||||
/// <param name="eventHandler"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <param name="sender"></param>
|
||||
public static void RaiseEvent<TSender, TArgs>(
|
||||
|
||||
/// <summary>
|
||||
/// Raises the event
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender"></typeparam>
|
||||
/// <typeparam name="TArgs"></typeparam>
|
||||
/// <param name="eventHandler"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <param name="sender"></param>
|
||||
public static void RaiseEvent<TSender, TArgs>(
|
||||
this TypedEventHandler<TSender, TArgs> eventHandler,
|
||||
TArgs args,
|
||||
TSender sender)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// An event message
|
||||
/// </summary>
|
||||
public sealed class EventMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EventMessage"/> class.
|
||||
/// </summary>
|
||||
public EventMessage(string category, string message, EventMessageType messageType = EventMessageType.Default)
|
||||
{
|
||||
Category = category;
|
||||
Message = message;
|
||||
MessageType = messageType;
|
||||
}
|
||||
|
||||
public string Category { get; private set; }
|
||||
public string Message { get; private set; }
|
||||
public EventMessageType MessageType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is used to track if this message should be used as a default message so that Umbraco doesn't also append it's own default messages
|
||||
/// </summary>
|
||||
internal bool IsDefaultEventMessage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event messages collection
|
||||
/// </summary>
|
||||
public sealed class EventMessages : DisposableObject
|
||||
{
|
||||
private readonly List<EventMessage> _msgs = new List<EventMessage>();
|
||||
|
||||
public void Add(EventMessage msg)
|
||||
{
|
||||
_msgs.Add(msg);
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _msgs.Count; }
|
||||
}
|
||||
|
||||
public IEnumerable<EventMessage> GetAll()
|
||||
{
|
||||
return _msgs;
|
||||
}
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
_msgs.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Event messages factory
|
||||
/// </summary>
|
||||
public interface IEventMessagesFactory
|
||||
{
|
||||
EventMessages Get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of event message
|
||||
/// </summary>
|
||||
public enum EventMessageType
|
||||
{
|
||||
Default = 0,
|
||||
Info = 1,
|
||||
Error = 2,
|
||||
Success = 3,
|
||||
Warning = 4
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Semver;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
@@ -13,11 +15,20 @@ namespace Umbraco.Core.Events
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
}
|
||||
|
||||
[Obsolete("Use constructor accepting UmbracoVersion instances instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
ConfiguredVersion = configuredVersion;
|
||||
TargetVersion = targetVersion;
|
||||
ConfiguredSemVersion = new SemVersion(configuredVersion);
|
||||
TargetSemVersion = new SemVersion(targetVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -28,12 +39,12 @@ namespace Umbraco.Core.Events
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, Version configuredVersion, Version targetVersion, bool canCancel)
|
||||
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
MigrationContext = migrationContext;
|
||||
ConfiguredVersion = configuredVersion;
|
||||
TargetVersion = targetVersion;
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,11 +53,20 @@ namespace Umbraco.Core.Events
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion)
|
||||
: base(eventObject)
|
||||
{
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
}
|
||||
|
||||
[Obsolete("Use constructor accepting UmbracoVersion instances instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion)
|
||||
: base(eventObject)
|
||||
{
|
||||
ConfiguredVersion = configuredVersion;
|
||||
TargetVersion = targetVersion;
|
||||
ConfiguredSemVersion = new SemVersion(configuredVersion);
|
||||
TargetSemVersion = new SemVersion(targetVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,9 +77,23 @@ namespace Umbraco.Core.Events
|
||||
get { return EventObject; }
|
||||
}
|
||||
|
||||
public Version ConfiguredVersion { get; private set; }
|
||||
[Obsolete("Use ConfiguredSemVersion instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Version ConfiguredVersion
|
||||
{
|
||||
get { return ConfiguredSemVersion.GetVersion(); }
|
||||
}
|
||||
|
||||
public Version TargetVersion { get; private set; }
|
||||
[Obsolete("Use TargetUmbracoVersion instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Version TargetVersion
|
||||
{
|
||||
get { return TargetSemVersion.GetVersion(); }
|
||||
}
|
||||
|
||||
public SemVersion ConfiguredSemVersion { get; private set; }
|
||||
|
||||
public SemVersion TargetSemVersion { get; private set; }
|
||||
|
||||
internal MigrationContext MigrationContext { get; private set; }
|
||||
}
|
||||
|
||||
@@ -4,22 +4,51 @@ using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
public class MoveEventInfo<TEntity>
|
||||
{
|
||||
public MoveEventInfo(TEntity entity, string originalPath, int newParentId)
|
||||
{
|
||||
Entity = entity;
|
||||
OriginalPath = originalPath;
|
||||
NewParentId = newParentId;
|
||||
}
|
||||
|
||||
public TEntity Entity { get; set; }
|
||||
public string OriginalPath { get; set; }
|
||||
public int NewParentId { get; set; }
|
||||
}
|
||||
|
||||
public class MoveEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting a collection of MoveEventInfo objects
|
||||
/// </summary>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
/// <param name="moveInfo">
|
||||
/// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation
|
||||
/// </param>
|
||||
public MoveEventArgs(bool canCancel, EventMessages eventMessages, params MoveEventInfo<TEntity>[] moveInfo)
|
||||
: base(default(TEntity), canCancel, eventMessages)
|
||||
{
|
||||
if (moveInfo.FirstOrDefault() == null)
|
||||
{
|
||||
throw new ArgumentException("moveInfo argument must contain at least one item");
|
||||
}
|
||||
|
||||
MoveInfoCollection = moveInfo;
|
||||
//assign the legacy props
|
||||
EventObject = moveInfo.First().Entity;
|
||||
ParentId = moveInfo.First().NewParentId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a collection of MoveEventInfo objects
|
||||
/// </summary>
|
||||
/// <param name="eventMessages"></param>
|
||||
/// <param name="moveInfo">
|
||||
/// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation
|
||||
/// </param>
|
||||
public MoveEventArgs(EventMessages eventMessages, params MoveEventInfo<TEntity>[] moveInfo)
|
||||
: base(default(TEntity), eventMessages)
|
||||
{
|
||||
if (moveInfo.FirstOrDefault() == null)
|
||||
{
|
||||
throw new ArgumentException("moveInfo argument must contain at least one item");
|
||||
}
|
||||
|
||||
MoveInfoCollection = moveInfo;
|
||||
//assign the legacy props
|
||||
EventObject = moveInfo.First().Entity;
|
||||
ParentId = moveInfo.First().NewParentId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a collection of MoveEventInfo objects
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
public class MoveEventInfo<TEntity>
|
||||
{
|
||||
public MoveEventInfo(TEntity entity, string originalPath, int newParentId)
|
||||
{
|
||||
Entity = entity;
|
||||
OriginalPath = originalPath;
|
||||
NewParentId = newParentId;
|
||||
}
|
||||
|
||||
public TEntity Entity { get; set; }
|
||||
public string OriginalPath { get; set; }
|
||||
public int NewParentId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,39 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
public class NewEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
|
||||
{
|
||||
public NewEventArgs(TEntity eventObject, bool canCancel, string @alias, int parentId) : base(eventObject, canCancel)
|
||||
|
||||
|
||||
public NewEventArgs(TEntity eventObject, bool canCancel, string @alias, int parentId, EventMessages eventMessages)
|
||||
: base(eventObject, canCancel, eventMessages)
|
||||
{
|
||||
Alias = alias;
|
||||
ParentId = parentId;
|
||||
}
|
||||
|
||||
public NewEventArgs(TEntity eventObject, bool canCancel, string @alias, TEntity parent, EventMessages eventMessages)
|
||||
: base(eventObject, canCancel, eventMessages)
|
||||
{
|
||||
Alias = alias;
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
public NewEventArgs(TEntity eventObject, string @alias, int parentId, EventMessages eventMessages)
|
||||
: base(eventObject, eventMessages)
|
||||
{
|
||||
Alias = alias;
|
||||
ParentId = parentId;
|
||||
}
|
||||
|
||||
public NewEventArgs(TEntity eventObject, string @alias, TEntity parent, EventMessages eventMessages)
|
||||
: base(eventObject, eventMessages)
|
||||
{
|
||||
Alias = alias;
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public NewEventArgs(TEntity eventObject, bool canCancel, string @alias, int parentId) : base(eventObject, canCancel)
|
||||
{
|
||||
Alias = alias;
|
||||
ParentId = parentId;
|
||||
|
||||
@@ -4,6 +4,52 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
public class PublishEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the publish operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="isAllPublished"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public PublishEventArgs(IEnumerable<TEntity> eventObject, bool canCancel, bool isAllPublished, EventMessages eventMessages)
|
||||
: base(eventObject, canCancel, eventMessages)
|
||||
{
|
||||
IsAllRepublished = isAllPublished;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the publish operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public PublishEventArgs(IEnumerable<TEntity> eventObject, EventMessages eventMessages)
|
||||
: base(eventObject, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public PublishEventArgs(TEntity eventObject, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="isAllPublished"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public PublishEventArgs(TEntity eventObject, bool canCancel, bool isAllPublished, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, canCancel, eventMessages)
|
||||
{
|
||||
IsAllRepublished = isAllPublished;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the publish operation
|
||||
/// </summary>
|
||||
|
||||
@@ -4,12 +4,55 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
public class SaveEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the saving operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
public SaveEventArgs(IEnumerable<TEntity> eventObject, bool canCancel)
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the saving operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public SaveEventArgs(IEnumerable<TEntity> eventObject, bool canCancel, EventMessages eventMessages)
|
||||
: base(eventObject, canCancel, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the saving operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public SaveEventArgs(IEnumerable<TEntity> eventObject, EventMessages eventMessages)
|
||||
: base(eventObject, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public SaveEventArgs(TEntity eventObject, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public SaveEventArgs(TEntity eventObject, bool canCancel, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, canCancel, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the saving operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
public SaveEventArgs(IEnumerable<TEntity> eventObject, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple/default transient messages factory
|
||||
/// </summary>
|
||||
internal class TransientMessagesFactory : IEventMessagesFactory
|
||||
{
|
||||
public EventMessages Get()
|
||||
{
|
||||
return new EventMessages();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-18
@@ -1,18 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- Blocks public downloading of anything in this folder and sub folders -->
|
||||
|
||||
<configuration>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<validation validateIntegratedModeConfiguration="false" />
|
||||
<handlers>
|
||||
<remove name="BlockViewHandler"/>
|
||||
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- Blocks public downloading of anything in this folder and sub folders -->
|
||||
|
||||
<configuration>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<validation validateIntegratedModeConfiguration="false" />
|
||||
<handlers>
|
||||
<remove name="BlockViewHandler"/>
|
||||
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.0
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Umbraco.Core.FileResources {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Files {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Files() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Core.FileResources.Files", typeof(Files).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <?xml version="1.0"?>
|
||||
///
|
||||
///<!-- Blocks public downloading of anything in this folder and sub folders -->
|
||||
///
|
||||
///<configuration>
|
||||
/// <system.web>
|
||||
/// <httpHandlers>
|
||||
/// <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
|
||||
/// </httpHandlers>
|
||||
/// </system.web>
|
||||
/// <system.webServer>
|
||||
/// <validation validateIntegratedModeConfiguration="false" />
|
||||
/// <handlers>
|
||||
/// <remove name="BlockViewHandler"/>
|
||||
/// <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.H [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string BlockingWebConfig {
|
||||
get {
|
||||
return ResourceManager.GetString("BlockingWebConfig", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="BlockingWebConfig" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>blockingweb.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -6,6 +6,7 @@ using System.IO;
|
||||
using System.Configuration;
|
||||
using System.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -51,7 +52,23 @@ namespace Umbraco.Core.IO
|
||||
return VirtualPathUtility.ToAbsolute(virtualPath, SystemDirectories.Root);
|
||||
}
|
||||
|
||||
[Obsolete("Use Umbraco.Web.Templates.TemplateUtilities.ResolveUrlsFromTextString instead, this method on this class will be removed in future versions")]
|
||||
public static Attempt<string> TryResolveUrl(string virtualPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (virtualPath.StartsWith("~"))
|
||||
return Attempt.Succeed(virtualPath.Replace("~", SystemDirectories.Root).Replace("//", "/"));
|
||||
if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute))
|
||||
return Attempt.Succeed(virtualPath);
|
||||
return Attempt.Succeed(VirtualPathUtility.ToAbsolute(virtualPath, SystemDirectories.Root));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt.Fail(virtualPath, ex);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use Umbraco.Web.Templates.TemplateUtilities.ResolveUrlsFromTextString instead, this method on this class will be removed in future versions")]
|
||||
internal static string ResolveUrlsFromTextString(string text)
|
||||
{
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.ResolveUrlsFromTextString)
|
||||
@@ -67,7 +84,7 @@ namespace Umbraco.Core.IO
|
||||
if (tag.Groups[1].Success)
|
||||
url = tag.Groups[1].Value;
|
||||
|
||||
if (string.IsNullOrEmpty(url) == false)
|
||||
if (String.IsNullOrEmpty(url) == false)
|
||||
{
|
||||
string resolvedUrl = (url.Substring(0, 1) == "/") ? ResolveUrl(url.Substring(1)) : ResolveUrl(url);
|
||||
text = text.Replace(url, resolvedUrl);
|
||||
@@ -92,10 +109,10 @@ namespace Umbraco.Core.IO
|
||||
if (useHttpContext && HttpContext.Current != null)
|
||||
{
|
||||
//string retval;
|
||||
if (string.IsNullOrEmpty(path) == false && (path.StartsWith("~") || path.StartsWith(SystemDirectories.Root)))
|
||||
return System.Web.Hosting.HostingEnvironment.MapPath(path);
|
||||
if (String.IsNullOrEmpty(path) == false && (path.StartsWith("~") || path.StartsWith(SystemDirectories.Root)))
|
||||
return HostingEnvironment.MapPath(path);
|
||||
else
|
||||
return System.Web.Hosting.HostingEnvironment.MapPath("~/" + path.TrimStart('/'));
|
||||
return HostingEnvironment.MapPath("~/" + path.TrimStart('/'));
|
||||
}
|
||||
|
||||
var root = GetRootDirectorySafe();
|
||||
@@ -115,7 +132,7 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
string retval = ConfigurationManager.AppSettings[settingsKey];
|
||||
|
||||
if (string.IsNullOrEmpty(retval))
|
||||
if (String.IsNullOrEmpty(retval))
|
||||
retval = standardPath;
|
||||
|
||||
return retval.TrimEnd('/');
|
||||
@@ -232,7 +249,7 @@ namespace Umbraco.Core.IO
|
||||
/// <returns></returns>
|
||||
internal static string GetRootDirectorySafe()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_rootDir) == false)
|
||||
if (String.IsNullOrEmpty(_rootDir) == false)
|
||||
{
|
||||
return _rootDir;
|
||||
}
|
||||
@@ -241,7 +258,7 @@ namespace Umbraco.Core.IO
|
||||
var uri = new Uri(codeBase);
|
||||
var path = uri.LocalPath;
|
||||
var baseDirectory = Path.GetDirectoryName(path);
|
||||
if (string.IsNullOrEmpty(baseDirectory))
|
||||
if (String.IsNullOrEmpty(baseDirectory))
|
||||
throw new Exception("No root directory could be resolved. Please ensure that your Umbraco solution is correctly configured.");
|
||||
|
||||
_rootDir = baseDirectory.Contains("bin")
|
||||
@@ -253,8 +270,8 @@ namespace Umbraco.Core.IO
|
||||
|
||||
internal static string GetRootDirectoryBinFolder()
|
||||
{
|
||||
string binFolder = string.Empty;
|
||||
if (string.IsNullOrEmpty(_rootDir))
|
||||
string binFolder = String.Empty;
|
||||
if (String.IsNullOrEmpty(_rootDir))
|
||||
{
|
||||
binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory.FullName;
|
||||
return binFolder;
|
||||
@@ -298,5 +315,25 @@ namespace Umbraco.Core.IO
|
||||
// use string extensions
|
||||
return filePath.ToSafeFileName();
|
||||
}
|
||||
|
||||
public static void EnsurePathExists(string path)
|
||||
{
|
||||
var absolutePath = IOHelper.MapPath(path);
|
||||
if (Directory.Exists(absolutePath) == false)
|
||||
Directory.CreateDirectory(absolutePath);
|
||||
}
|
||||
|
||||
public static void EnsureFileExists(string path, string contents)
|
||||
{
|
||||
var absolutePath = IOHelper.MapPath(path);
|
||||
if (File.Exists(absolutePath) == false)
|
||||
{
|
||||
using (var writer = File.CreateText(absolutePath))
|
||||
{
|
||||
writer.Write(contents);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using log4net.Appender;
|
||||
using log4net.Core;
|
||||
using log4net.Util;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <remarks>
|
||||
/// Based on https://github.com/cjbhaines/Log4Net.Async
|
||||
/// </remarks>
|
||||
public abstract class AsyncForwardingAppenderBase : ForwardingAppender
|
||||
{
|
||||
#region Private Members
|
||||
|
||||
private const FixFlags DefaultFixFlags = FixFlags.Partial;
|
||||
private FixFlags _fixFlags = DefaultFixFlags;
|
||||
private LoggingEventHelper _loggingEventHelper;
|
||||
|
||||
#endregion Private Members
|
||||
|
||||
#region Properties
|
||||
|
||||
public FixFlags Fix
|
||||
{
|
||||
get { return _fixFlags; }
|
||||
set { SetFixFlags(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The logger name that will be used for logging internal errors.
|
||||
/// </summary>
|
||||
protected abstract string InternalLoggerName { get; }
|
||||
|
||||
public abstract int? BufferSize { get; set; }
|
||||
|
||||
#endregion Properties
|
||||
|
||||
public override void ActivateOptions()
|
||||
{
|
||||
base.ActivateOptions();
|
||||
_loggingEventHelper = new LoggingEventHelper(InternalLoggerName, DefaultFixFlags);
|
||||
InitializeAppenders();
|
||||
}
|
||||
|
||||
#region Appender Management
|
||||
|
||||
public override void AddAppender(IAppender newAppender)
|
||||
{
|
||||
base.AddAppender(newAppender);
|
||||
SetAppenderFixFlags(newAppender);
|
||||
}
|
||||
|
||||
private void SetFixFlags(FixFlags newFixFlags)
|
||||
{
|
||||
if (newFixFlags != _fixFlags)
|
||||
{
|
||||
_loggingEventHelper.Fix = newFixFlags;
|
||||
_fixFlags = newFixFlags;
|
||||
InitializeAppenders();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeAppenders()
|
||||
{
|
||||
foreach (var appender in Appenders)
|
||||
{
|
||||
SetAppenderFixFlags(appender);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetAppenderFixFlags(IAppender appender)
|
||||
{
|
||||
var bufferingAppender = appender as BufferingAppenderSkeleton;
|
||||
if (bufferingAppender != null)
|
||||
{
|
||||
bufferingAppender.Fix = Fix;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Appender Management
|
||||
|
||||
#region Forwarding
|
||||
|
||||
protected void ForwardInternalError(string message, Exception exception, Type thisType)
|
||||
{
|
||||
LogLog.Error(thisType, message, exception);
|
||||
var loggingEvent = _loggingEventHelper.CreateLoggingEvent(Level.Error, message, exception);
|
||||
ForwardLoggingEvent(loggingEvent, thisType);
|
||||
}
|
||||
|
||||
protected void ForwardLoggingEvent(LoggingEvent loggingEvent, Type thisType)
|
||||
{
|
||||
try
|
||||
{
|
||||
base.Append(loggingEvent);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LogLog.Error(thisType, "Unable to forward logging event", exception);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Forwarding
|
||||
}
|
||||
}
|
||||
@@ -1,276 +1,276 @@
|
||||
using log4net.Core;
|
||||
using log4net.Util;
|
||||
using System;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using log4net.Appender;
|
||||
using log4net.Core;
|
||||
using log4net.Util;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Based on code by Chris Haines http://cjbhaines.wordpress.com/2012/02/13/asynchronous-log4net-appenders/
|
||||
/// <summary>
|
||||
/// Based on https://github.com/cjbhaines/Log4Net.Async
|
||||
/// which is based on code by Chris Haines http://cjbhaines.wordpress.com/2012/02/13/asynchronous-log4net-appenders/
|
||||
/// </summary>
|
||||
public class AsynchronousRollingFileAppender : RollingFileAppender
|
||||
{
|
||||
private readonly ManualResetEvent _manualResetEvent;
|
||||
private int _bufferOverflowCounter;
|
||||
private bool _forceStop;
|
||||
private bool _hasFinished;
|
||||
private DateTime _lastLoggedBufferOverflow;
|
||||
private bool _logBufferOverflow;
|
||||
private RingBuffer<LoggingEvent> _pendingAppends;
|
||||
private int _queueSizeLimit = 1000;
|
||||
private bool _shuttingDown;
|
||||
private RingBuffer<LoggingEvent> pendingAppends;
|
||||
private readonly ManualResetEvent manualResetEvent;
|
||||
private bool shuttingDown;
|
||||
private bool hasFinished;
|
||||
private bool forceStop;
|
||||
private bool logBufferOverflow;
|
||||
private int bufferOverflowCounter;
|
||||
private DateTime lastLoggedBufferOverflow;
|
||||
private int queueSizeLimit = 1000;
|
||||
public int QueueSizeLimit
|
||||
{
|
||||
get
|
||||
{
|
||||
return queueSizeLimit;
|
||||
}
|
||||
set
|
||||
{
|
||||
queueSizeLimit = value;
|
||||
}
|
||||
}
|
||||
|
||||
public AsynchronousRollingFileAppender()
|
||||
{
|
||||
_manualResetEvent = new ManualResetEvent(false);
|
||||
}
|
||||
public AsynchronousRollingFileAppender()
|
||||
{
|
||||
manualResetEvent = new ManualResetEvent(false);
|
||||
}
|
||||
|
||||
public int QueueSizeLimit
|
||||
{
|
||||
get { return _queueSizeLimit; }
|
||||
set { _queueSizeLimit = value; }
|
||||
}
|
||||
public override void ActivateOptions()
|
||||
{
|
||||
base.ActivateOptions();
|
||||
pendingAppends = new RingBuffer<LoggingEvent>(QueueSizeLimit);
|
||||
pendingAppends.BufferOverflow += OnBufferOverflow;
|
||||
StartAppendTask();
|
||||
}
|
||||
|
||||
public override void ActivateOptions()
|
||||
{
|
||||
base.ActivateOptions();
|
||||
_pendingAppends = new RingBuffer<LoggingEvent>(QueueSizeLimit);
|
||||
_pendingAppends.BufferOverflow += OnBufferOverflow;
|
||||
StartAppendTask();
|
||||
}
|
||||
protected override void Append(LoggingEvent[] loggingEvents)
|
||||
{
|
||||
Array.ForEach(loggingEvents, Append);
|
||||
}
|
||||
|
||||
protected override void Append(LoggingEvent[] loggingEvents)
|
||||
{
|
||||
Array.ForEach(loggingEvents, Append);
|
||||
}
|
||||
protected override void Append(LoggingEvent loggingEvent)
|
||||
{
|
||||
if (FilterEvent(loggingEvent))
|
||||
{
|
||||
pendingAppends.Enqueue(loggingEvent);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Append(LoggingEvent loggingEvent)
|
||||
{
|
||||
if (FilterEvent(loggingEvent))
|
||||
{
|
||||
_pendingAppends.Enqueue(loggingEvent);
|
||||
}
|
||||
}
|
||||
protected override void OnClose()
|
||||
{
|
||||
shuttingDown = true;
|
||||
manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
_shuttingDown = true;
|
||||
_manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
|
||||
if (!hasFinished)
|
||||
{
|
||||
forceStop = true;
|
||||
base.Append(new LoggingEvent(new LoggingEventData
|
||||
{
|
||||
Level = Level.Error,
|
||||
Message = "Unable to clear out the AsyncRollingFileAppender buffer in the allotted time, forcing a shutdown",
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Identity = "",
|
||||
ExceptionString = "",
|
||||
UserName = WindowsIdentity.GetCurrent() != null ? WindowsIdentity.GetCurrent().Name : "",
|
||||
Domain = AppDomain.CurrentDomain.FriendlyName,
|
||||
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
|
||||
LocationInfo = new LocationInfo(this.GetType().Name, "OnClose", "AsyncRollingFileAppender.cs", "75"),
|
||||
LoggerName = this.GetType().FullName,
|
||||
Properties = new PropertiesDictionary(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (!_hasFinished)
|
||||
{
|
||||
_forceStop = true;
|
||||
var windowsIdentity = WindowsIdentity.GetCurrent();
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
var logEvent = new LoggingEvent(new LoggingEventData
|
||||
{
|
||||
Level = global::log4net.Core.Level.Error,
|
||||
Message =
|
||||
"Unable to clear out the AsynchronousRollingFileAppender buffer in the allotted time, forcing a shutdown",
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Identity = "",
|
||||
ExceptionString = "",
|
||||
UserName = windowsIdentity != null ? windowsIdentity.Name : "",
|
||||
Domain = AppDomain.CurrentDomain.FriendlyName,
|
||||
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
|
||||
LocationInfo =
|
||||
new LocationInfo(this.GetType().Name, "OnClose", "AsynchronousRollingFileAppender.cs", "59"),
|
||||
LoggerName = this.GetType().FullName,
|
||||
Properties = new PropertiesDictionary(),
|
||||
});
|
||||
private void StartAppendTask()
|
||||
{
|
||||
if (!shuttingDown)
|
||||
{
|
||||
Task appendTask = new Task(AppendLoggingEvents, TaskCreationOptions.LongRunning);
|
||||
appendTask.LogErrors(LogAppenderError).ContinueWith(x => StartAppendTask()).LogErrors(LogAppenderError);
|
||||
appendTask.Start();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.DateTimeStrategy != null)
|
||||
{
|
||||
base.Append(logEvent);
|
||||
}
|
||||
}
|
||||
private void LogAppenderError(string logMessage, Exception exception)
|
||||
{
|
||||
base.Append(new LoggingEvent(new LoggingEventData
|
||||
{
|
||||
Level = Level.Error,
|
||||
Message = "Appender exception: " + logMessage,
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Identity = "",
|
||||
ExceptionString = exception.ToString(),
|
||||
UserName = WindowsIdentity.GetCurrent() != null ? WindowsIdentity.GetCurrent().Name : "",
|
||||
Domain = AppDomain.CurrentDomain.FriendlyName,
|
||||
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
|
||||
LocationInfo = new LocationInfo(this.GetType().Name, "LogAppenderError", "AsyncRollingFileAppender.cs", "152"),
|
||||
LoggerName = this.GetType().FullName,
|
||||
Properties = new PropertiesDictionary(),
|
||||
}));
|
||||
}
|
||||
|
||||
base.OnClose();
|
||||
}
|
||||
private void AppendLoggingEvents()
|
||||
{
|
||||
LoggingEvent loggingEventToAppend;
|
||||
while (!shuttingDown)
|
||||
{
|
||||
if (logBufferOverflow)
|
||||
{
|
||||
LogBufferOverflowError();
|
||||
logBufferOverflow = false;
|
||||
bufferOverflowCounter = 0;
|
||||
lastLoggedBufferOverflow = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private void StartAppendTask()
|
||||
{
|
||||
if (!_shuttingDown)
|
||||
{
|
||||
Task appendTask = new Task(AppendLoggingEvents, TaskCreationOptions.LongRunning);
|
||||
appendTask.LogErrors(LogAppenderError).ContinueWith(x => StartAppendTask()).LogErrors(LogAppenderError);
|
||||
appendTask.Start();
|
||||
}
|
||||
}
|
||||
while (!pendingAppends.TryDequeue(out loggingEventToAppend))
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
if (shuttingDown)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (loggingEventToAppend == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
private void LogAppenderError(string logMessage, Exception exception)
|
||||
{
|
||||
var windowsIdentity = WindowsIdentity.GetCurrent();
|
||||
base.Append(new LoggingEvent(new LoggingEventData
|
||||
{
|
||||
Level = Level.Error,
|
||||
Message = "Appender exception: " + logMessage,
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Identity = "",
|
||||
ExceptionString = exception.ToString(),
|
||||
UserName = windowsIdentity != null ? windowsIdentity.Name : "",
|
||||
Domain = AppDomain.CurrentDomain.FriendlyName,
|
||||
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
|
||||
LocationInfo =
|
||||
new LocationInfo(this.GetType().Name,
|
||||
"LogAppenderError",
|
||||
"AsynchronousRollingFileAppender.cs",
|
||||
"100"),
|
||||
LoggerName = this.GetType().FullName,
|
||||
Properties = new PropertiesDictionary(),
|
||||
}));
|
||||
}
|
||||
try
|
||||
{
|
||||
base.Append(loggingEventToAppend);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLoggingEvents()
|
||||
{
|
||||
LoggingEvent loggingEventToAppend;
|
||||
while (!_shuttingDown)
|
||||
{
|
||||
if (_logBufferOverflow)
|
||||
{
|
||||
LogBufferOverflowError();
|
||||
_logBufferOverflow = false;
|
||||
_bufferOverflowCounter = 0;
|
||||
_lastLoggedBufferOverflow = DateTime.UtcNow;
|
||||
}
|
||||
while (pendingAppends.TryDequeue(out loggingEventToAppend) && !forceStop)
|
||||
{
|
||||
try
|
||||
{
|
||||
base.Append(loggingEventToAppend);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
hasFinished = true;
|
||||
manualResetEvent.Set();
|
||||
}
|
||||
|
||||
while (!_pendingAppends.TryDequeue(out loggingEventToAppend))
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
if (_shuttingDown)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (loggingEventToAppend == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
private void LogBufferOverflowError()
|
||||
{
|
||||
base.Append(new LoggingEvent(new LoggingEventData
|
||||
{
|
||||
Level = Level.Error,
|
||||
Message = string.Format("Buffer overflow. {0} logging events have been lost in the last 30 seconds. [QueueSizeLimit: {1}]", bufferOverflowCounter, QueueSizeLimit),
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Identity = "",
|
||||
ExceptionString = "",
|
||||
UserName = WindowsIdentity.GetCurrent() != null ? WindowsIdentity.GetCurrent().Name : "",
|
||||
Domain = AppDomain.CurrentDomain.FriendlyName,
|
||||
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
|
||||
LocationInfo = new LocationInfo(this.GetType().Name, "LogBufferOverflowError", "AsyncRollingFileAppender.cs", "152"),
|
||||
LoggerName = this.GetType().FullName,
|
||||
Properties = new PropertiesDictionary(),
|
||||
}));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
base.Append(loggingEventToAppend);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
private void OnBufferOverflow(object sender, EventArgs eventArgs)
|
||||
{
|
||||
bufferOverflowCounter++;
|
||||
if (logBufferOverflow == false)
|
||||
{
|
||||
if (lastLoggedBufferOverflow < DateTime.UtcNow.AddSeconds(-30))
|
||||
{
|
||||
logBufferOverflow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (_pendingAppends.TryDequeue(out loggingEventToAppend) && !_forceStop)
|
||||
{
|
||||
try
|
||||
{
|
||||
base.Append(loggingEventToAppend);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
_hasFinished = true;
|
||||
_manualResetEvent.Set();
|
||||
}
|
||||
internal interface IQueue<T>
|
||||
{
|
||||
void Enqueue(T item);
|
||||
bool TryDequeue(out T ret);
|
||||
}
|
||||
|
||||
private void LogBufferOverflowError()
|
||||
{
|
||||
var windowsIdentity = WindowsIdentity.GetCurrent();
|
||||
base.Append(new LoggingEvent(new LoggingEventData
|
||||
{
|
||||
Level = Level.Error,
|
||||
Message =
|
||||
string.Format(
|
||||
"Buffer overflow. {0} logging events have been lost in the last 30 seconds. [QueueSizeLimit: {1}]",
|
||||
_bufferOverflowCounter,
|
||||
QueueSizeLimit),
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Identity = "",
|
||||
ExceptionString = "",
|
||||
UserName = windowsIdentity != null ? windowsIdentity.Name : "",
|
||||
Domain = AppDomain.CurrentDomain.FriendlyName,
|
||||
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
|
||||
LocationInfo =
|
||||
new LocationInfo(this.GetType().Name,
|
||||
"LogBufferOverflowError",
|
||||
"AsynchronousRollingFileAppender.cs",
|
||||
"172"),
|
||||
LoggerName = this.GetType().FullName,
|
||||
Properties = new PropertiesDictionary(),
|
||||
}));
|
||||
}
|
||||
internal class RingBuffer<T> : IQueue<T>
|
||||
{
|
||||
private readonly object lockObject = new object();
|
||||
private readonly T[] buffer;
|
||||
private readonly int size;
|
||||
private int readIndex = 0;
|
||||
private int writeIndex = 0;
|
||||
private bool bufferFull = false;
|
||||
|
||||
private void OnBufferOverflow(object sender, EventArgs eventArgs)
|
||||
{
|
||||
_bufferOverflowCounter++;
|
||||
if (_logBufferOverflow == false)
|
||||
{
|
||||
if (_lastLoggedBufferOverflow < DateTime.UtcNow.AddSeconds(-30))
|
||||
{
|
||||
_logBufferOverflow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int Size { get { return size; } }
|
||||
|
||||
private class RingBuffer<T>
|
||||
{
|
||||
private readonly object _lockObject = new object();
|
||||
private readonly T[] _buffer;
|
||||
private readonly int _size;
|
||||
private int _readIndex = 0;
|
||||
private int _writeIndex = 0;
|
||||
private bool _bufferFull = false;
|
||||
public event Action<object, EventArgs> BufferOverflow;
|
||||
|
||||
public event Action<object, EventArgs> BufferOverflow;
|
||||
public RingBuffer(int size)
|
||||
{
|
||||
this.size = size;
|
||||
buffer = new T[size];
|
||||
}
|
||||
|
||||
public RingBuffer(int size)
|
||||
{
|
||||
this._size = size;
|
||||
_buffer = new T[size];
|
||||
}
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
var bufferWasFull = false;
|
||||
lock (lockObject)
|
||||
{
|
||||
buffer[writeIndex] = item;
|
||||
writeIndex = (++writeIndex) % size;
|
||||
if (bufferFull)
|
||||
{
|
||||
bufferWasFull = true;
|
||||
readIndex = writeIndex;
|
||||
}
|
||||
else if (writeIndex == readIndex)
|
||||
{
|
||||
bufferFull = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
_buffer[_writeIndex] = item;
|
||||
_writeIndex = (++_writeIndex) % _size;
|
||||
if (_bufferFull)
|
||||
{
|
||||
if (BufferOverflow != null)
|
||||
{
|
||||
BufferOverflow(this, EventArgs.Empty);
|
||||
}
|
||||
_readIndex = _writeIndex;
|
||||
}
|
||||
else if (_writeIndex == _readIndex)
|
||||
{
|
||||
_bufferFull = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bufferWasFull)
|
||||
{
|
||||
if (BufferOverflow != null)
|
||||
{
|
||||
BufferOverflow(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryDequeue(out T ret)
|
||||
{
|
||||
if (_readIndex == _writeIndex && !_bufferFull)
|
||||
{
|
||||
ret = default(T);
|
||||
return false;
|
||||
}
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_readIndex == _writeIndex && !_bufferFull)
|
||||
{
|
||||
ret = default(T);
|
||||
return false;
|
||||
}
|
||||
public bool TryDequeue(out T ret)
|
||||
{
|
||||
if (readIndex == writeIndex && !bufferFull)
|
||||
{
|
||||
ret = default(T);
|
||||
return false;
|
||||
}
|
||||
lock (lockObject)
|
||||
{
|
||||
if (readIndex == writeIndex && !bufferFull)
|
||||
{
|
||||
ret = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = _buffer[_readIndex];
|
||||
_readIndex = (++_readIndex) % _size;
|
||||
_bufferFull = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = buffer[readIndex];
|
||||
buffer[readIndex] = default(T);
|
||||
readIndex = (++readIndex) % size;
|
||||
bufferFull = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -12,15 +13,20 @@ namespace Umbraco.Core.Logging
|
||||
/// Used for logging
|
||||
///</summary>
|
||||
public class Logger : ILogger
|
||||
{
|
||||
{
|
||||
|
||||
public Logger(FileInfo log4NetConfigFile)
|
||||
:this()
|
||||
{
|
||||
XmlConfigurator.Configure(log4NetConfigFile);
|
||||
}
|
||||
|
||||
private Logger()
|
||||
{
|
||||
|
||||
//Add custom global properties to the log4net context that we can use in our logging output
|
||||
|
||||
log4net.GlobalContext.Properties["processId"] = Process.GetCurrentProcess().Id;
|
||||
log4net.GlobalContext.Properties["appDomainId"] = AppDomain.CurrentDomain.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,31 +59,19 @@ namespace Umbraco.Core.Logging
|
||||
|
||||
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);
|
||||
logger.Error((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());
|
||||
logger.WarnFormat((message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
}
|
||||
|
||||
public void Warn(Type callingType, string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
@@ -92,7 +86,7 @@ namespace Umbraco.Core.Logging
|
||||
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
logger.WarnFormat((message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
|
||||
}
|
||||
|
||||
@@ -105,7 +99,7 @@ namespace Umbraco.Core.Logging
|
||||
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);
|
||||
logger.WarnFormat((message) + ". Exception: " + e, executedParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -117,7 +111,7 @@ namespace Umbraco.Core.Logging
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsInfoEnabled == false) return;
|
||||
logger.Info(PrefixThreadId(generateMessage.Invoke()));
|
||||
logger.Info((generateMessage.Invoke()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -131,7 +125,7 @@ namespace Umbraco.Core.Logging
|
||||
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);
|
||||
logger.InfoFormat((generateMessageFormat), executedParams);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +138,7 @@ namespace Umbraco.Core.Logging
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsDebugEnabled == false) return;
|
||||
logger.Debug(PrefixThreadId(generateMessage.Invoke()));
|
||||
logger.Debug((generateMessage.Invoke()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,7 +152,7 @@ namespace Umbraco.Core.Logging
|
||||
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);
|
||||
logger.DebugFormat((generateMessageFormat), executedParams);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using log4net.Core;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <remarks>
|
||||
/// Based on https://github.com/cjbhaines/Log4Net.Async
|
||||
/// </remarks>
|
||||
internal class LoggingEventContext
|
||||
{
|
||||
public LoggingEventContext(LoggingEvent loggingEvent)
|
||||
{
|
||||
LoggingEvent = loggingEvent;
|
||||
}
|
||||
|
||||
public LoggingEvent LoggingEvent { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using log4net.Core;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <remarks>
|
||||
/// Based on https://github.com/cjbhaines/Log4Net.Async
|
||||
/// </remarks>
|
||||
internal class LoggingEventHelper
|
||||
{
|
||||
// needs to be a seperate class so that location is determined correctly by log4net when required
|
||||
|
||||
private static readonly Type HelperType = typeof(LoggingEventHelper);
|
||||
private readonly string loggerName;
|
||||
|
||||
public FixFlags Fix { get; set; }
|
||||
|
||||
public LoggingEventHelper(string loggerName, FixFlags fix)
|
||||
{
|
||||
this.loggerName = loggerName;
|
||||
Fix = fix;
|
||||
}
|
||||
|
||||
public LoggingEvent CreateLoggingEvent(Level level, string message, Exception exception)
|
||||
{
|
||||
var loggingEvent = new LoggingEvent(HelperType, null, loggerName, level, message, exception);
|
||||
loggingEvent.Fix = Fix;
|
||||
return loggingEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using log4net.Core;
|
||||
using log4net.Util;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// An asynchronous appender based on <see cref="BlockingCollection{T}"/>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Based on https://github.com/cjbhaines/Log4Net.Async
|
||||
/// </remarks>
|
||||
public class ParallelForwardingAppender : AsyncForwardingAppenderBase, IDisposable
|
||||
{
|
||||
#region Private Members
|
||||
|
||||
private const int DefaultBufferSize = 1000;
|
||||
private BlockingCollection<LoggingEventContext> _loggingEvents;
|
||||
private CancellationTokenSource _loggingCancelationTokenSource;
|
||||
private CancellationToken _loggingCancelationToken;
|
||||
private Task _loggingTask;
|
||||
private Double _shutdownFlushTimeout = 1;
|
||||
private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(1);
|
||||
private static readonly Type ThisType = typeof(ParallelForwardingAppender);
|
||||
private volatile bool _shutDownRequested;
|
||||
private int? _bufferSize = DefaultBufferSize;
|
||||
|
||||
#endregion Private Members
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of LoggingEvents that will be buffered. Set to null for unlimited.
|
||||
/// </summary>
|
||||
public override int? BufferSize
|
||||
{
|
||||
get { return _bufferSize; }
|
||||
set { _bufferSize = value; }
|
||||
}
|
||||
|
||||
public int BufferEntryCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_loggingEvents == null) return 0;
|
||||
return _loggingEvents.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time period in which the system will wait for appenders to flush before canceling the background task.
|
||||
/// </summary>
|
||||
public Double ShutdownFlushTimeout
|
||||
{
|
||||
get
|
||||
{
|
||||
return _shutdownFlushTimeout;
|
||||
}
|
||||
set
|
||||
{
|
||||
_shutdownFlushTimeout = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string InternalLoggerName
|
||||
{
|
||||
get { return "ParallelForwardingAppender"; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Startup
|
||||
|
||||
public override void ActivateOptions()
|
||||
{
|
||||
base.ActivateOptions();
|
||||
_shutdownFlushTimespan = TimeSpan.FromSeconds(_shutdownFlushTimeout);
|
||||
StartForwarding();
|
||||
}
|
||||
|
||||
private void StartForwarding()
|
||||
{
|
||||
if (_shutDownRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//Create a collection which will block the thread and wait for new entries
|
||||
//if the collection is empty
|
||||
if (BufferSize.HasValue && BufferSize > 0)
|
||||
{
|
||||
_loggingEvents = new BlockingCollection<LoggingEventContext>(BufferSize.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
//No limit on the number of events.
|
||||
_loggingEvents = new BlockingCollection<LoggingEventContext>();
|
||||
}
|
||||
//The cancellation token is used to cancel a running task gracefully.
|
||||
_loggingCancelationTokenSource = new CancellationTokenSource();
|
||||
_loggingCancelationToken = _loggingCancelationTokenSource.Token;
|
||||
_loggingTask = new Task(SubscriberLoop, _loggingCancelationToken);
|
||||
_loggingTask.Start();
|
||||
}
|
||||
|
||||
#endregion Startup
|
||||
|
||||
#region Shutdown
|
||||
|
||||
private void CompleteSubscriberTask()
|
||||
{
|
||||
_shutDownRequested = true;
|
||||
if (_loggingEvents == null || _loggingEvents.IsAddingCompleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//Don't allow more entries to be added.
|
||||
_loggingEvents.CompleteAdding();
|
||||
//Allow some time to flush
|
||||
Thread.Sleep(_shutdownFlushTimespan);
|
||||
if (!_loggingTask.IsCompleted && !_loggingCancelationToken.IsCancellationRequested)
|
||||
{
|
||||
_loggingCancelationTokenSource.Cancel();
|
||||
//Wait here so that the error logging messages do not get into a random order.
|
||||
//Don't pass the cancellation token because we are not interested
|
||||
//in catching the OperationCanceledException that results.
|
||||
_loggingTask.Wait();
|
||||
}
|
||||
if (!_loggingEvents.IsCompleted)
|
||||
{
|
||||
ForwardInternalError("The buffer was not able to be flushed before timeout occurred.", null, ThisType);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
CompleteSubscriberTask();
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion Shutdown
|
||||
|
||||
#region Appending
|
||||
|
||||
protected override void Append(LoggingEvent loggingEvent)
|
||||
{
|
||||
if (_loggingEvents == null || _loggingEvents.IsAddingCompleted || loggingEvent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
loggingEvent.Fix = Fix;
|
||||
//In the case where blocking on a full collection, and the task is subsequently completed, the cancellation token
|
||||
//will prevent the entry from attempting to add to the completed collection which would result in an exception.
|
||||
_loggingEvents.Add(new LoggingEventContext(loggingEvent), _loggingCancelationToken);
|
||||
}
|
||||
|
||||
protected override void Append(LoggingEvent[] loggingEvents)
|
||||
{
|
||||
if (_loggingEvents == null || _loggingEvents.IsAddingCompleted || loggingEvents == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var loggingEvent in loggingEvents)
|
||||
{
|
||||
Append(loggingEvent);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Appending
|
||||
|
||||
#region Forwarding
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over a BlockingCollection containing LoggingEvents.
|
||||
/// </summary>
|
||||
private void SubscriberLoop()
|
||||
{
|
||||
Thread.CurrentThread.Name = String.Format("{0} ParallelForwardingAppender Subscriber Task", Name);
|
||||
//The task will continue in a blocking loop until
|
||||
//the queue is marked as adding completed, or the task is canceled.
|
||||
try
|
||||
{
|
||||
//This call blocks until an item is available or until adding is completed
|
||||
foreach (var entry in _loggingEvents.GetConsumingEnumerable(_loggingCancelationToken))
|
||||
{
|
||||
ForwardLoggingEvent(entry.LoggingEvent, ThisType);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
//The thread was canceled before all entries could be forwarded and the collection completed.
|
||||
ForwardInternalError("Subscriber task was canceled before completion.", ex, ThisType);
|
||||
//Cancellation is called in the CompleteSubscriberTask so don't call that again.
|
||||
}
|
||||
catch (ThreadAbortException ex)
|
||||
{
|
||||
//Thread abort may occur on domain unload.
|
||||
ForwardInternalError("Subscriber task was aborted.", ex, ThisType);
|
||||
//Cannot recover from a thread abort so complete the task.
|
||||
CompleteSubscriberTask();
|
||||
//The exception is swallowed because we don't want the client application
|
||||
//to halt due to a logging issue.
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//On exception, try to log the exception
|
||||
ForwardInternalError("Subscriber task error in forwarding loop.", ex, ThisType);
|
||||
//Any error in the loop is going to be some sort of extenuating circumstance from which we
|
||||
//probably cannot recover anyway. Complete subscribing.
|
||||
CompleteSubscriberTask();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Forwarding
|
||||
|
||||
#region IDisposable Implementation
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
//Implement IDisposable.
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_loggingTask != null)
|
||||
{
|
||||
if (!(_loggingTask.IsCanceled || _loggingTask.IsCompleted || _loggingTask.IsFaulted))
|
||||
{
|
||||
try
|
||||
{
|
||||
CompleteSubscriberTask();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogLog.Error(ThisType, "Exception Completing Subscriber Task in Dispose Method", ex);
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
_loggingTask.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogLog.Error(ThisType, "Exception Disposing Logging Task", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loggingTask = null;
|
||||
}
|
||||
}
|
||||
if (_loggingEvents != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_loggingEvents.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogLog.Error(ThisType, "Exception Disposing BlockingCollection", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loggingEvents = null;
|
||||
}
|
||||
}
|
||||
if (_loggingCancelationTokenSource != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_loggingCancelationTokenSource.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogLog.Error(ThisType, "Exception Disposing CancellationTokenSource", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loggingCancelationTokenSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Use C# destructor syntax for finalization code.
|
||||
~ParallelForwardingAppender()
|
||||
{
|
||||
// Simply call Dispose(false).
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion IDisposable Implementation
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Macros
|
||||
internal class MacroTagParser
|
||||
{
|
||||
private static readonly Regex MacroRteContent = new Regex(@"(<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(\s*?-->)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO (?:.+)?macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO (?:.+?)?macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// This formats the persisted string to something useful for the rte so that the macro renders properly since we
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
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
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
// 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(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
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)
|
||||
{
|
||||
_logger.Debug<MainDom>("Signaled" + (_signaled ? " (again)" : "") + " (" + source + ").");
|
||||
if (_signaled) return;
|
||||
if (_isMainDom == false) return; // probably not needed
|
||||
_signaled = true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Debug<MainDom>("Stopping...");
|
||||
foreach (var callback in _callbacks.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(); // no timeout on callbacks
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error<MainDom>("Error while running callback, remaining callbacks will not run.", e);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
_logger.Debug<MainDom>("Stopped.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// in any case...
|
||||
_isMainDom = false;
|
||||
_asyncLocker.Dispose();
|
||||
_logger.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)
|
||||
{
|
||||
_logger.Debug<MainDom>("Cannot acquire MainDom (signaled).");
|
||||
return false;
|
||||
}
|
||||
|
||||
_logger.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);
|
||||
|
||||
_logger.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -96,11 +97,15 @@ namespace Umbraco.Core.Manifest
|
||||
|
||||
if (depth < 1)
|
||||
{
|
||||
var dirs = currDir.GetDirectories();
|
||||
var result = new List<string>();
|
||||
foreach (var d in dirs)
|
||||
if (currDir.Exists)
|
||||
{
|
||||
result.AddRange(GetAllManifestFileContents(d));
|
||||
var dirs = currDir.GetDirectories();
|
||||
|
||||
foreach (var d in dirs)
|
||||
{
|
||||
result.AddRange(GetAllManifestFileContents(d));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -136,11 +141,22 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
var result = new List<PackageManifest>();
|
||||
foreach (var m in manifestFileContents)
|
||||
{
|
||||
if (m.IsNullOrWhiteSpace()) continue;
|
||||
{
|
||||
var manifestContent = m;
|
||||
|
||||
if (manifestContent.IsNullOrWhiteSpace()) continue;
|
||||
|
||||
// Strip byte object marker, JSON.NET does not like it
|
||||
var preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
|
||||
|
||||
// Strangely StartsWith(preamble) would always return true
|
||||
if (manifestContent.Substring(0, 1) == preamble)
|
||||
manifestContent = manifestContent.Remove(0, preamble.Length);
|
||||
|
||||
if (manifestContent.IsNullOrWhiteSpace()) continue;
|
||||
|
||||
//remove any comments first
|
||||
var replaced = CommentsSurround.Replace(m, match => " ");
|
||||
var replaced = CommentsSurround.Replace(manifestContent, match => " ");
|
||||
replaced = CommentsLine.Replace(replaced, match => "");
|
||||
|
||||
JObject deserialized;
|
||||
@@ -150,7 +166,7 @@ namespace Umbraco.Core.Manifest
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ManifestParser>("An error occurred parsing manifest with contents: " + m, ex);
|
||||
LogHelper.Error<ManifestParser>("An error occurred parsing manifest with contents: " + manifestContent, ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Core.Media.Exif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands ExifProperty objects contained in an ExifFile as seperate properties.
|
||||
/// Expands ExifProperty objects contained in an ExifFile as separate properties.
|
||||
/// </summary>
|
||||
internal sealed class ExifFileTypeDescriptor : CustomTypeDescriptor
|
||||
{
|
||||
|
||||
@@ -95,13 +95,7 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
public virtual ITemplate Template
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_template == null)
|
||||
return _contentType.DefaultTemplate;
|
||||
|
||||
return _template;
|
||||
}
|
||||
get { return _template; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
|
||||
@@ -460,6 +460,11 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
public bool AddPropertyType(PropertyType propertyType)
|
||||
{
|
||||
if (propertyType.HasIdentity == false)
|
||||
{
|
||||
propertyType.Key = Guid.NewGuid();
|
||||
}
|
||||
|
||||
if (PropertyTypeExists(propertyType.Alias) == false)
|
||||
{
|
||||
_propertyTypes.Add(propertyType);
|
||||
|
||||
@@ -198,6 +198,11 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
public override bool AddPropertyType(PropertyType propertyType, string propertyGroupName)
|
||||
{
|
||||
if (propertyType.HasIdentity == false)
|
||||
{
|
||||
propertyType.Key = Guid.NewGuid();
|
||||
}
|
||||
|
||||
if (PropertyTypeExists(propertyType.Alias) == false)
|
||||
{
|
||||
if (PropertyGroups.Contains(propertyGroupName))
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
|
||||
var descendants = contentTypeService.GetContentTypeChildren(contentType.Id)
|
||||
.FlattenList(type => contentTypeService.GetContentTypeChildren(type.Id));
|
||||
.SelectRecursive(type => contentTypeService.GetContentTypeChildren(type.Id));
|
||||
return descendants;
|
||||
}
|
||||
|
||||
|
||||
@@ -268,11 +268,6 @@ namespace Umbraco.Core.Models
|
||||
get { return _additionalData; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
public IDictionary<string, object> AdditionalData { get; private set; }
|
||||
|
||||
internal override void AddingEntity()
|
||||
{
|
||||
base.AddingEntity();
|
||||
|
||||
@@ -14,22 +14,22 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public class DictionaryItem : Entity, IDictionaryItem
|
||||
{
|
||||
private Guid _parentId;
|
||||
private Guid? _parentId;
|
||||
private string _itemKey;
|
||||
private IEnumerable<IDictionaryTranslation> _translations;
|
||||
|
||||
public DictionaryItem(string itemKey)
|
||||
: this(new Guid(Constants.Conventions.Localization.DictionaryItemRootId), itemKey)
|
||||
: this(null, itemKey)
|
||||
{}
|
||||
|
||||
public DictionaryItem(Guid parentId, string itemKey)
|
||||
public DictionaryItem(Guid? parentId, string itemKey)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_itemKey = itemKey;
|
||||
_translations = new List<IDictionaryTranslation>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, Guid>(x => x.ParentId);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, Guid?>(x => x.ParentId);
|
||||
private static readonly PropertyInfo ItemKeySelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, string>(x => x.ItemKey);
|
||||
private static readonly PropertyInfo TranslationsSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, IEnumerable<IDictionaryTranslation>>(x => x.Translations);
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Umbraco.Core.Models
|
||||
/// Gets or Sets the Parent Id of the Dictionary Item
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public Guid ParentId
|
||||
public Guid? ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
@@ -95,11 +95,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
base.AddingEntity();
|
||||
|
||||
Key = Guid.NewGuid();
|
||||
|
||||
//If ParentId is not set we should default to the root parent id
|
||||
if(ParentId == Guid.Empty)
|
||||
_parentId = new Guid(Constants.Conventions.Localization.DictionaryItemRootId);
|
||||
Key = Guid.NewGuid();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// the new api, which also needs to take effect in the legacy api.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
[Obsolete("Anytime there's a cancellable method it needs to return an Attempt so we know the outcome instead of this hack, not all services have been updated to use this though yet.")]
|
||||
internal bool WasCancelled
|
||||
{
|
||||
get { return _wasCancelled; }
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Models
|
||||
/// Gets or Sets the Parent Id of the Dictionary Item
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
Guid ParentId { get; set; }
|
||||
Guid? ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Key for the Dictionary Item
|
||||
|
||||
@@ -4,9 +4,14 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IDomain : IAggregateRoot, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
ILanguage Language { get; set; }
|
||||
int? LanguageId { get; set; }
|
||||
string DomainName { get; set; }
|
||||
IContent RootContent { get; set; }
|
||||
int? RootContentId { get; set; }
|
||||
bool IsWildcard { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Readonly value of the language ISO code for the domain
|
||||
/// </summary>
|
||||
string LanguageIsoCode { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using Semver;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IMigrationEntry : IAggregateRoot, IRememberBeingDirty
|
||||
{
|
||||
string MigrationName { get; set; }
|
||||
SemVersion Version { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IServerRegistration : IServerAddress, IAggregateRoot, IRememberBeingDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the server unique identity.
|
||||
/// </summary>
|
||||
string ServerIdentity { get; set; }
|
||||
|
||||
new string ServerAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the server is active.
|
||||
/// </summary>
|
||||
bool IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date and time the registration was created.
|
||||
/// </summary>
|
||||
DateTime Registered { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date and time the registration was last accessed.
|
||||
/// </summary>
|
||||
DateTime Accessed { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,13 @@ namespace Umbraco.Core.Models.Identity
|
||||
public class BackOfficeIdentityUser : IdentityUser<int, IIdentityUserLogin, IdentityUserRole<string>, IdentityUserClaim<int>>
|
||||
{
|
||||
|
||||
public BackOfficeIdentityUser()
|
||||
{
|
||||
StartMediaId = -1;
|
||||
StartContentId = -1;
|
||||
Culture = Configuration.GlobalSettings.DefaultUILanguage;
|
||||
}
|
||||
|
||||
public virtual async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager manager)
|
||||
{
|
||||
// NOTE the authenticationType must match the umbraco one
|
||||
@@ -31,6 +38,30 @@ namespace Umbraco.Core.Models.Identity
|
||||
|
||||
public string UserTypeAlias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lockout is always enabled
|
||||
/// </summary>
|
||||
public override bool LockoutEnabled
|
||||
{
|
||||
get { return true; }
|
||||
set
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Based on the user's lockout end date, this will determine if they are locked out
|
||||
/// </summary>
|
||||
internal bool IsLockedOut
|
||||
{
|
||||
get
|
||||
{
|
||||
var isLocked = (LockoutEndDateUtc.HasValue && LockoutEndDateUtc.Value.ToLocalTime() >= DateTime.Now);
|
||||
return isLocked;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden to make the retrieval lazy
|
||||
/// </summary>
|
||||
|
||||
@@ -14,8 +14,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
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.LockoutEndDateUtc, expression => expression.MapFrom(user => user.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?)null))
|
||||
.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)))
|
||||
@@ -23,6 +22,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
.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.AccessFailedCount, expression => expression.MapFrom(user => user.FailedPasswordAttempts))
|
||||
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class Macro : Entity, IMacro
|
||||
public class Macro : Entity, IMacro
|
||||
{
|
||||
public Macro()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Semver;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public class MigrationEntry : Entity, IMigrationEntry
|
||||
{
|
||||
public MigrationEntry()
|
||||
{
|
||||
}
|
||||
|
||||
public MigrationEntry(int id, DateTime createDate, string migrationName, SemVersion version)
|
||||
{
|
||||
Id = id;
|
||||
CreateDate = createDate;
|
||||
_migrationName = migrationName;
|
||||
_version = version;
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<MigrationEntry, string>(x => x.MigrationName);
|
||||
private static readonly PropertyInfo VersionSelector = ExpressionHelper.GetPropertyInfo<MigrationEntry, SemVersion>(x => x.Version);
|
||||
private string _migrationName;
|
||||
private SemVersion _version;
|
||||
|
||||
public string MigrationName
|
||||
{
|
||||
get { return _migrationName; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_migrationName = value;
|
||||
return _migrationName;
|
||||
}, _migrationName, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public SemVersion Version
|
||||
{
|
||||
get { return _version; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_version = value;
|
||||
return _version;
|
||||
}, _version, VersionSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,9 +137,23 @@ namespace Umbraco.Core.Models
|
||||
new DelegateEqualityComparer<object>(
|
||||
(o, o1) =>
|
||||
{
|
||||
//Custom comparer for enumerable if it is enumerable
|
||||
if (o == null && o1 == null) return true;
|
||||
|
||||
//custom comparer for strings.
|
||||
if (o is string || o1 is string)
|
||||
{
|
||||
//if one is null and another is empty then they are the same
|
||||
if ((o as string).IsNullOrWhiteSpace() && (o1 as string).IsNullOrWhiteSpace())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (o == null || o1 == null) return false;
|
||||
return o.Equals(o1);
|
||||
}
|
||||
|
||||
if (o == null || o1 == null) return false;
|
||||
|
||||
//Custom comparer for enumerable if it is enumerable
|
||||
var enum1 = o as IEnumerable;
|
||||
var enum2 = o1 as IEnumerable;
|
||||
if (enum1 != null && enum2 != null)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -105,6 +106,13 @@ namespace Umbraco.Core.Models
|
||||
set
|
||||
{
|
||||
_propertyTypes = value;
|
||||
|
||||
//since we're adding this collection to this group, we need to ensure that all the lazy values are set.
|
||||
foreach (var propertyType in _propertyTypes)
|
||||
{
|
||||
propertyType.PropertyGroupId = new Lazy<int>(() => this.Id);
|
||||
}
|
||||
|
||||
_propertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
public Guid UniqueId { get; set; }
|
||||
|
||||
[Column("parent")]
|
||||
public Guid Parent { get; set; }
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[ForeignKey(typeof(DictionaryDto), Column = "id")]
|
||||
public Guid? Parent { get; set; }
|
||||
|
||||
[Column("key")]
|
||||
[Length(1000)]
|
||||
|
||||
@@ -23,5 +23,11 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[Column("domainName")]
|
||||
public string DomainName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used for a result on the query to get the associated language for a domain if there is one
|
||||
/// </summary>
|
||||
[ResultColumn("languageISOCode")]
|
||||
public string IsoCode { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
public int PrimaryKey { get; set; }
|
||||
|
||||
[Column("languageId")]
|
||||
[ForeignKey(typeof(LanguageDto), Column = "id")]
|
||||
public int LanguageId { get; set; }
|
||||
|
||||
[Column("UniqueId")]
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoMigration")]
|
||||
[PrimaryKey("id")]
|
||||
[ExplicitColumns]
|
||||
internal class MigrationDto
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(AutoIncrement = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("name")]
|
||||
[Length(255)]
|
||||
[Index(IndexTypes.UniqueNonClustered, ForColumns = "name,version", Name = "IX_umbracoMigration")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("createDate")]
|
||||
[Constraint(Default = "getdate()")]
|
||||
public DateTime CreateDate { get; set; }
|
||||
|
||||
[Column("version")]
|
||||
[Length(50)]
|
||||
public string Version { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,12 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[ExplicitColumns]
|
||||
internal class NodeDto
|
||||
{
|
||||
public NodeDto()
|
||||
{
|
||||
//By default, always generate a new guid
|
||||
UniqueId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public const int NodeIdSeed = 1050;
|
||||
|
||||
[Column("id")]
|
||||
@@ -42,6 +48,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[Column("uniqueID")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoNodeUniqueID")]
|
||||
[Constraint(Default = "newid()")]
|
||||
public Guid UniqueId { get; set; }
|
||||
|
||||
[Column("text")]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Persistence;
|
||||
using System;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
@@ -8,6 +9,12 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[ExplicitColumns]
|
||||
internal class PropertyTypeDto
|
||||
{
|
||||
public PropertyTypeDto()
|
||||
{
|
||||
//by default always create a new guid
|
||||
UniqueId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 50)]
|
||||
public int Id { get; set; }
|
||||
@@ -51,5 +58,11 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[ResultColumn]
|
||||
public DataTypeDto DataTypeDto { get; set; }
|
||||
|
||||
[Column("UniqueID")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Constraint(Default = "newid()")]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_cmsPropertyTypeUniqueID")]
|
||||
public Guid UniqueId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoUserLogins")]
|
||||
[ExplicitColumns]
|
||||
internal class UserLoginDto
|
||||
{
|
||||
[Column("contextID")]
|
||||
[Index(IndexTypes.Clustered, Name = "IX_umbracoUserLogins_Index")]
|
||||
public Guid ContextId { get; set; }
|
||||
|
||||
[Column("userID")]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[Column("timeout")]
|
||||
public long Timeout { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Represents a registered server in a multiple-servers environment.
|
||||
/// </summary>
|
||||
public class ServerRegistration : Entity, IServerAddress, IAggregateRoot
|
||||
public class ServerRegistration : Entity, IServerRegistration
|
||||
{
|
||||
private string _serverAddress;
|
||||
private string _serverIdentity;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Models
|
||||
public class Stylesheet : File
|
||||
{
|
||||
public Stylesheet(string path)
|
||||
: base(path)
|
||||
: base(path.EnsureEndsWith(".css"))
|
||||
{
|
||||
InitializeProperties();
|
||||
}
|
||||
@@ -33,11 +33,11 @@ namespace Umbraco.Core.Models
|
||||
//re-parse it so we can check what properties are different and adjust the event handlers
|
||||
var parsed = StylesheetHelper.ParseRules(Content).ToArray();
|
||||
var names = parsed.Select(x => x.Name).ToArray();
|
||||
var existing = _properties.Value.Where(x => names.Contains(x.Name)).ToArray();
|
||||
var existing = _properties.Value.Where(x => names.InvariantContains(x.Name)).ToArray();
|
||||
//update existing
|
||||
foreach (var stylesheetProperty in existing)
|
||||
{
|
||||
var updateFrom = parsed.Single(x => x.Name == stylesheetProperty.Name);
|
||||
var updateFrom = parsed.Single(x => x.Name.InvariantEquals(stylesheetProperty.Name));
|
||||
//remove current event handler while we update, we'll reset it after
|
||||
stylesheetProperty.PropertyChanged -= Property_PropertyChanged;
|
||||
stylesheetProperty.Alias = updateFrom.Selector;
|
||||
@@ -46,14 +46,14 @@ namespace Umbraco.Core.Models
|
||||
stylesheetProperty.PropertyChanged += Property_PropertyChanged;
|
||||
}
|
||||
//remove no longer existing
|
||||
var nonExisting = _properties.Value.Where(x => names.Contains(x.Name) == false).ToArray();
|
||||
var nonExisting = _properties.Value.Where(x => names.InvariantContains(x.Name) == false).ToArray();
|
||||
foreach (var stylesheetProperty in nonExisting)
|
||||
{
|
||||
stylesheetProperty.PropertyChanged -= Property_PropertyChanged;
|
||||
_properties.Value.Remove(stylesheetProperty);
|
||||
}
|
||||
//add new ones
|
||||
var newItems = parsed.Where(x => _properties.Value.Select(p => p.Name).Contains(x.Name) == false);
|
||||
var newItems = parsed.Where(x => _properties.Value.Select(p => p.Name).InvariantContains(x.Name) == false);
|
||||
foreach (var stylesheetRule in newItems)
|
||||
{
|
||||
var prop = new StylesheetProperty(stylesheetRule.Name, stylesheetRule.Selector, stylesheetRule.Styles);
|
||||
@@ -128,7 +128,7 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="property"></param>
|
||||
public void AddProperty(StylesheetProperty property)
|
||||
{
|
||||
if (Properties.Any(x => x.Name == property.Name))
|
||||
if (Properties.Any(x => x.Name.InvariantEquals(property.Name)))
|
||||
{
|
||||
throw new DuplicateNameException("The property with the name " + property.Name + " already exists in the collection");
|
||||
}
|
||||
@@ -151,7 +151,7 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="name"></param>
|
||||
public void RemoveProperty(string name)
|
||||
{
|
||||
if (Properties.Any(x => x.Name == name))
|
||||
if (Properties.Any(x => x.Name.InvariantEquals(name)))
|
||||
{
|
||||
Content = StylesheetHelper.ReplaceRule(Content, name, null);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
//TODO: Need to custom serialize this
|
||||
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class UmbracoDomain : Entity, IDomain
|
||||
@@ -16,25 +14,32 @@ namespace Umbraco.Core.Models
|
||||
_domainName = domainName;
|
||||
}
|
||||
|
||||
private IContent _content;
|
||||
private ILanguage _language;
|
||||
public UmbracoDomain(string domainName, string languageIsoCode)
|
||||
: this(domainName)
|
||||
{
|
||||
LanguageIsoCode = languageIsoCode;
|
||||
}
|
||||
|
||||
private int? _contentId;
|
||||
private int? _languageId;
|
||||
private string _domainName;
|
||||
|
||||
private static readonly PropertyInfo DefaultLanguageSelector = ExpressionHelper.GetPropertyInfo<UmbracoDomain, ILanguage>(x => x.Language);
|
||||
private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo<UmbracoDomain, int?>(x => x.RootContentId);
|
||||
private static readonly PropertyInfo DefaultLanguageSelector = ExpressionHelper.GetPropertyInfo<UmbracoDomain, int?>(x => x.LanguageId);
|
||||
private static readonly PropertyInfo DomainNameSelector = ExpressionHelper.GetPropertyInfo<UmbracoDomain, string>(x => x.DomainName);
|
||||
private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo<UmbracoDomain, IContent>(x => x.RootContent);
|
||||
|
||||
|
||||
[DataMember]
|
||||
public ILanguage Language
|
||||
public int? LanguageId
|
||||
{
|
||||
get { return _language; }
|
||||
get { return _languageId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_language = value;
|
||||
return _language;
|
||||
}, _language, DefaultLanguageSelector);
|
||||
_languageId = value;
|
||||
return _languageId;
|
||||
}, _languageId, DefaultLanguageSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,16 +58,16 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public IContent RootContent
|
||||
public int? RootContentId
|
||||
{
|
||||
get { return _content; }
|
||||
get { return _contentId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_content = value;
|
||||
return _content;
|
||||
}, _content, ContentSelector);
|
||||
_contentId = value;
|
||||
return _contentId;
|
||||
}, _contentId, ContentSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,5 +75,10 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get { return string.IsNullOrWhiteSpace(DomainName) || DomainName.StartsWith("*"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Readonly value of the language ISO code for the domain
|
||||
/// </summary>
|
||||
public string LanguageIsoCode { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
//create the legacy resolver and only include the legacy types
|
||||
_legacyResolver = new LegacyStartupHandlerResolver(
|
||||
serviceProvider, logger,
|
||||
applicationEventHandlers.Where(x => !TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>(x)));
|
||||
}
|
||||
|
||||
@@ -70,8 +71,8 @@ namespace Umbraco.Core.ObjectResolution
|
||||
|
||||
private class LegacyStartupHandlerResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>, IDisposable
|
||||
{
|
||||
internal LegacyStartupHandlerResolver(IEnumerable<Type> legacyStartupHandlers)
|
||||
: base(legacyStartupHandlers)
|
||||
internal LegacyStartupHandlerResolver(IServiceProvider serviceProvider, ILogger logger, IEnumerable<Type> legacyStartupHandlers)
|
||||
: base(serviceProvider, logger, legacyStartupHandlers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <exception cref="InvalidOperationException">resolution is already frozen.</exception>
|
||||
public static void Freeze()
|
||||
{
|
||||
LogHelper.Debug(typeof(Resolution), "Freezing resolution");
|
||||
LogHelper.Debug(typeof (Resolution), "Freezing resolution");
|
||||
|
||||
using (new WriteLock(ConfigurationLock))
|
||||
{
|
||||
@@ -121,9 +121,20 @@ namespace Umbraco.Core.ObjectResolution
|
||||
|
||||
_isFrozen = true;
|
||||
}
|
||||
|
||||
if (Frozen != null)
|
||||
Frozen(null, null);
|
||||
|
||||
LogHelper.Debug(typeof(Resolution), "Resolution is frozen");
|
||||
|
||||
if (Frozen == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
Frozen(null, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error(typeof (Resolution), "Exception in Frozen event handler.", e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
@@ -60,7 +62,7 @@ namespace Umbraco.Core.Persistence
|
||||
if (guardConfiguration && applicationContext.IsConfigured)
|
||||
throw new Exception("Umbraco is already configured!");
|
||||
|
||||
CreateDatabaseSchemaDo();
|
||||
CreateDatabaseSchemaDo(applicationContext.Services.MigrationEntryService);
|
||||
}
|
||||
|
||||
internal void CreateDatabaseSchemaDo(bool guardConfiguration, ApplicationContext applicationContext)
|
||||
@@ -68,16 +70,19 @@ namespace Umbraco.Core.Persistence
|
||||
if (guardConfiguration && applicationContext.IsConfigured)
|
||||
throw new Exception("Umbraco is already configured!");
|
||||
|
||||
CreateDatabaseSchemaDo();
|
||||
CreateDatabaseSchemaDo(applicationContext.Services.MigrationEntryService);
|
||||
}
|
||||
|
||||
internal void CreateDatabaseSchemaDo()
|
||||
internal void CreateDatabaseSchemaDo(IMigrationEntryService migrationEntryService)
|
||||
{
|
||||
_logger.Info<Database>("Initializing database schema creation");
|
||||
|
||||
var creation = new DatabaseSchemaCreation(_db, _logger, _syntaxProvider);
|
||||
creation.InitializeDatabaseSchema();
|
||||
|
||||
//Now ensure to cretae the tag in the db for the current migration version
|
||||
migrationEntryService.CreateEntry(GlobalSettings.UmbracoMigrationName, UmbracoVersion.GetSemanticVersion());
|
||||
|
||||
_logger.Info<Database>("Finalized database schema creation");
|
||||
}
|
||||
|
||||
@@ -146,6 +151,13 @@ namespace Umbraco.Core.Persistence
|
||||
_db.Update<UserDto>("SET id = @IdAfter WHERE id = @IdBefore AND userLogin = @Login", new { IdAfter = 0, IdBefore = 1, Login = "admin" });
|
||||
}
|
||||
|
||||
//Loop through index statements and execute sql
|
||||
foreach (var sql in indexSql)
|
||||
{
|
||||
int createdIndex = _db.Execute(new Sql(sql));
|
||||
_logger.Info<Database>(string.Format("Create Index sql {0}:\n {1}", createdIndex, sql));
|
||||
}
|
||||
|
||||
//Loop through foreignkey statements and execute sql
|
||||
foreach (var sql in foreignSql)
|
||||
{
|
||||
@@ -153,12 +165,7 @@ namespace Umbraco.Core.Persistence
|
||||
_logger.Info<Database>(string.Format("Create Foreign Key sql {0}:\n {1}", createdFk, sql));
|
||||
}
|
||||
|
||||
//Loop through index statements and execute sql
|
||||
foreach (var sql in indexSql)
|
||||
{
|
||||
int createdIndex = _db.Execute(new Sql(sql));
|
||||
_logger.Info<Database>(string.Format("Create Index sql {0}:\n {1}", createdIndex, sql));
|
||||
}
|
||||
|
||||
|
||||
transaction.Complete();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
@@ -75,8 +76,10 @@ namespace Umbraco.Core.Persistence
|
||||
connection.Open();
|
||||
connection.Close();
|
||||
}
|
||||
catch (DbException)
|
||||
catch (DbException exc)
|
||||
{
|
||||
// Don't swallow this error, the exception is super handy for knowing "why" its not available
|
||||
LogHelper.WarnWithException<IDbConnection>("Configured database is reporting as not being available!", exc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user