Compare commits
498 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 635ebcb9be | |||
| 33f7a8477d | |||
| 646194e013 | |||
| 425fcf36eb | |||
| 31fd05ebca | |||
| 495b4ed9e0 | |||
| 87c904cc96 | |||
| 03c65c8eec | |||
| 14aeb55c14 | |||
| 7ddbc83731 | |||
| 17533c57d3 | |||
| 433668e202 | |||
| 9edcc0c903 | |||
| f747f69c62 | |||
| e07985439a | |||
| 620f21d7d7 | |||
| 4a13047d5d | |||
| 446a480f21 | |||
| b56f8c8fb3 | |||
| 296c24f829 | |||
| c5e88ef69f | |||
| 2a7e493c74 | |||
| e14d3fd379 | |||
| fa43cfd58f | |||
| 711afe8bb7 | |||
| 23525300bb | |||
| 8d33488923 | |||
| 32a6a49077 | |||
| b93ea7c69b | |||
| 640be73a66 | |||
| 32ae88fc81 | |||
| a4c9c3bfd9 | |||
| 182107286c | |||
| a7e939e71f | |||
| 83d05bd01c | |||
| 9fb10ea004 | |||
| c916df0d13 | |||
| 99a63a3cdb | |||
| ad52c0f033 | |||
| 6d18d32356 | |||
| 75f0f1f4ee | |||
| 425a9f6a34 | |||
| 1d5f7ae822 | |||
| 3f7a93e0c9 | |||
| 72ad9f51c1 | |||
| 20fb27f7e1 | |||
| c8e20cf64b | |||
| 3accecd504 | |||
| d9121b4684 | |||
| 132ec1702c | |||
| a4e3127704 | |||
| 2678e23c7d | |||
| 4dc94d1e0b | |||
| b058b1e345 | |||
| dfa1e73ddf | |||
| 390f56a64d | |||
| 04c623f19c | |||
| 633d88c8c4 | |||
| 40a9da5ee0 | |||
| 3b982b80f5 | |||
| 1cada5aeb5 | |||
| 64719586dc | |||
| 63d010f78f | |||
| e97a01c75c | |||
| 65ae43918d | |||
| 21c635f61a | |||
| 6cc747bf76 | |||
| af2693af76 | |||
| d95fc0210e | |||
| 00de509478 | |||
| 1b5139889c | |||
| d976fbe4de | |||
| 47474d31d6 | |||
| 840a95ba62 | |||
| e18d8da872 | |||
| b6ec364156 | |||
| 6b07ee83eb | |||
| 7e0c1fac36 | |||
| 8cdfba42d5 | |||
| e8dd56786b | |||
| 2a9309ea38 | |||
| c732ee6eb2 | |||
| ee2f2dfda0 | |||
| 9d6b38a1c1 | |||
| f6490a897a | |||
| ce8f5c167c | |||
| 5f242aa3f6 | |||
| ab8b0f4ebb | |||
| a57d3f7eba | |||
| f5a1e41569 | |||
| 8c79977a23 | |||
| 52f05612ad | |||
| c5a0da6aa5 | |||
| 266aa3423b | |||
| 7ea87638f7 | |||
| b96b372400 | |||
| fcb8f0d417 | |||
| 6e3c4854b9 | |||
| ba24deffc9 | |||
| aa7fd7bb2b | |||
| e7a6a29e59 | |||
| c43efbbfc4 | |||
| adedc9b64b | |||
| 73d77083ae | |||
| b2a1f67fb4 | |||
| 3a0d617b14 | |||
| ce0c72d9f8 | |||
| cb966ac70b | |||
| 6c40f32c2a | |||
| cce32f406f | |||
| 610ff91a9d | |||
| 45f39158ba | |||
| d7b5d73e62 | |||
| 780a9632f0 | |||
| 603b6c73f7 | |||
| 1b66c42c9b | |||
| 5175fb5188 | |||
| b260769799 | |||
| 4495fd05c4 | |||
| 923653f2b5 | |||
| 083320002b | |||
| 3052c7311f | |||
| 3af7958940 | |||
| c7498cec03 | |||
| abe4ec6524 | |||
| e3a8b4ac78 | |||
| 365dffe2db | |||
| 381157ac5d | |||
| f993e96547 | |||
| 734f75b3ad | |||
| 7ef066f396 | |||
| 23bb0e3ac3 | |||
| 2dea4a1d70 | |||
| 07bdd138cc | |||
| 2b750843c5 | |||
| bd81507ecb | |||
| ea7fb32fb9 | |||
| 2cd64dd540 | |||
| 2a058cdbcc | |||
| 37860b4015 | |||
| 0f056b1702 | |||
| aa5588bbd3 | |||
| 33c5c41a31 | |||
| 8d3c798c6c | |||
| 245591c31f | |||
| 8fb8fc00b4 | |||
| 50b05d25f5 | |||
| c04ee7bdc7 | |||
| 75d218d2e3 | |||
| 4efa2c9f57 | |||
| 630a44358f | |||
| f7015d521b | |||
| 860c8c1002 | |||
| a2120d1c6b | |||
| fc3f9dfeae | |||
| cf64c0243c | |||
| ca9f53738b | |||
| 8d2e466e34 | |||
| ec46d65bb4 | |||
| 164f22aa50 | |||
| cc50003e3e | |||
| 8698deb469 | |||
| 738e4f5c46 | |||
| c854ea8a35 | |||
| 9bd865d259 | |||
| 2d55dda662 | |||
| 29b2458ef3 | |||
| 1e6de161e6 | |||
| 508886b1ad | |||
| 3ab0879a99 | |||
| 4baecfe833 | |||
| 3612f18f3f | |||
| 86852f9815 | |||
| 9aa44c40ce | |||
| da331b7408 | |||
| 0230bedeb6 | |||
| bd6aa51397 | |||
| 9b85bc0e64 | |||
| 2044d1b5db | |||
| 2c05eda899 | |||
| 0852200861 | |||
| f955955ad8 | |||
| 9042a23de7 | |||
| b9eaaa0f29 | |||
| f79d046a87 | |||
| 737d7d6712 | |||
| 4d8ed22206 | |||
| 06dc76496d | |||
| 2877b7bda4 | |||
| c137854e01 | |||
| fe9f5b224a | |||
| 45f2cc9a20 | |||
| f1c680c7e2 | |||
| 36108df4d0 | |||
| 51ad21302a | |||
| 010893a73a | |||
| 32e6604cf7 | |||
| b2cedf6380 | |||
| 9fc5ee897f | |||
| e8e8053063 | |||
| c635ec67d0 | |||
| 750370d148 | |||
| 2c6daa2918 | |||
| e33c877605 | |||
| 85e73df3c8 | |||
| a17a11d50b | |||
| 6ead98a51d | |||
| 7cc12211e1 | |||
| f9b7e1b7fa | |||
| 33c5f3fcc7 | |||
| 47f6924ac3 | |||
| 45b8daa18c | |||
| 1157c11d89 | |||
| 6815092b62 | |||
| 876753cb54 | |||
| b374dcf2c2 | |||
| f7cfa507d7 | |||
| 5df0013406 | |||
| 30d08bfae1 | |||
| b0ae03b220 | |||
| ffb9849745 | |||
| cc55107da3 | |||
| 6c4ee40b96 | |||
| c637c517b8 | |||
| cdf6249a41 | |||
| d9540bcfc5 | |||
| aeb417d3d8 | |||
| bcfc7b2507 | |||
| 7c32365bd3 | |||
| bf6ba727a4 | |||
| 63159702e3 | |||
| 545a873af2 | |||
| db268c6805 | |||
| 2967075c1f | |||
| 4761e4bd43 | |||
| a27dccd0d9 | |||
| 6b8bfc2e2d | |||
| 5b15218174 | |||
| 894cfb2e85 | |||
| 7deae8ea37 | |||
| 03aa7fd06b | |||
| 54ba547c8c | |||
| c1172b6823 | |||
| a91d531db2 | |||
| dd0d4e872f | |||
| 265fd6b91c | |||
| 038b4300ba | |||
| 958d7940f2 | |||
| a3f7ef7002 | |||
| 36eb340c11 | |||
| aa929e8091 | |||
| 2ebfbd5d08 | |||
| 567be2aecf | |||
| 6a6ac99c34 | |||
| 03fc0c868c | |||
| dced287c1c | |||
| bcd426092c | |||
| 62ed7e0a53 | |||
| 566986201f | |||
| a9947cda48 | |||
| 271b0691e2 | |||
| cf46df441a | |||
| aec017e933 | |||
| 3727ef54aa | |||
| 5615f9590b | |||
| e084ddeb41 | |||
| f8760b34b8 | |||
| 9d95c04ab6 | |||
| 62c4713593 | |||
| e3ef3dfb32 | |||
| 7509724e35 | |||
| a41e32c068 | |||
| 3baf326498 | |||
| 8ea9627d51 | |||
| 957feefb2e | |||
| 40b7659078 | |||
| 0427ecc7f4 | |||
| 11560a5451 | |||
| 5bef77c0fb | |||
| 89b85bcf4b | |||
| 694d252ce5 | |||
| 7efc06429c | |||
| ad188fab70 | |||
| b47f9e87f1 | |||
| dddc308167 | |||
| 5919dca5d5 | |||
| 7493426e25 | |||
| 1733e876c4 | |||
| c958422317 | |||
| 6a9277a712 | |||
| 2d336fde73 | |||
| ac3bec5d9e | |||
| 7da60e9937 | |||
| eba5fc84c0 | |||
| 71d8736e7e | |||
| ae1ff4c39a | |||
| f9f998e823 | |||
| e10fc26729 | |||
| 0d6999292c | |||
| 3e7681d4d2 | |||
| c838b8a381 | |||
| 96a279499b | |||
| a3f0b7a37f | |||
| ec87b951d5 | |||
| 2e033b3bb6 | |||
| d8721197b7 | |||
| 4a05b0ea31 | |||
| 663fc4f954 | |||
| 845595b01b | |||
| 2fca8f3444 | |||
| 9324ab8e0e | |||
| e6faf73f4f | |||
| 9f301f8cc6 | |||
| e7c5d1f4f3 | |||
| 91ee948b4e | |||
| c1ed910a51 | |||
| 7414b3596e | |||
| a995c9557c | |||
| 55f06a7ca6 | |||
| e921dca9d6 | |||
| 9ad813d990 | |||
| 9fba3fa673 | |||
| a00278892a | |||
| 196357f6c3 | |||
| 7a736344f9 | |||
| a36824e796 | |||
| 6e2dc64001 | |||
| 68d5acbe48 | |||
| a6b9ceef7b | |||
| 8de579083c | |||
| 6a6b82d1e8 | |||
| ac090c05ae | |||
| 527ef10cda | |||
| 766cf56a3f | |||
| 73714c7cef | |||
| 0485c20331 | |||
| d104ea1b57 | |||
| 41c952a2fa | |||
| 6c09a58baf | |||
| 8d2c5029af | |||
| 8c97e367a2 | |||
| 6423914f01 | |||
| 3b25214433 | |||
| 35a8c5e980 | |||
| 64031777d8 | |||
| 102bf058bc | |||
| 7f51e01be7 | |||
| cb3ac17f43 | |||
| 8dc5092763 | |||
| 4e6bdd1fc7 | |||
| f741861014 | |||
| 5e4a23ea84 | |||
| ea54997bb7 | |||
| da4f51fe2c | |||
| fc9aa1d231 | |||
| ac43b40f33 | |||
| 77201f3805 | |||
| 81f7754a45 | |||
| 2f9360ac08 | |||
| c23be1fd96 | |||
| 1c7bb623f1 | |||
| 75de4e4e67 | |||
| ded940a757 | |||
| b80415b34e | |||
| 2ecc978591 | |||
| de13f7e361 | |||
| 0af4b3da82 | |||
| def651d98e | |||
| a03f5420fa | |||
| 4ab14484ba | |||
| a0f662c114 | |||
| 975d84f3d0 | |||
| c0b708b1f4 | |||
| d93ca26181 | |||
| cf8a0728d8 | |||
| ea24e43c90 | |||
| 75e747a2d2 | |||
| be398a4616 | |||
| 84bd89f00b | |||
| a1c2352dca | |||
| b6ec42334b | |||
| 56fb570267 | |||
| 510d8b9dda | |||
| d8e4895daa | |||
| c20cd907b0 | |||
| c72b4f40bd | |||
| f8d09a9ac3 | |||
| a399a8766d | |||
| 7f103724f3 | |||
| 98ecf0e824 | |||
| 5fb11a77e7 | |||
| d7c72dc279 | |||
| 2c8c88e4b8 | |||
| 9f7347a4f5 | |||
| 13e5590efa | |||
| 77bffa69fd | |||
| 763f8796e0 | |||
| 3be13f57cf | |||
| 31a5363387 | |||
| ef20f228ec | |||
| bc08feaa08 | |||
| ef9ce720b2 | |||
| 4c3d2c10ac | |||
| 0db781b59f | |||
| c94eb4328f | |||
| 47ab187780 | |||
| 020cc54da7 | |||
| dd0a18cf5b | |||
| f726ec740a | |||
| db79b95d22 | |||
| bac2b7643f | |||
| 11449688ba | |||
| b080ebf697 | |||
| 0b0784d40c | |||
| bfb36cac7c | |||
| dd2a1207f4 | |||
| 58b3ce749e | |||
| 6c693ff7b1 | |||
| 95df864d01 | |||
| eaa36a248c | |||
| ca7fe6854b | |||
| 1be3af1e31 | |||
| b8bcb3820a | |||
| 571849f211 | |||
| c8bcbdb3e1 | |||
| 32c187f023 | |||
| dda9519e5e | |||
| 91ff702cf2 | |||
| f7f269aa79 | |||
| 0d34b203d5 | |||
| 34975183d2 | |||
| 545a156942 | |||
| f9d5b28372 | |||
| 8df7812165 | |||
| d1ac2f11d1 | |||
| 5d681c18fe | |||
| a66d651c07 | |||
| e541995e01 | |||
| 6ee17dad03 | |||
| e8d924cd2c | |||
| fa2ea78bda | |||
| 1989a44d4f | |||
| 6b3de00e08 | |||
| 8b00e72bf6 | |||
| 56281d64b0 | |||
| 024a4ed8d0 | |||
| 789927a043 | |||
| cc0ad0b089 | |||
| a94f3b6211 | |||
| 1340cc0b2e | |||
| c8aedb381b | |||
| 64692e0041 | |||
| f1039a18e4 | |||
| 23b6cf1c24 | |||
| 09f50da821 | |||
| 197ab6357f | |||
| b3e3855931 | |||
| f466bc7cfb | |||
| b77521cbc5 | |||
| 58b91fe6a0 | |||
| a95fbff597 | |||
| 80ee18ee95 | |||
| 6146a0576c | |||
| 73df3ec0de | |||
| d24e4834aa | |||
| 38593ea36c | |||
| 1b232f3214 | |||
| aa1ded5f1a | |||
| e5a20f0c1b | |||
| 9d701cabf6 | |||
| c6c522da04 | |||
| 2251f39fcf | |||
| 01b4e8d59c | |||
| bfd8e96f71 | |||
| e7b84b1637 | |||
| b8ac74a05d | |||
| 38624b1e59 | |||
| a699d9e1de | |||
| cda7a66ec8 | |||
| 36a5313336 | |||
| fedcdcfcd5 | |||
| 11964401c8 | |||
| 48202cfa09 | |||
| 8cac3e9c5c | |||
| 25c481b3ca | |||
| 6b254e1a20 | |||
| a00ceb24e1 | |||
| c587632ea0 | |||
| 8f2c662f27 | |||
| dc06e303fc | |||
| dbf38fbeb8 | |||
| 97ffed5ee7 | |||
| 8b49d2d377 | |||
| 6513097d38 | |||
| d1bf2c0ad7 | |||
| 59152cbe80 | |||
| 027f76af96 | |||
| eece4c194a |
+2
-2
@@ -1,6 +1,6 @@
|
||||
@ECHO OFF
|
||||
SET release=6.0.3
|
||||
SET comment=
|
||||
SET release=6.1.0
|
||||
SET comment=beta
|
||||
SET version=%release%
|
||||
|
||||
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
|
||||
|
||||
+193
-153
@@ -1,19 +1,19 @@
|
||||
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!--
|
||||
<!--
|
||||
****************************************************
|
||||
INCLUDES
|
||||
*****************************************************
|
||||
-->
|
||||
|
||||
<PropertyGroup>
|
||||
<MSBuildCommunityTasksPath>..\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
|
||||
<UmbracoMSBuildTasksPath>..\UmbracoMSBuildTasks</UmbracoMSBuildTasksPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\tools\UmbracoMSBuildTasks\Umbraco.MSBuild.Tasks.Targets" />
|
||||
<Import Project="..\tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
|
||||
<PropertyGroup>
|
||||
<MSBuildCommunityTasksPath>..\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
|
||||
<UmbracoMSBuildTasksPath>..\UmbracoMSBuildTasks</UmbracoMSBuildTasksPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\tools\UmbracoMSBuildTasks\Umbraco.MSBuild.Tasks.Targets" />
|
||||
<Import Project="..\tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
|
||||
|
||||
<UsingTask TaskName="GenerateHash" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
@@ -53,65 +53,68 @@
|
||||
</UsingTask>
|
||||
|
||||
|
||||
<!--
|
||||
<!--
|
||||
****************************************************
|
||||
VARIABLES
|
||||
*****************************************************
|
||||
-->
|
||||
|
||||
<!-- NB: BUILD_NUMBER is passed in by the build server -->
|
||||
<PropertyGroup Condition="'$(BUILD_NUMBER)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_NUMBER)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!='' AND '$(BUILD_COMMENT)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)-$(BUILD_COMMENT)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BuildConfiguration>Release</BuildConfiguration>
|
||||
<BuildFolder>_BuildOutput\</BuildFolder>
|
||||
<BuildZipFileName>UmbracoCms$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileName>
|
||||
<BuildZipFileNameBin>UmbracoCms.AllBinaries$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameBin>
|
||||
<BuildZipFileNameWebPi>UmbracoCms.WebPI$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameWebPi>
|
||||
<IncludeSymbols>False</IncludeSymbols>
|
||||
<BuildFolderRelativeToProjects>..\..\build\$(BuildFolder)</BuildFolderRelativeToProjects>
|
||||
<BuildFolderAbsolutePath>$(MSBuildProjectDirectory)\$(BuildFolder)</BuildFolderAbsolutePath>
|
||||
<SolutionBinFolder>$(BuildFolder)bin\</SolutionBinFolder>
|
||||
<WebAppFolder>$(BuildFolder)WebApp\</WebAppFolder>
|
||||
<WebPiFolder>$(BuildFolder)WebPi\</WebPiFolder>
|
||||
<SolutionBinFolderRelativeToProjects>$(BuildFolderRelativeToProjects)bin\</SolutionBinFolderRelativeToProjects>
|
||||
<SolutionBinFolderAbsolutePath>$(BuildFolderAbsolutePath)bin\</SolutionBinFolderAbsolutePath>
|
||||
<WebAppFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebApp\</WebAppFolderRelativeToProjects>
|
||||
<WebAppFolderAbsolutePath>$(BuildFolderAbsolutePath)WebApp\</WebAppFolderAbsolutePath>
|
||||
<WebPiFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebPi\</WebPiFolderRelativeToProjects>
|
||||
<WebPiFolderAbsolutePath>$(BuildFolderAbsolutePath)WebPi\</WebPiFolderAbsolutePath>
|
||||
</PropertyGroup>
|
||||
<!-- NB: BUILD_NUMBER is passed in by the build server -->
|
||||
<PropertyGroup Condition="'$(BUILD_NUMBER)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_NUMBER)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!='' AND '$(BUILD_COMMENT)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)-$(BUILD_COMMENT)</DECIMAL_BUILD_NUMBER>
|
||||
</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)macroScripts" />
|
||||
<SystemFolders Include="$(WebAppFolder)xslt" />
|
||||
<SystemFolders Include="$(WebAppFolder)usercontrols" />
|
||||
<SystemFolders Include="$(WebAppFolder)Views" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<BuildConfiguration>Release</BuildConfiguration>
|
||||
<BuildFolder>_BuildOutput\</BuildFolder>
|
||||
<BuildZipFileName>UmbracoCms$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileName>
|
||||
<BuildZipFileNameBin>UmbracoCms.AllBinaries$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameBin>
|
||||
<BuildZipFileNameWebPi>UmbracoCms.WebPI$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameWebPi>
|
||||
<IncludeSymbols>False</IncludeSymbols>
|
||||
<BuildFolderRelativeToProjects>..\..\build\$(BuildFolder)</BuildFolderRelativeToProjects>
|
||||
<BuildFolderAbsolutePath>$(MSBuildProjectDirectory)\$(BuildFolder)</BuildFolderAbsolutePath>
|
||||
<SolutionBinFolder>$(BuildFolder)bin\</SolutionBinFolder>
|
||||
<WebAppFolder>$(BuildFolder)WebApp\</WebAppFolder>
|
||||
<WebPiFolder>$(BuildFolder)WebPi\</WebPiFolder>
|
||||
<SolutionBinFolderRelativeToProjects>$(BuildFolderRelativeToProjects)bin\</SolutionBinFolderRelativeToProjects>
|
||||
<SolutionBinFolderAbsolutePath>$(BuildFolderAbsolutePath)bin\</SolutionBinFolderAbsolutePath>
|
||||
<WebAppFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebApp\</WebAppFolderRelativeToProjects>
|
||||
<WebAppFolderAbsolutePath>$(BuildFolderAbsolutePath)WebApp\</WebAppFolderAbsolutePath>
|
||||
<WebPiFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebPi\</WebPiFolderRelativeToProjects>
|
||||
<WebPiFolderAbsolutePath>$(BuildFolderAbsolutePath)WebPi\</WebPiFolderAbsolutePath>
|
||||
<ExaminePDFPath>$(BuildFolderAbsolutePath)UmbracoExamine.PDF\</ExaminePDFPath>
|
||||
<ExamineAzurePath>$(BuildFolderAbsolutePath)UmbracoExamine.Azure\</ExamineAzurePath>
|
||||
<ExaminePDFAzurePath>$(BuildFolderAbsolutePath)UmbracoExamine.PDF.Azure\</ExaminePDFAzurePath>
|
||||
</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)MacroScripts" />
|
||||
<SystemFolders Include="$(WebAppFolder)Xslt" />
|
||||
<SystemFolders Include="$(WebAppFolder)UserControls" />
|
||||
<SystemFolders Include="$(WebAppFolder)Views" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
****************************************************
|
||||
TARGETS
|
||||
*****************************************************
|
||||
-->
|
||||
|
||||
<Target Name="Build" DependsOnTargets="GenerateWebPiHash">
|
||||
<Message Text="Build finished" />
|
||||
<Message Text="Build finished" />
|
||||
</Target>
|
||||
|
||||
<Target Name="GenerateWebPiHash" DependsOnTargets="ZipWebPiApp">
|
||||
@@ -120,117 +123,154 @@
|
||||
</ItemGroup>
|
||||
<Message Text="Calculating hash for $(BuildZipFileNameWebPi)" />
|
||||
<GenerateHash InputFiles="@(WebPiFile)" OutputFile="webpihash.txt" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CleanUp" DependsOnTargets="ZipWebPiApp">
|
||||
<Message Text="Deleting $(BuildFolder)" Importance="high" />
|
||||
<RemoveDir Directories="$(BuildFolder)" />
|
||||
<Message Text="Finished deleting $(BuildFolder)" Importance="high" />
|
||||
</Target>
|
||||
</Target>
|
||||
|
||||
<Target Name="ZipWebPiApp" DependsOnTargets="ZipWebApp" >
|
||||
<!-- Clean folders -->
|
||||
<RemoveDir Directories="$(WebPiFolder)" />
|
||||
<MakeDir Directories="$(WebPiFolder)" />
|
||||
<MakeDir Directories="$(WebPiFolder)umbraco" />
|
||||
<Target Name="CleanUp" DependsOnTargets="ZipWebPiApp">
|
||||
<Message Text="Deleting $(BuildFolder)" Importance="high" />
|
||||
<RemoveDir Directories="$(BuildFolder)" />
|
||||
<Message Text="Finished deleting $(BuildFolder)" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<!-- Copy fresh built umbraco files -->
|
||||
<Exec Command="xcopy %22$(WebAppFolderAbsolutePath)*%22 %22$(WebPiFolderAbsolutePath)umbraco%22 /S /E /Y /I" />
|
||||
|
||||
<!-- Copy Web Pi template files -->
|
||||
<ItemGroup>
|
||||
<WebPiFiles Include="..\src\WebPi\**\*.*" />
|
||||
</ItemGroup>
|
||||
<Target Name="ZipWebPiApp" DependsOnTargets="ZipWebApp" >
|
||||
<!-- Clean folders -->
|
||||
<RemoveDir Directories="$(WebPiFolder)" />
|
||||
<MakeDir Directories="$(WebPiFolder)" />
|
||||
<MakeDir Directories="$(WebPiFolder)umbraco" />
|
||||
|
||||
<Copy SourceFiles="@(WebPiFiles)"
|
||||
DestinationFiles="@(WebPiFiles->'$(WebPiFolder)%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
<!-- Copy fresh built umbraco files -->
|
||||
<Exec Command="xcopy %22$(WebAppFolderAbsolutePath)*%22 %22$(WebPiFolderAbsolutePath)umbraco%22 /S /E /Y /I" />
|
||||
|
||||
<!-- Zip the files -->
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22" />
|
||||
</Target>
|
||||
|
||||
<Target Name="ZipWebApp" DependsOnTargets="CreateSystemFolders" >
|
||||
<Message Text="Starting to zip to $(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
<!-- Copy Web Pi template files -->
|
||||
<ItemGroup>
|
||||
<WebPiFiles Include="..\src\WebPi\**\*.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameBin)%22 %22$(SolutionBinFolderAbsolutePath)*%22" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileName)%22 %22$(WebAppFolderAbsolutePath)*%22" />
|
||||
|
||||
<Message Text="Finished zipping to build\$(BuildFolder)\$(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
</Target>
|
||||
<Copy SourceFiles="@(WebPiFiles)"
|
||||
DestinationFiles="@(WebPiFiles->'$(WebPiFolder)%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
|
||||
<Target Name="CreateSystemFolders" DependsOnTargets="CopyLibraries" Inputs="@(SystemFolders)" Outputs="%(Identity).Dummy">
|
||||
<MakeDir Directories="@(SystemFolders)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyLibraries" DependsOnTargets="OffsetTimestamps" >
|
||||
<!-- Copy SQL CE -->
|
||||
<ItemGroup>
|
||||
<SQLCE4Files
|
||||
Include="..\src\packages\SqlServerCE.4.0.0.0\**\*.*"
|
||||
Exclude="..\src\packages\SqlServerCE.4.0.0.0\lib\**\*;..\src\packages\SqlServerCE.4.0.0.0\**\*.nu*"
|
||||
<!-- Zip the files -->
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22" />
|
||||
</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" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileName)%22 %22$(WebAppFolderAbsolutePath)*%22" />
|
||||
|
||||
<Message Text="Finished zipping to build\$(BuildFolder)\$(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CreateSystemFolders" DependsOnTargets="CopyLibraries" Inputs="@(SystemFolders)" Outputs="%(Identity).Dummy">
|
||||
<MakeDir Directories="@(SystemFolders)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyLibraries" DependsOnTargets="OffsetTimestamps" >
|
||||
<!-- Copy SQL CE -->
|
||||
<ItemGroup>
|
||||
<SQLCE4Files
|
||||
Include="..\src\packages\SqlServerCE.4.0.0.0\**\*.*"
|
||||
Exclude="..\src\packages\SqlServerCE.4.0.0.0\lib\**\*;..\src\packages\SqlServerCE.4.0.0.0\**\*.nu*"
|
||||
/>
|
||||
</ItemGroup>
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(SQLCE4Files)"
|
||||
DestinationFiles="@(SQLCE4Files->'$(SolutionBinFolder)%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(SQLCE4Files)"
|
||||
DestinationFiles="@(SQLCE4Files->'$(SolutionBinFolder)%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
|
||||
<Copy SourceFiles="@(SQLCE4Files)"
|
||||
DestinationFiles="@(SQLCE4Files->'$(WebAppFolder)bin\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
|
||||
</Target>
|
||||
<Copy SourceFiles="@(SQLCE4Files)"
|
||||
DestinationFiles="@(SQLCE4Files->'$(WebAppFolder)bin\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
|
||||
<!-- Offset the modified timestamps on all umbraco dlls, as WebResources break if date is in the future, which, due to timezone offsets can happen. -->
|
||||
<Target Name="OffsetTimestamps" DependsOnTargets="CopyTransformedWebConfig">
|
||||
<CreateItem Include="$(BuildFolder)**\umbraco.*.dll">
|
||||
<Output TaskParameter="Include" ItemName="FilesToOffsetTimestamp" />
|
||||
</CreateItem>
|
||||
<Message Text="Starting to offset timestamps" Importance="high" />
|
||||
<Umbraco.MSBuild.Tasks.TimestampOffset Files="@(FilesToOffsetTimestamp)" Offset="-11" />
|
||||
<Message Text="Finished offsetting timestamps" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<!-- Copy the transformed web.config file to the root -->
|
||||
<Target Name="CopyTransformedWebConfig" DependsOnTargets="CopyXmlDocumentation">
|
||||
<ItemGroup>
|
||||
<WebConfigFile Include="..\src\Umbraco.Web.UI\web.$(BuildConfiguration).Config.transformed" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(WebConfigFile)"
|
||||
DestinationFiles="$(WebAppFolder)Web.config"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
</Target>
|
||||
|
||||
<!-- Copy the xml documentation to the bin folder -->
|
||||
<Target Name="CopyXmlDocumentation" DependsOnTargets="CompileProjects">
|
||||
<ItemGroup>
|
||||
<XmlDocumentationFiles Include="$(SolutionBinFolder)*.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(XmlDocumentationFiles)"
|
||||
DestinationFiles="@(XmlDocumentationFiles->'$(WebAppFolder)bin\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<Message Text="CopyXmlDocumentation" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileProjects" DependsOnTargets="SetVersionNumber">
|
||||
<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 -->
|
||||
<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;Build;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
|
||||
</MSBuild>
|
||||
</Target>
|
||||
|
||||
<!-- DONE -->
|
||||
<Message Text="Finished compiling projects" Importance="high" />
|
||||
</Target>
|
||||
<!-- Offset the modified timestamps on all umbraco dlls, as WebResources break if date is in the future, which, due to timezone offsets can happen. -->
|
||||
<Target Name="OffsetTimestamps" DependsOnTargets="CopyTransformedWebConfig">
|
||||
<CreateItem Include="$(BuildFolder)**\umbraco.*.dll">
|
||||
<Output TaskParameter="Include" ItemName="FilesToOffsetTimestamp" />
|
||||
</CreateItem>
|
||||
<Message Text="Starting to offset timestamps" Importance="high" />
|
||||
<Umbraco.MSBuild.Tasks.TimestampOffset Files="@(FilesToOffsetTimestamp)" Offset="-11" />
|
||||
<Message Text="Finished offsetting timestamps" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<!-- Copy the transformed web.config file to the root -->
|
||||
<Target Name="CopyTransformedWebConfig" DependsOnTargets="CopyXmlDocumentation">
|
||||
<ItemGroup>
|
||||
<WebConfigFile Include="..\src\Umbraco.Web.UI\web.$(BuildConfiguration).Config.transformed" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(WebConfigFile)"
|
||||
DestinationFiles="$(WebAppFolder)Web.config"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
</Target>
|
||||
|
||||
<!-- Copy the xml documentation to the bin folder -->
|
||||
<Target Name="CopyXmlDocumentation" DependsOnTargets="CompileProjects">
|
||||
<ItemGroup>
|
||||
<XmlDocumentationFiles Include="$(SolutionBinFolder)*.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(XmlDocumentationFiles)"
|
||||
DestinationFiles="@(XmlDocumentationFiles->'$(WebAppFolder)bin\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<Message Text="CopyXmlDocumentation" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileProjects" DependsOnTargets="CompileExternalExamineProjects">
|
||||
|
||||
<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;Build;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
|
||||
</MSBuild>
|
||||
|
||||
<!-- DONE -->
|
||||
<Message Text="Finished compiling projects" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileExternalExamineProjects" DependsOnTargets="SetVersionNumber">
|
||||
<Message Text="Building externally shipped examine projects" Importance="high" />
|
||||
|
||||
<!-- First remove old files from the examine builds -->
|
||||
<ItemGroup>
|
||||
<FilesToDeleteBeforeBuild Include="$(ExaminePDFPath)*;$(ExamineAzurePath)*"/>
|
||||
</ItemGroup>
|
||||
<Delete Files="@(FilesToDeleteBeforeBuild)" />
|
||||
<!--
|
||||
Build the UmbracoExamine.PDF.Azure library ... this builds the 3 projects that we want to bundle separately so no need to build each one separately .
|
||||
We'll just build this one and then manually copy the DLLs to where we want them.
|
||||
-->
|
||||
<MSBuild Projects="..\src\UmbracoExamine.PDF.Azure\UmbracoExamine.PDF.Azure.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);PipelineDependsOnBuild=False;OutDir=$(ExaminePDFAzurePath);" Targets="Clean;Build;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
|
||||
</MSBuild>
|
||||
<ItemGroup>
|
||||
<ExaminePDFFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.pdf;$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.xml;$(ExaminePDFAzurePath)**\itextsharp.dll" />
|
||||
<ExamineAzureFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.pdb;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.xml" />
|
||||
<ExaminePDFAzureFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.pdb;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.xml" />
|
||||
</ItemGroup>
|
||||
<!-- Now copy the built files to their correct deployment folders-->
|
||||
<Copy SourceFiles="@(ExaminePDFFiles)"
|
||||
DestinationFolder="$(ExaminePDFPath)"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(ExamineAzureFiles)"
|
||||
DestinationFolder="$(ExamineAzurePath)"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<!-- Then just delete the files we don't want to ship in the UmbracoExamine.Azure.PDF folder -->
|
||||
<ItemGroup>
|
||||
<FilesToDeleteAfterBuild Include="$(ExaminePDFAzurePath)*" Exclude="$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.dll;$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.pdb;$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.xml"/>
|
||||
</ItemGroup>
|
||||
<Delete Files="@(FilesToDeleteAfterBuild)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<!-- Match & replace 3 and 4 digit version numbers and -beta (if it's there) -->
|
||||
<FileUpdate
|
||||
<FileUpdate
|
||||
Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="(\d+)\.(\d+)\.(\d+)(.(\d+))?"
|
||||
ReplacementText="$(BUILD_RELEASE)"/>
|
||||
@@ -238,5 +278,5 @@
|
||||
<FileUpdate Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="CurrentComment { get { return "([a-zA-Z]+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_COMMENT)""/>
|
||||
</Target>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -16,7 +16,7 @@
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.20710.0]" />
|
||||
<dependency id="ServiceStack.Text" version="3.9.21" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="4.0.20710.0" />
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
@@ -21,4 +21,7 @@ if ($project) {
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
$umbracoFilesPath = Join-Path $rootPath "UmbracoFiles\*"
|
||||
Copy-Item $umbracoFilesPath $projectDestinationPath -recurse -force
|
||||
|
||||
# Open readme.txt file
|
||||
$DTE.ItemOperations.OpenFile($toolsPath + '\Readme.txt')
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
|
||||
@@ -15,33 +18,53 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// one per AppDomain, represents the global Umbraco application
|
||||
/// </remarks>
|
||||
public class ApplicationContext
|
||||
public class ApplicationContext : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
internal ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
|
||||
:this()
|
||||
: this(dbContext, serviceContext, true)
|
||||
{
|
||||
if (dbContext == null) throw new ArgumentNullException("dbContext");
|
||||
if (serviceContext == null) throw new ArgumentNullException("serviceContext");
|
||||
|
||||
_databaseContext = dbContext;
|
||||
_services = serviceContext;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <param name="enableCache"></param>
|
||||
internal ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, bool enableCache)
|
||||
: this(enableCache)
|
||||
{
|
||||
if (dbContext == null) throw new ArgumentNullException("dbContext");
|
||||
if (serviceContext == null) throw new ArgumentNullException("serviceContext");
|
||||
|
||||
_databaseContext = dbContext;
|
||||
_services = serviceContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empty constructor normally reserved for unit tests when a DatabaseContext or a ServiceContext is not
|
||||
/// necessarily required or needs to be set after construction.
|
||||
/// </summary>
|
||||
internal ApplicationContext()
|
||||
{
|
||||
//create a new application cache from the HttpRuntime.Cache
|
||||
ApplicationCache = HttpRuntime.Cache == null
|
||||
? new CacheHelper(new Cache())
|
||||
: new CacheHelper(HttpRuntime.Cache);
|
||||
internal ApplicationContext() : this(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor used to specify if we will enable application cache or not
|
||||
/// </summary>
|
||||
/// <param name="enableCache"></param>
|
||||
internal ApplicationContext(bool enableCache)
|
||||
{
|
||||
//create a new application cache from the HttpRuntime.Cache
|
||||
ApplicationCache = HttpRuntime.Cache == null
|
||||
? new CacheHelper(new System.Web.Caching.Cache(), enableCache)
|
||||
: new CacheHelper(HttpRuntime.Cache, enableCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Singleton accessor
|
||||
/// </summary>
|
||||
@@ -186,5 +209,54 @@ namespace Umbraco.Core
|
||||
}
|
||||
internal set { _services = value; }
|
||||
}
|
||||
|
||||
|
||||
private volatile bool _disposed;
|
||||
private readonly ReaderWriterLockSlim _disposalLocker = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// This will dispose and reset all resources used to run the application
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// IMPORTANT: Never dispose this object if you require the Umbraco application to run, disposing this object
|
||||
/// is generally used for unit testing and when your application is shutting down after you have booted Umbraco.
|
||||
/// </remarks>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
// Only operate if we haven't already disposed
|
||||
if (_disposed) return;
|
||||
|
||||
using (new WriteLock(_disposalLocker))
|
||||
{
|
||||
// Check again now we're inside the lock
|
||||
if (_disposed) return;
|
||||
|
||||
//clear the cache
|
||||
if (ApplicationCache != null)
|
||||
{
|
||||
ApplicationCache.ClearAllCache();
|
||||
}
|
||||
//reset all resolvers
|
||||
ResolverCollection.ResetAll();
|
||||
//reset resolution itself (though this should be taken care of by resetting any of the resolvers above)
|
||||
Resolution.Reset();
|
||||
|
||||
//reset the instance objects
|
||||
this.ApplicationCache = null;
|
||||
if (_databaseContext != null) //need to check the internal field here
|
||||
{
|
||||
if (DatabaseContext.Database != null)
|
||||
{
|
||||
DatabaseContext.Database.Dispose();
|
||||
}
|
||||
}
|
||||
this.DatabaseContext = null;
|
||||
this.Services = null;
|
||||
this._isReady = false; //set the internal field
|
||||
|
||||
// Indicate that the instance has been disposed.
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A plugin type that allows developers to execute code during the Umbraco bootup process
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Allows you to override the methods that you would like to execute code for: ApplicationInitialized, ApplicationStarting, ApplicationStarted.
|
||||
///
|
||||
/// By default none of these methods will execute if the Umbraco application is not configured or if the Umbraco database is not configured, however
|
||||
/// if you need these methods to execute even if either of these are not configured you can override the properties:
|
||||
/// ExecuteWhenApplicationNotConfigured and ExecuteWhenDatabaseNotConfigured
|
||||
/// </remarks>
|
||||
public abstract class ApplicationEventHandler : IApplicationEventHandler
|
||||
{
|
||||
public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationInitialized(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationStarting(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationStarted(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable method to execute when the ApplicationContext is created and other static objects that require initialization have been setup
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected virtual void ApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OVerridable method to execute when All resolvers have been initialized but resolution is not frozen so they can be modified in this method
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected virtual void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable method to execute when Bootup is completed, this allows you to perform any other bootup logic required for the application.
|
||||
/// Resolution is frozen so now they can be used to resolve instances.
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected virtual void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the methods should execute based on the configuration status of the application.
|
||||
/// </summary>
|
||||
/// <param name="applicationContext"></param>
|
||||
/// <returns></returns>
|
||||
private bool ShouldExecute(ApplicationContext applicationContext)
|
||||
{
|
||||
if (applicationContext.IsConfigured && applicationContext.DatabaseContext.IsDatabaseConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!applicationContext.IsConfigured && ExecuteWhenApplicationNotConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!applicationContext.DatabaseContext.IsDatabaseConfigured && ExecuteWhenDatabaseNotConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A flag to determine if the overridable methods for this class will execute even if the
|
||||
/// Umbraco application is not configured
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An Umbraco Application is not configured when it requires a new install or upgrade. When the latest version in the
|
||||
/// assembly does not match the version in the config.
|
||||
/// </remarks>
|
||||
protected virtual bool ExecuteWhenApplicationNotConfigured
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A flag to determine if the overridable methods for this class will execute even if the
|
||||
/// Umbraco database is not configured
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Umbraco database is not configured when we cannot connect to the database or when the database tables are not installed.
|
||||
/// </remarks>
|
||||
protected virtual bool ExecuteWhenDatabaseNotConfigured
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constants storing cache keys used in caching
|
||||
/// </summary>
|
||||
public static class CacheKeys
|
||||
{
|
||||
public const string ApplicationTreeCacheKey = "ApplicationTreeCache";
|
||||
public const string ApplicationsCacheKey = "ApplicationCache";
|
||||
|
||||
public const string UserTypeCacheKey = "UserTypeCache";
|
||||
|
||||
public const string ContentItemCacheKey = "contentItem";
|
||||
|
||||
public const string MediaCacheKey = "UL_GetMedia";
|
||||
|
||||
public const string MacroXsltCacheKey = "macroXslt_";
|
||||
public const string MacroCacheKey = "UmbracoMacroCache";
|
||||
public const string MacroHtmlCacheKey = "macroHtml_";
|
||||
public const string MacroControlCacheKey = "macroControl_";
|
||||
public const string MacroHtmlDateAddedCacheKey = "macroHtml_DateAdded_";
|
||||
public const string MacroControlDateAddedCacheKey = "macroControl_DateAdded_";
|
||||
|
||||
public const string MemberLibraryCacheKey = "UL_GetMember";
|
||||
public const string MemberBusinessLogicCacheKey = "MemberCacheItem_";
|
||||
|
||||
public const string TemplateFrontEndCacheKey = "template";
|
||||
public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache";
|
||||
|
||||
public const string UserContextCacheKey = "UmbracoUserContext";
|
||||
public const string UserContextTimeoutCacheKey = "UmbracoUserContextTimeout";
|
||||
public const string UserCacheKey = "UmbracoUser";
|
||||
|
||||
public const string ContentTypeCacheKey = "UmbracoContentType";
|
||||
|
||||
public const string ContentTypePropertiesCacheKey = "ContentType_PropertyTypes_Content:";
|
||||
|
||||
public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache";
|
||||
|
||||
public const string LanguageCacheKey = "UmbracoLanguageCache";
|
||||
|
||||
public const string DomainCacheKey = "UmbracoDomainList";
|
||||
|
||||
public const string StylesheetCacheKey = "UmbracoStylesheet";
|
||||
public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty";
|
||||
|
||||
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Web.Caching;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// An abstract class for implementing a cache helper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, ETC...
|
||||
/// </remarks>
|
||||
internal abstract class CacheProviderBase
|
||||
{
|
||||
public abstract void ClearAllCache();
|
||||
public abstract void ClearCacheItem(string key);
|
||||
public abstract void ClearCacheObjectTypes(string typeName);
|
||||
public abstract void ClearCacheObjectTypes<T>();
|
||||
public abstract void ClearCacheByKeySearch(string keyStartsWith);
|
||||
public abstract void ClearCacheByKeyExpression(string regexString);
|
||||
public abstract IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith);
|
||||
public abstract T GetCacheItem<T>(string cacheKey);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, Func<T> getCacheItem);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, Func<T> getCacheItem);
|
||||
public abstract void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Sync;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for cache refreshers to inherit from that ensures the correct events are raised
|
||||
/// when cache refreshing occurs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstanceType">The real cache refresher type, this is used for raising strongly typed events</typeparam>
|
||||
public abstract class CacheRefresherBase<TInstanceType> : ICacheRefresher
|
||||
where TInstanceType : ICacheRefresher
|
||||
{
|
||||
/// <summary>
|
||||
/// An event that is raised when cache is updated on an individual server
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event will fire on each server configured for an Umbraco project whenever a cache refresher
|
||||
/// is updated.
|
||||
/// </remarks>
|
||||
public static event TypedEventHandler<TInstanceType, CacheRefresherEventArgs> CacheUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the event
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="args"></param>
|
||||
protected static void OnCacheUpdated(TInstanceType sender, CacheRefresherEventArgs args)
|
||||
{
|
||||
if (CacheUpdated != null)
|
||||
{
|
||||
CacheUpdated(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the real instance of the object ('this') for use in strongly typed events
|
||||
/// </summary>
|
||||
protected abstract TInstanceType Instance { get; }
|
||||
|
||||
public abstract Guid UniqueIdentifier { get; }
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual void RefreshAll()
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(null, MessageType.RefreshAll));
|
||||
}
|
||||
|
||||
public virtual void Refresh(int id)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RefreshById));
|
||||
}
|
||||
|
||||
public virtual void Remove(int id)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RemoveById));
|
||||
}
|
||||
|
||||
public virtual void Refresh(Guid id)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RefreshById));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Event args for cache refresher updates
|
||||
/// </summary>
|
||||
public class CacheRefresherEventArgs : EventArgs
|
||||
{
|
||||
public CacheRefresherEventArgs(object msgObject, MessageType type)
|
||||
{
|
||||
MessageType = type;
|
||||
MessageObject = msgObject;
|
||||
}
|
||||
public object MessageObject { get; private set; }
|
||||
public MessageType MessageType { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A CacheProvider that wraps the logic of the HttpRuntime.Cache
|
||||
/// </summary>
|
||||
internal class HttpRuntimeCacheProvider : CacheProviderBase
|
||||
{
|
||||
private readonly System.Web.Caching.Cache _cache;
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
public HttpRuntimeCacheProvider(System.Web.Caching.Cache cache)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears everything in umbraco's runtime cache, which means that not only
|
||||
/// umbraco content is removed, but also other cache items from pages running in
|
||||
/// the same application / website. Use with care :-)
|
||||
/// </summary>
|
||||
public override void ClearAllCache()
|
||||
{
|
||||
var cacheEnumerator = _cache.GetEnumerator();
|
||||
while (cacheEnumerator.MoveNext())
|
||||
{
|
||||
_cache.Remove(cacheEnumerator.Key.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the item in umbraco's runtime cache with the given key
|
||||
/// </summary>
|
||||
/// <param name="key">Key</param>
|
||||
public override void ClearCacheItem(string key)
|
||||
{
|
||||
// NH 10 jan 2012
|
||||
// Patch by the always wonderful Stéphane Gay to avoid cache null refs
|
||||
lock (Locker)
|
||||
{
|
||||
if (_cache[key] == null) return;
|
||||
_cache.Remove(key); ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type name as the
|
||||
/// input parameter. (using [object].GetType())
|
||||
/// </summary>
|
||||
/// <param name="typeName">The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument"</param>
|
||||
public override void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
foreach (DictionaryEntry c in _cache)
|
||||
{
|
||||
if (_cache[c.Key.ToString()] != null
|
||||
&& _cache[c.Key.ToString()].GetType().ToString().InvariantEquals(typeName))
|
||||
{
|
||||
_cache.Remove(c.Key.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<CacheHelper>("Cache clearing error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type specified
|
||||
/// </summary>
|
||||
public override void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
foreach (DictionaryEntry c in _cache)
|
||||
{
|
||||
if (_cache[c.Key.ToString()] != null
|
||||
&& _cache[c.Key.ToString()].GetType() == typeof(T))
|
||||
{
|
||||
_cache.Remove(c.Key.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<CacheHelper>("Cache clearing error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that starts with the key passed.
|
||||
/// </summary>
|
||||
/// <param name="keyStartsWith">The start of the key</param>
|
||||
public override void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
foreach (DictionaryEntry c in _cache)
|
||||
{
|
||||
if (c.Key is string && ((string)c.Key).InvariantStartsWith(keyStartsWith))
|
||||
{
|
||||
ClearCacheItem((string)c.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that have a key that matches the regular expression
|
||||
/// </summary>
|
||||
/// <param name="regexString"></param>
|
||||
public override void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
foreach (DictionaryEntry c in _cache)
|
||||
{
|
||||
if (c.Key is string && Regex.IsMatch(((string)c.Key), regexString))
|
||||
{
|
||||
ClearCacheItem((string)c.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
return (from DictionaryEntry c in _cache
|
||||
where c.Key is string && ((string)c.Key).InvariantStartsWith(keyStartsWith)
|
||||
select c.Value.TryConvertTo<T>()
|
||||
into attempt
|
||||
where attempt.Success
|
||||
select attempt.Result).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cache item by key, does not update the cache if it isn't there.
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey)
|
||||
{
|
||||
var result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
return default(TT);
|
||||
}
|
||||
return result.TryConvertTo<TT>().Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with all of the default parameters
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey, Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, CacheItemPriority.Normal, null, null, null, getCacheItem, Locker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey,
|
||||
TimeSpan? timeout, Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, null, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemRemovedCallback refreshAction, TimeSpan? timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, CacheItemPriority.Normal, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, priority, refreshAction, null, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem, Locker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <param name="syncLock"></param>
|
||||
/// <returns></returns>
|
||||
private TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency, TimeSpan? timeout, Func<TT> getCacheItem, object syncLock)
|
||||
{
|
||||
var result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
lock (syncLock)
|
||||
{
|
||||
result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
result = getCacheItem();
|
||||
if (result != null)
|
||||
{
|
||||
//we use Insert instead of add if for some crazy reason there is now a cache with the cache key in there, it will just overwrite it.
|
||||
_cache.Insert(cacheKey, result, cacheDependency,
|
||||
timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value),
|
||||
TimeSpan.Zero, priority, refreshAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.TryConvertTo<TT>().Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public override void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
InsertCacheItem(cacheKey, priority, null, null, null, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public override void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
InsertCacheItem(cacheKey, priority, null, null, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public override void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
InsertCacheItem(cacheKey, priority, null, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public override void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
object result = getCacheItem();
|
||||
if (result != null)
|
||||
{
|
||||
//we use Insert instead of add if for some crazy reason there is now a cache with the cache key in there, it will just overwrite it.
|
||||
_cache.Insert(cacheKey, result, cacheDependency,
|
||||
timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value),
|
||||
TimeSpan.Zero, priority, refreshAction);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly type cache refresher that is able to refresh cache of real instances of objects as well as IDs
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <remarks>
|
||||
/// This is much better for performance when we're not running in a load balanced environment so we can refresh the cache
|
||||
/// against a already resolved object instead of looking the object back up by id.
|
||||
/// </remarks>
|
||||
interface ICacheRefresher<T> : ICacheRefresher
|
||||
{
|
||||
void Refresh(T instance);
|
||||
void Remove(T instance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache refresher that supports refreshing or removing cache based on a custom Json payload
|
||||
/// </summary>
|
||||
interface IJsonCacheRefresher : ICacheRefresher
|
||||
{
|
||||
/// <summary>
|
||||
/// Refreshes, clears, etc... any cache based on the information provided in the json
|
||||
/// </summary>
|
||||
/// <param name="jsonPayload"></param>
|
||||
void Refresh(string jsonPayload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Umbraco.Core.Sync;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for json cache refreshers that ensures the correct events are raised when
|
||||
/// cache refreshing occurs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstanceType">The real cache refresher type, this is used for raising strongly typed events</typeparam>
|
||||
public abstract class JsonCacheRefresherBase<TInstanceType> : CacheRefresherBase<TInstanceType>, IJsonCacheRefresher
|
||||
where TInstanceType : ICacheRefresher
|
||||
{
|
||||
|
||||
public virtual void Refresh(string jsonPayload)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Caching;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
internal class NullCacheProvider : CacheProviderBase
|
||||
{
|
||||
public override void ClearAllCache()
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheItem(string key)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, Func<T> getCacheItem)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Umbraco.Core.Sync;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for cache refreshers to inherit from that ensures the correct events are raised
|
||||
/// when cache refreshing occurs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstanceType">The real cache refresher type, this is used for raising strongly typed events</typeparam>
|
||||
/// <typeparam name="TEntityType">The entity type that this refresher can update cache for</typeparam>
|
||||
public abstract class TypedCacheRefresherBase<TInstanceType, TEntityType> : CacheRefresherBase<TInstanceType>, ICacheRefresher<TEntityType>
|
||||
where TInstanceType : ICacheRefresher
|
||||
{
|
||||
public virtual void Refresh(TEntityType instance)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(instance, MessageType.RefreshByInstance));
|
||||
}
|
||||
|
||||
public virtual void Remove(TEntityType instance)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(instance, MessageType.RemoveByInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
+311
-77
@@ -3,8 +3,10 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -16,29 +18,33 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// This class may be opened publicly at some point but needs a review of what is absoletely necessary.
|
||||
/// </remarks>
|
||||
public class CacheHelper
|
||||
public class CacheHelper //: CacheProviderBase
|
||||
{
|
||||
private readonly Cache _cache;
|
||||
private readonly bool _enableCache;
|
||||
private readonly HttpRuntimeCacheProvider _httpCache;
|
||||
private readonly NullCacheProvider _nullCache = new NullCacheProvider();
|
||||
|
||||
public CacheHelper(System.Web.Caching.Cache cache)
|
||||
: this(cache, true)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Clears everything in umbraco's runtime cache, which means that not only
|
||||
/// umbraco content is removed, but also other cache items from pages running in
|
||||
/// the same application / website. Use with care :-)
|
||||
/// </summary>
|
||||
internal CacheHelper(System.Web.Caching.Cache cache, bool enableCache)
|
||||
{
|
||||
_httpCache = new HttpRuntimeCacheProvider(cache);
|
||||
_enableCache = enableCache;
|
||||
}
|
||||
|
||||
public void ClearAllCache()
|
||||
{
|
||||
var cacheEnumerator = _cache.GetEnumerator();
|
||||
while (cacheEnumerator.MoveNext())
|
||||
{
|
||||
_cache.Remove(cacheEnumerator.Key.ToString());
|
||||
}
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.ClearAllCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearAllCache();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,12 +53,13 @@ namespace Umbraco.Core
|
||||
/// <param name="key">Key</param>
|
||||
public void ClearCacheItem(string key)
|
||||
{
|
||||
// NH 10 jan 2012
|
||||
// Patch by the always wonderful Stéphane Gay to avoid cache null refs
|
||||
lock (Locker)
|
||||
if (!_enableCache)
|
||||
{
|
||||
if (_cache[key] == null) return;
|
||||
_cache.Remove(key);;
|
||||
_nullCache.ClearCacheItem(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearCacheItem(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,54 +71,191 @@ namespace Umbraco.Core
|
||||
/// <param name="typeName">The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument"</param>
|
||||
public void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
try
|
||||
if (!_enableCache)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
foreach (var c in from DictionaryEntry c in _cache where _cache[c.Key.ToString()] != null && _cache[c.Key.ToString()].GetType().ToString() == typeName select c)
|
||||
{
|
||||
_cache.Remove(c.Key.ToString());
|
||||
}
|
||||
}
|
||||
_nullCache.ClearCacheObjectTypes(typeName);
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
LogHelper.Error<CacheHelper>("Cache clearing error", e);
|
||||
_httpCache.ClearCacheObjectTypes(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type specified
|
||||
/// </summary>
|
||||
public void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.ClearCacheObjectTypes<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearCacheObjectTypes<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that starts with the key passed.
|
||||
/// </summary>
|
||||
/// <param name="keyStartsWith">The start of the key</param>
|
||||
public void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.ClearCacheByKeySearch(keyStartsWith);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearCacheByKeySearch(keyStartsWith);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that have a key that matches the regular expression
|
||||
/// </summary>
|
||||
/// <param name="regexString"></param>
|
||||
public void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.ClearCacheByKeyExpression(regexString);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearCacheByKeyExpression(regexString);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
foreach (var c in from DictionaryEntry c in _cache where c.Key is string && ((string)c.Key).StartsWith(keyStartsWith) select c)
|
||||
{
|
||||
ClearCacheItem((string)c.Key);
|
||||
}
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cache item by key, does not update the cache if it isn't there.
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with all of the default parameters
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey, Func<TT> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
TimeSpan timeout, Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, null, timeout, getCacheItem);
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, CacheItemPriority.Normal, refreshAction, timeout, getCacheItem);
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, priority, refreshAction, null, timeout, getCacheItem);
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, priority, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, priority, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
@@ -119,46 +263,136 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem, Locker);
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used only for legacy purposes as I did not want to change all of the locking to one lock found on this object,
|
||||
/// however, the reason this is used for legacy purposes is because I see zero reason to use different sync locks, just the one
|
||||
/// lock (Locker) on this class should be sufficient.
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <param name="syncLock"></param>
|
||||
/// <returns></returns>
|
||||
internal TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency, TimeSpan timeout, Func<TT> getCacheItem, object syncLock)
|
||||
{
|
||||
var result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
lock (syncLock)
|
||||
{
|
||||
result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
result = getCacheItem();
|
||||
if (result != null)
|
||||
{
|
||||
//we use Insert instead of add if for some crazy reason there is now a cache with the cache key in there, it will just overwrite it.
|
||||
_cache.Insert(cacheKey, result, cacheDependency, DateTime.Now.Add(timeout), TimeSpan.Zero, priority, refreshAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (TT)result;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, priority, null, cacheDependency, null, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, priority, null, cacheDependency, null, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.InsertCacheItem<T>(cacheKey, priority, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.InsertCacheItem<T>(cacheKey, priority, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.InsertCacheItem<T>(cacheKey, priority, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.InsertCacheItem<T>(cacheKey, priority, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.InsertCacheItem<T>(cacheKey, priority, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.InsertCacheItem<T>(cacheKey, priority, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.InsertCacheItem<T>(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.InsertCacheItem<T>(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureIdsAreTracked();
|
||||
EnsureIsInitialized();
|
||||
return Values;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.CodeAnnotations
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute to add a Friendly Name string with an UmbracoObjectType enum value
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
|
||||
internal class FriendlyNameAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// friendly name value
|
||||
/// </summary>
|
||||
private readonly string _friendlyName;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the FriendlyNameAttribute class
|
||||
/// Sets the friendly name value
|
||||
/// </summary>
|
||||
/// <param name="friendlyName">attribute value</param>
|
||||
public FriendlyNameAttribute(string friendlyName)
|
||||
{
|
||||
this._friendlyName = friendlyName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the friendly name
|
||||
/// </summary>
|
||||
/// <returns>string of friendly name</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return this._friendlyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.CodeAnnotations
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute to associate a GUID string and Type with an UmbracoObjectType Enum value
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||
internal class UmbracoObjectTypeAttribute : Attribute
|
||||
{
|
||||
public UmbracoObjectTypeAttribute(string objectId)
|
||||
{
|
||||
ObjectId = new Guid(objectId);
|
||||
}
|
||||
|
||||
public UmbracoObjectTypeAttribute(string objectId, Type modelType)
|
||||
{
|
||||
ObjectId = new Guid(objectId);
|
||||
ModelType = modelType;
|
||||
}
|
||||
|
||||
public Guid ObjectId { get; private set; }
|
||||
|
||||
public Type ModelType { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A thread-safe representation of a <see cref="HashSet{T}"/>.
|
||||
/// Enumerating this collection is thread-safe and will only operate on a clone that is generated before returning the enumerator.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[Serializable]
|
||||
public class ConcurrentHashSet<T> : ICollection<T>
|
||||
{
|
||||
private readonly HashSet<T> _innerSet = new HashSet<T>();
|
||||
private readonly ReaderWriterLockSlim _instanceLocker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>1</filterpriority>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetThreadSafeClone().GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through a collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </returns>
|
||||
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
return _innerSet.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public int Count
|
||||
{
|
||||
get { return GetThreadSafeClone().Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
|
||||
/// </returns>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public void Add(T item)
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
_innerSet.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to add an item to the collection
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryAdd(T item)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
if (clone.Contains(item)) return false;
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
//double check
|
||||
if (_innerSet.Contains(item)) return false;
|
||||
_innerSet.Add(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception>
|
||||
public void Clear()
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
_innerSet.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return GetThreadSafeClone().Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/> to an <see cref="T:System.Array"/>, starting at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/>. The array must have zero-based indexing.</param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is a null reference (Nothing in Visual Basic).</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero.</exception><exception cref="T:System.ArgumentException"><paramref name="index"/> is equal to or greater than the length of the <paramref name="array"/> -or- The number of elements in the source <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>.</exception>
|
||||
public void CopyTo(T[] array, int index)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
clone.CopyTo(array, index);
|
||||
}
|
||||
|
||||
private HashSet<T> GetThreadSafeClone()
|
||||
{
|
||||
HashSet<T> clone = null;
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
clone = new HashSet<T>(_innerSet, _innerSet.Comparer);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing. </param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins. </param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null. </exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero. </exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or- The number of elements in the source <see cref="T:System.Collections.ICollection"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>. </exception><exception cref="T:System.ArgumentException">The type of the source <see cref="T:System.Collections.ICollection"/> cannot be cast automatically to the type of the destination <paramref name="array"/>. </exception><filterpriority>2</filterpriority>
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
Array.Copy(clone.ToArray(), 0, array, index, clone.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// A case-insensitive configuration converter for enumerations.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the enumeration.</typeparam>
|
||||
internal class CaseInsensitiveEnumConfigConverter<T> : ConfigurationConverterBase
|
||||
where T : struct
|
||||
{
|
||||
public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
|
||||
//return Enum.Parse(typeof(T), (string)data, true);
|
||||
|
||||
T value;
|
||||
if (Enum.TryParse((string)data, true, out value))
|
||||
return value;
|
||||
|
||||
throw new Exception(string.Format("\"{0}\" is not valid {1} value. Valid values are: {2}.",
|
||||
data, typeof(T).Name,
|
||||
string.Join(", ", Enum.GetValues(typeof(T)).Cast<T>())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the configuration key for a section or a group.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal sealed class ConfigurationKeyAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConfigurationKeyAttribute"/> class with a configuration key.
|
||||
/// </summary>
|
||||
/// <param name="configurationKey">The configurationkey.</param>
|
||||
public ConfigurationKeyAttribute(string configurationKey)
|
||||
{
|
||||
ConfigurationKey = configurationKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the configuration key.
|
||||
/// </summary>
|
||||
public string ConfigurationKey { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -42,15 +42,24 @@ namespace Umbraco.Core.Configuration
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// used for unit tests
|
||||
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
|
||||
/// </summary>
|
||||
internal static void ResetCache()
|
||||
private static void ResetInternal()
|
||||
{
|
||||
_reservedUrlsCache = null;
|
||||
_reservedPaths = null;
|
||||
_reservedUrls = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets settings that were set programmatically, to their initial values.
|
||||
/// </summary>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal static void Reset()
|
||||
{
|
||||
ResetInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reserved urls from web.config.
|
||||
/// </summary>
|
||||
@@ -575,6 +584,16 @@ namespace Umbraco.Core.Configuration
|
||||
return context.Request.Path.ToLower().IndexOf(SystemDirectories.Umbraco.ToLower() + "/liveediting.aspx") > -1;
|
||||
}
|
||||
|
||||
public static bool RequestIsInUmbracoApplication(HttpContextBase context)
|
||||
{
|
||||
return context.Request.Path.ToLower().IndexOf(IOHelper.ResolveUrl(SystemDirectories.Umbraco).ToLower()) > -1;
|
||||
}
|
||||
|
||||
public static bool RequestIsLiveEditRedirector(HttpContextBase context)
|
||||
{
|
||||
return context.Request.Path.ToLower().IndexOf(SystemDirectories.Umbraco.ToLower() + "/liveediting.aspx") > -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether umbraco should force a secure (https) connection to the backoffice.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
// note - still must work on how to support read-only and ResetSection for collections
|
||||
// note - still must work on how to spread config over files (aka DeepConfig in v5)
|
||||
|
||||
/// <summary>
|
||||
/// Represents an Umbraco section within the configuration file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The requirement for these sections is to be read-only.</para>
|
||||
/// <para>However for unit tests purposes it is internally possible to override some values, and
|
||||
/// then calling <c>>ResetSection</c> should cancel these changes and bring the section back to
|
||||
/// what it was originally.</para>
|
||||
/// <para>The <c>UmbracoSettings.For{T}</c> method will return a section, either one that
|
||||
/// is in the configuration file, or a section that was created with default values.</para>
|
||||
/// </remarks>
|
||||
internal abstract class UmbracoConfigurationSection : ConfigurationSection
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the section actually is in the configuration file.
|
||||
/// </summary>
|
||||
protected bool IsPresent { get { return ElementInformation.IsPresent; } }
|
||||
|
||||
/// <summary>
|
||||
/// Resets settings that were set programmatically, to their initial values.
|
||||
/// </summary>
|
||||
/// <remarks>>To be used in unit tests.</remarks>
|
||||
internal protected virtual void ResetSection()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,11 @@ using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using System.Xml;
|
||||
using System.Configuration;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
@@ -20,6 +22,8 @@ namespace Umbraco.Core.Configuration
|
||||
|
||||
//TODO: Re-enable logging !!!!
|
||||
|
||||
//TODO: We need to convert this to a real section, it's currently using HttpRuntime.Cache to detect cahnges, this is real poor, especially in a console app
|
||||
|
||||
/// <summary>
|
||||
/// The UmbracoSettings Class contains general settings information for the entire Umbraco instance based on information from the /config/umbracoSettings.config file
|
||||
/// </summary>
|
||||
@@ -52,15 +56,14 @@ namespace Umbraco.Core.Configuration
|
||||
/// <summary>
|
||||
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
|
||||
/// </summary>
|
||||
internal static void ResetSetters()
|
||||
private static void ResetInternal()
|
||||
{
|
||||
_addTrailingSlash = null;
|
||||
_forceSafeAliases = null;
|
||||
_useLegacySchema = null;
|
||||
_useDomainPrefixes = null;
|
||||
_umbracoLibraryCacheDuration = null;
|
||||
_trySkipIisCustomErrors = null;
|
||||
SettingsFilePath = null;
|
||||
SettingsFilePath = null;
|
||||
}
|
||||
|
||||
internal const string TempFriendlyXmlChildContainerNodename = ""; // "children";
|
||||
@@ -503,7 +506,7 @@ namespace Umbraco.Core.Configuration
|
||||
private static IEnumerable<RazorDataTypeModelStaticMappingItem> _razorDataTypeModelStaticMapping;
|
||||
private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
|
||||
|
||||
public static IEnumerable<RazorDataTypeModelStaticMappingItem> RazorDataTypeModelStaticMapping
|
||||
internal static IEnumerable<RazorDataTypeModelStaticMappingItem> RazorDataTypeModelStaticMapping
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -652,23 +655,22 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
private static bool? _trySkipIisCustomErrors;
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to try to skip IIS custom errors.
|
||||
/// </summary>
|
||||
[UmbracoWillObsolete("Use UmbracoSettings.For<WebRouting>.TrySkipIisCustomErrors instead.")]
|
||||
internal static bool TrySkipIisCustomErrors
|
||||
{
|
||||
get { return GetKeyValue("/settings/web.routing/@trySkipIisCustomErrors", false); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating where to try to skip IIS custom errors.
|
||||
/// Gets a value indicating whether internal redirect preserves the template.
|
||||
/// </summary>
|
||||
public static bool TrySkipIisCustomErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
// default: false
|
||||
return _trySkipIisCustomErrors ?? GetKeyValue("/settings/web.routing/@trySkipIisCustomErrors", false);
|
||||
}
|
||||
internal set
|
||||
{
|
||||
// used for unit testing
|
||||
_trySkipIisCustomErrors = value;
|
||||
}
|
||||
[UmbracoWillObsolete("Use UmbracoSettings.For<WebRouting>.InternalRedirectPerservesTemplate instead.")]
|
||||
internal static bool InternalRedirectPreservesTemplate
|
||||
{
|
||||
get { return GetKeyValue("/settings/web.routing/@internalRedirectPreservesTemplate", false); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1214,6 +1216,12 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
return _defaultRenderingEngine.Value;
|
||||
}
|
||||
//internal set
|
||||
//{
|
||||
// _defaultRenderingEngine = value;
|
||||
// var node = UmbracoSettingsXmlDoc.DocumentElement.SelectSingleNode("/settings/templates/defaultRenderingEngine");
|
||||
// node.InnerText = value.ToString();
|
||||
//}
|
||||
}
|
||||
|
||||
private static MacroErrorBehaviour? _macroErrorBehaviour;
|
||||
@@ -1469,6 +1477,80 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Extensible settings
|
||||
|
||||
/// <summary>
|
||||
/// Resets settings that were set programmatically, to their initial values.
|
||||
/// </summary>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal static void Reset()
|
||||
{
|
||||
ResetInternal();
|
||||
|
||||
using (new WriteLock(SectionsLock))
|
||||
{
|
||||
foreach (var section in Sections.Values)
|
||||
section.ResetSection();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ReaderWriterLockSlim SectionsLock = new ReaderWriterLockSlim();
|
||||
private static readonly Dictionary<Type, UmbracoConfigurationSection> Sections = new Dictionary<Type, UmbracoConfigurationSection>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified UmbracoConfigurationSection.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the UmbracoConfigurationSectiont.</typeparam>
|
||||
/// <returns>The UmbracoConfigurationSection of the specified type.</returns>
|
||||
internal static T For<T>()
|
||||
where T : UmbracoConfigurationSection, new()
|
||||
{
|
||||
var sectionType = typeof (T);
|
||||
using (new WriteLock(SectionsLock))
|
||||
{
|
||||
if (Sections.ContainsKey(sectionType)) return Sections[sectionType] as T;
|
||||
|
||||
var attr = sectionType.GetCustomAttribute<ConfigurationKeyAttribute>(false);
|
||||
if (attr == null)
|
||||
throw new InvalidOperationException(string.Format("Type \"{0}\" is missing attribute ConfigurationKeyAttribute.", sectionType.FullName));
|
||||
|
||||
var sectionKey = attr.ConfigurationKey;
|
||||
if (string.IsNullOrWhiteSpace(sectionKey))
|
||||
throw new InvalidOperationException(string.Format("Type \"{0}\" ConfigurationKeyAttribute value is null or empty.", sectionType.FullName));
|
||||
|
||||
var section = GetSection(sectionType, sectionKey);
|
||||
|
||||
Sections[sectionType] = section;
|
||||
return section as T;
|
||||
}
|
||||
}
|
||||
|
||||
private static UmbracoConfigurationSection GetSection(Type sectionType, string key)
|
||||
{
|
||||
if (!sectionType.Inherits<UmbracoConfigurationSection>())
|
||||
throw new ArgumentException(string.Format(
|
||||
"Type \"{0}\" does not inherit from UmbracoConfigurationSection.", sectionType.FullName), "sectionType");
|
||||
|
||||
var section = ConfigurationManager.GetSection(key);
|
||||
|
||||
if (section != null && section.GetType() != sectionType)
|
||||
throw new InvalidCastException(string.Format("Section at key \"{0}\" is of type \"{1}\" and not \"{2}\".",
|
||||
key, section.GetType().FullName, sectionType.FullName));
|
||||
|
||||
if (section != null) return section as UmbracoConfigurationSection;
|
||||
|
||||
section = Activator.CreateInstance(sectionType) as UmbracoConfigurationSection;
|
||||
|
||||
if (section == null)
|
||||
throw new NullReferenceException(string.Format(
|
||||
"Activator failed to create an instance of type \"{0}\" for key\"{1}\" and returned null.",
|
||||
sectionType.FullName, key));
|
||||
|
||||
return section as UmbracoConfigurationSection;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("6.0.3");
|
||||
private static readonly Version Version = new Version("6.1.0");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
public static string CurrentComment { get { return "beta"; } }
|
||||
|
||||
// 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
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the alias identifiers for Umbraco's core application sections.
|
||||
/// </summary>
|
||||
public static class Applications
|
||||
{
|
||||
/// <summary>
|
||||
/// Application alias for the content section.
|
||||
/// </summary>
|
||||
public const string Content = "content";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the developer section.
|
||||
/// </summary>
|
||||
public const string Developer = "developer";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the media section.
|
||||
/// </summary>
|
||||
public const string Media = "media";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the members section.
|
||||
/// </summary>
|
||||
public const string Members = "member";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the settings section.
|
||||
/// </summary>
|
||||
public const string Settings = "settings";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the translation section.
|
||||
/// </summary>
|
||||
public const string Translation = "translation";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the users section.
|
||||
/// </summary>
|
||||
public const string Users = "users";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for property-type alias conventions that are used within the Umbraco core.
|
||||
/// </summary>
|
||||
public static class Conventions
|
||||
{
|
||||
/// <summary>
|
||||
/// Constants for Umbraco Content property aliases.
|
||||
/// </summary>
|
||||
public static class Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Property alias for the Content's Url (internal) redirect.
|
||||
/// </summary>
|
||||
public const string InternalRedirectId = "umbracoInternalRedirectId";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Content's navigational hide, (not actually used in core code).
|
||||
/// </summary>
|
||||
public const string NaviHide = "umbracoNaviHide";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Content's Url redirect.
|
||||
/// </summary>
|
||||
public const string Redirect = "umbracoRedirect";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Content's Url alias.
|
||||
/// </summary>
|
||||
public const string UrlAlias = "umbracoUrlAlias";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Content's Url name.
|
||||
/// </summary>
|
||||
public const string UrlName = "umbracoUrlName";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constants for Umbraco Media property aliases.
|
||||
/// </summary>
|
||||
public static class Media
|
||||
{
|
||||
/// <summary>
|
||||
/// Property alias for the Media's file name.
|
||||
/// </summary>
|
||||
public const string File = "umbracoFile";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Media's width.
|
||||
/// </summary>
|
||||
public const string Width = "umbracoWidth";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Media's height.
|
||||
/// </summary>
|
||||
public const string Height = "umbracoHeight";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Media's file size (in bytes).
|
||||
/// </summary>
|
||||
public const string Bytes = "umbracoBytes";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Media's file extension.
|
||||
/// </summary>
|
||||
public const string Extension = "umbracoExtension";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the alias identifiers for Umbraco media types.
|
||||
/// </summary>
|
||||
public static class MediaTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// MediaType alias for a file.
|
||||
/// </summary>
|
||||
public const string File = "File";
|
||||
|
||||
/// <summary>
|
||||
/// MediaType alias for a folder.
|
||||
/// </summary>
|
||||
public const string Folder = "Folder";
|
||||
|
||||
/// <summary>
|
||||
/// MediaType alias for an image.
|
||||
/// </summary>
|
||||
public const string Image = "Image";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constants for Umbraco URLs/Querystrings.
|
||||
/// </summary>
|
||||
public static class Url
|
||||
{
|
||||
/// <summary>
|
||||
/// Querystring parameter name used for Umbraco's alternative template functionality.
|
||||
/// </summary>
|
||||
public const string AltTemplate = "altTemplate";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco object types as constants for easy centralized access/management.
|
||||
/// </summary>
|
||||
public static class ObjectTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Guid for a Content Item object.
|
||||
/// </summary>
|
||||
public const string ContentItem = "10E2B09F-C28B-476D-B77A-AA686435E44A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Content Item Type object.
|
||||
/// </summary>
|
||||
public const string ContentItemType = "7A333C54-6F43-40A4-86A2-18688DC7E532";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Content Recycle Bin.
|
||||
/// </summary>
|
||||
public const string ContentRecycleBin = "01BB7FF2-24DC-4C0C-95A2-C24EF72BBAC8";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a DataType object.
|
||||
/// </summary>
|
||||
public const string DataType = "30A2A501-1978-4DDB-A57B-F7EFED43BA3C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document object.
|
||||
/// </summary>
|
||||
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document Type object.
|
||||
/// </summary>
|
||||
public const string DocumentType = "A2CB7800-F571-4787-9638-BC48539A0EFB";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Media object.
|
||||
/// </summary>
|
||||
public const string Media = "B796F64C-1F99-4FFB-B886-4BF4BC011A9C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Media Recycle Bin.
|
||||
/// </summary>
|
||||
public const string MediaRecycleBin = "CF3D8E34-1C1C-41e9-AE56-878B57B32113";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Media Type object.
|
||||
/// </summary>
|
||||
public const string MediaType = "4EA4382B-2F5A-4C2B-9587-AE9B3CF3602E";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member object.
|
||||
/// </summary>
|
||||
public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member Group object.
|
||||
/// </summary>
|
||||
public const string MemberGroup = "366E63B9-880F-4E13-A61C-98069B029728";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member Type object.
|
||||
/// </summary>
|
||||
public const string MemberType = "9B5416FB-E72F-45A9-A07B-5A9A2709CE43";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Stylesheet object.
|
||||
/// </summary>
|
||||
public const string Stylesheet = "9F68DA4F-A3A8-44C2-8226-DCBD125E4840";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the System Root.
|
||||
/// </summary>
|
||||
public const string SystemRoot = "EA7D8624-4CFE-4578-A871-24AA946BF34D";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Template object.
|
||||
/// </summary>
|
||||
public const string Template = "6FBDE604-4178-42CE-A10B-8A2600A2F07D";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco Property Editors as constants for easy centralized access/management.
|
||||
/// </summary>
|
||||
public static class PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Guid for the Checkbox list datatype.
|
||||
/// </summary>
|
||||
public const string CheckBoxList = "B4471851-82B6-4C75-AFA4-39FA9C6A75E9";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Color Picker datatype.
|
||||
/// </summary>
|
||||
public const string ColorPicker = "F8D60F68-EC59-4974-B43B-C46EB5677985";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Content Picker datatype.
|
||||
/// </summary>
|
||||
public const string ContentPicker = "158AA029-24ED-4948-939E-C3DA209E5FBA";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Date datatype.
|
||||
/// </summary>
|
||||
public const string Date = "23E93522-3200-44E2-9F29-E61A6FCBB79A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Date/Time datatype.
|
||||
/// </summary>
|
||||
public const string DateTime = "B6FB1622-AFA5-4BBF-A3CC-D9672A442222";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dictionary Picker datatype.
|
||||
/// </summary>
|
||||
public const string DictionaryPicker = "17B70066-F764-407D-AB05-3717F1E1C513";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list datatype.
|
||||
/// </summary>
|
||||
public const string DropDownList = "A74EA9C9-8E18-4D2A-8CF6-73C6206C5DA6";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list multiple datatype.
|
||||
/// </summary>
|
||||
public const string DropDownListMultiple = "928639ED-9C73-4028-920C-1E55DBB68783";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list multiple, publish keys datatype.
|
||||
/// </summary>
|
||||
public const string DropdownlistMultiplePublishKeys = "928639AA-9C73-4028-920C-1E55DBB68783";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list, publishing keys datatype.
|
||||
/// </summary>
|
||||
public const string DropdownlistPublishingKeys = "A74EA9E1-8E18-4D2A-8CF6-73C6206C5DA6";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Folder browser datatype.
|
||||
/// </summary>
|
||||
public const string FolderBrowser = "CCCD4AE9-F399-4ED2-8038-2E88D19E810C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Image Cropper datatype.
|
||||
/// </summary>
|
||||
public const string ImageCropper = "7A2D436C-34C2-410F-898F-4A23B3D79F54";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Integer datatype.
|
||||
/// </summary>
|
||||
public const string Integer = "1413AFCB-D19A-4173-8E9A-68288D2A73B8";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Macro Container datatype.
|
||||
/// </summary>
|
||||
public const string MacroContainer = "474FCFF8-9D2D-11DE-ABC6-AD7A56D89593";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Media Picker datatype.
|
||||
/// </summary>
|
||||
public const string MediaPicker = "EAD69342-F06D-4253-83AC-28000225583B";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Member Picker datatype.
|
||||
/// </summary>
|
||||
public const string MemberPicker = "39F533E4-0551-4505-A64B-E0425C5CE775";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Multi-Node Tree Picker datatype
|
||||
/// </summary>
|
||||
public const string MultiNodeTreePicker = "7E062C13-7C41-4AD9-B389-41D88AEEF87C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Multiple Textstring datatype.
|
||||
/// </summary>
|
||||
public const string MultipleTextstring = "5359AD0B-06CC-4182-92BD-0A9117448D3F";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the No edit datatype.
|
||||
/// </summary>
|
||||
public const string NoEdit = "6C738306-4C17-4D88-B9BD-6546F3771597";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Picker Relations datatype.
|
||||
/// </summary>
|
||||
public const string PickerRelations = "83396FF2-2E39-4A90-9066-17F5F3989374";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Radiobutton list datatype.
|
||||
/// </summary>
|
||||
public const string RadioButtonList = "A52C7C1C-C330-476E-8605-D63D3B84B6A6";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Related Links datatype.
|
||||
/// </summary>
|
||||
public const string RelatedLinks = "71B8AD1A-8DC2-425C-B6B8-FAA158075E63";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Slider datatype.
|
||||
/// </summary>
|
||||
public const string Slider = "29E790E6-26B3-438A-B21F-908663A0B19E";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Tags datatype.
|
||||
/// </summary>
|
||||
public const string Tags = "4023E540-92F5-11DD-AD8B-0800200C9A66";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Textbox datatype.
|
||||
/// </summary>
|
||||
public const string Textbox = "EC15C1E5-9D90-422A-AA52-4F7622C63BEA";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Textbox multiple datatype.
|
||||
/// </summary>
|
||||
public const string TextboxMultiple = "67DB8357-EF57-493E-91AC-936D305E0F2A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the TinyMCE v3 wysiwyg datatype.
|
||||
/// </summary>
|
||||
public const string TinyMCEv3 = "5E9B75AE-FACE-41C8-B47E-5F4B0FD82F83";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the TinyMCE wysiwyg (deprecated, upgrade to tinymce v3!) datatype.
|
||||
/// </summary>
|
||||
public const string TinyMCE = "83722133-F80C-4273-BDB6-1BEFAA04A612";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the True/False (Ja/Nej) datatype.
|
||||
/// </summary>
|
||||
public const string TrueFalse = "38B352C1-E9F8-4FD8-9324-9A2EAB06D97A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Ultimate Picker datatype.
|
||||
/// </summary>
|
||||
public const string UltimatePicker = "CDBF0B5D-5CB2-445F-BC12-FCAAEC07CF2C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the UltraSimpleEditor datatype.
|
||||
/// </summary>
|
||||
public const string UltraSimpleEditor = "60B7DABF-99CD-41EB-B8E9-4D2E669BBDE9";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Umbraco Usercontrol Wrapper datatype.
|
||||
/// </summary>
|
||||
public const string UmbracoUserControlWrapper = "D15E1281-E456-4B24-AA86-1DDA3E4299D5";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Upload field datatype.
|
||||
/// </summary>
|
||||
public const string UploadField = "5032A6E6-69E3-491D-BB28-CD31CD11086C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the XPath CheckBoxList datatype.
|
||||
/// </summary>
|
||||
public const string XPathCheckBoxList = "34451D92-D270-49BA-8C7F-EE55BFEEE1CB";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the XPath DropDownList datatype.
|
||||
/// </summary>
|
||||
public const string XPathDropDownList = "173A96AE-00ED-4A7C-9F76-4B53D4A0A1B9";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco system nodes.
|
||||
/// </summary>
|
||||
public static class System
|
||||
{
|
||||
/// <summary>
|
||||
/// The integer identifier for global system root node.
|
||||
/// </summary>
|
||||
public const int Root = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The integer identifier for content's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinContent = -20;
|
||||
|
||||
/// <summary>
|
||||
/// The integer identifier for media's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinMedia = -21;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Constants all the identifiers within the Umbraco core.
|
||||
/// </summary>
|
||||
public static partial class Constants
|
||||
{
|
||||
// generic constants can go here
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,10 @@ using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Macros;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Core.Strings;
|
||||
using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -106,6 +109,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
//add custom types here that are internal
|
||||
ApplicationEventsResolver.Current.AddType<PublishedContentHelper>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -175,12 +180,25 @@ namespace Umbraco.Core
|
||||
{
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create the resolvers
|
||||
/// </summary>
|
||||
protected virtual void InitializeResolvers()
|
||||
{
|
||||
//by default we'll use the standard configuration based sync
|
||||
ServerRegistrarResolver.Current = new ServerRegistrarResolver(
|
||||
new ConfigServerRegistrar());
|
||||
|
||||
//by default (outside of the web) we'll use the default server messenger without
|
||||
//supplying a username/password, this will automatically disable distributed calls
|
||||
// .. we'll override this in the WebBootManager
|
||||
ServerMessengerResolver.Current = new ServerMessengerResolver(
|
||||
new DefaultServerMessenger());
|
||||
|
||||
MappingResolver.Current = new MappingResolver(
|
||||
() => PluginManager.Current.ResolveAssignedMapperTypes());
|
||||
|
||||
RepositoryResolver.Current = new RepositoryResolver(
|
||||
new RepositoryFactory());
|
||||
|
||||
@@ -208,27 +226,11 @@ namespace Umbraco.Core
|
||||
MacroPropertyTypeResolver.Current = new MacroPropertyTypeResolver(
|
||||
PluginManager.Current.ResolveMacroPropertyTypes());
|
||||
|
||||
//TODO: Y U NO WORK?
|
||||
//MigrationResolver.Current = new MigrationResolver(
|
||||
// PluginManager.Current.ResolveMigrationTypes());
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(
|
||||
() => PluginManager.Current.ResolveMigrationTypes());
|
||||
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(new List<Type>
|
||||
{
|
||||
typeof (MigrationsVersionFourNineZero.RemoveUmbracoAppConstraints),
|
||||
typeof (DeleteAppTables),
|
||||
typeof (EnsureAppsTreesUpdated),
|
||||
typeof (MoveMasterContentTypeData),
|
||||
typeof (NewCmsContentType2ContentTypeTable),
|
||||
typeof (RemoveMasterContentTypeColumn),
|
||||
typeof (RenameCmsTabTable),
|
||||
typeof (RenameTabIdColumn),
|
||||
typeof (UpdateCmsContentTypeAllowedContentTypeTable),
|
||||
typeof (UpdateCmsContentTypeTable),
|
||||
typeof (UpdateCmsContentVersionTable),
|
||||
typeof (UpdateCmsPropertyTypeGroupTable),
|
||||
typeof (UpdatePropertyTypesAndGroups)
|
||||
});
|
||||
|
||||
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
PluginManager.Current.ResolvePropertyEditorValueConverters());
|
||||
@@ -236,6 +238,18 @@ namespace Umbraco.Core
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<DatePickerPropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<TinyMcePropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<YesNoPropertyEditorValueConverter>();
|
||||
}
|
||||
|
||||
// this is how we'd switch over to DefaultShortStringHelper _and_ still use
|
||||
// UmbracoSettings UrlReplaceCharacters...
|
||||
//ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
// new DefaultShortStringHelper().WithConfig(DefaultShortStringHelper.ApplyUrlReplaceCharacters));
|
||||
|
||||
// use the Legacy one for now
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
new LegacyShortStringHelper());
|
||||
|
||||
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
|
||||
typeof (DefaultUrlSegmentProvider));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureIdsAreTracked();
|
||||
EnsureIsInitialized();
|
||||
return Values;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Custom IApplicationStartupHandler that auto subscribes to the applications events
|
||||
/// </summary>
|
||||
public interface IApplicationEventHandler : IApplicationStartupHandler
|
||||
|
||||
@@ -137,25 +137,42 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates if the current filepath matches a directory where the user is allowed to edit a file
|
||||
/// Verifies that the current filepath matches a directory where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">filepath </param>
|
||||
/// <param name="validDir"></param>
|
||||
/// <returns>true if valid, throws a FileSecurityException if not</returns>
|
||||
internal static bool ValidateEditPath(string filePath, string validDir)
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validDir">The valid directory.</param>
|
||||
/// <returns>A value indicating whether the filepath is valid.</returns>
|
||||
internal static bool VerifyEditPath(string filePath, string validDir)
|
||||
{
|
||||
if (!filePath.StartsWith(MapPath(SystemDirectories.Root)))
|
||||
filePath = MapPath(filePath);
|
||||
if (!validDir.StartsWith(MapPath(SystemDirectories.Root)))
|
||||
validDir = MapPath(validDir);
|
||||
|
||||
if (!filePath.StartsWith(validDir))
|
||||
throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
return filePath.StartsWith(validDir);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the current filepath matches a directory where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validDir">The valid directory.</param>
|
||||
/// <returns>True, if the filepath is valid, else an exception is thrown.</returns>
|
||||
/// <exception cref="FileSecurityException">The filepath is invalid.</exception>
|
||||
internal static bool ValidateEditPath(string filePath, string validDir)
|
||||
{
|
||||
if (!VerifyEditPath(filePath, validDir))
|
||||
throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool ValidateEditPath(string filePath, IEnumerable<string> validDirs)
|
||||
/// <summary>
|
||||
/// Verifies that the current filepath matches one of several directories where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validDirs">The valid directories.</param>
|
||||
/// <returns>A value indicating whether the filepath is valid.</returns>
|
||||
internal static bool VerifyEditPath(string filePath, IEnumerable<string> validDirs)
|
||||
{
|
||||
foreach (var dir in validDirs)
|
||||
{
|
||||
@@ -169,19 +186,49 @@ namespace Umbraco.Core.IO
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool ValidateFileExtension(string filePath, List<string> validFileExtensions)
|
||||
/// <summary>
|
||||
/// Validates that the current filepath matches one of several directories where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validDirs">The valid directories.</param>
|
||||
/// <returns>True, if the filepath is valid, else an exception is thrown.</returns>
|
||||
/// <exception cref="FileSecurityException">The filepath is invalid.</exception>
|
||||
internal static bool ValidateEditPath(string filePath, IEnumerable<string> validDirs)
|
||||
{
|
||||
if (!VerifyEditPath(filePath, validDirs))
|
||||
throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the current filepath has one of several authorized extensions.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validFileExtensions">The valid extensions.</param>
|
||||
/// <returns>A value indicating whether the filepath is valid.</returns>
|
||||
internal static bool VerifyFileExtension(string filePath, List<string> validFileExtensions)
|
||||
{
|
||||
if (!filePath.StartsWith(MapPath(SystemDirectories.Root)))
|
||||
filePath = MapPath(filePath);
|
||||
var f = new FileInfo(filePath);
|
||||
|
||||
return validFileExtensions.Contains(f.Extension.Substring(1));
|
||||
}
|
||||
|
||||
|
||||
if (!validFileExtensions.Contains(f.Extension.Substring(1)))
|
||||
/// <summary>
|
||||
/// Validates that the current filepath has one of several authorized extensions.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validFileExtensions">The valid extensions.</param>
|
||||
/// <returns>True, if the filepath is valid, else an exception is thrown.</returns>
|
||||
/// <exception cref="FileSecurityException">The filepath is invalid.</exception>
|
||||
internal static bool ValidateFileExtension(string filePath, List<string> validFileExtensions)
|
||||
{
|
||||
if (!VerifyFileExtension(filePath, validFileExtensions))
|
||||
throw new FileSecurityException(String.Format("The extension for the current file '{0}' is not of an allowed type for this editor. This is typically controlled from either the installed MacroEngines or based on configuration in /config/umbracoSettings.config", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -216,55 +263,8 @@ namespace Umbraco.Core.IO
|
||||
/// <returns>A safe filename without any path specific chars.</returns>
|
||||
internal static string SafeFileName(string filePath)
|
||||
{
|
||||
if (String.IsNullOrEmpty(filePath))
|
||||
return String.Empty;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(filePath))
|
||||
{
|
||||
foreach (var character in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
filePath = filePath.Replace(character, '-');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = String.Empty;
|
||||
}
|
||||
|
||||
//Break up the file in name and extension before applying the UrlReplaceCharacters
|
||||
var fileNamePart = filePath.Substring(0, filePath.LastIndexOf('.'));
|
||||
var ext = filePath.Substring(filePath.LastIndexOf('.'));
|
||||
|
||||
//Because the file usually is downloadable as well we check characters against 'UmbracoSettings.UrlReplaceCharacters'
|
||||
XmlNode replaceChars = UmbracoSettings.UrlReplaceCharacters;
|
||||
foreach (XmlNode n in replaceChars.SelectNodes("char"))
|
||||
{
|
||||
if (n.Attributes.GetNamedItem("org") != null && n.Attributes.GetNamedItem("org").Value != "")
|
||||
fileNamePart = fileNamePart.Replace(n.Attributes.GetNamedItem("org").Value, XmlHelper.GetNodeValue(n));
|
||||
}
|
||||
|
||||
filePath = string.Concat(fileNamePart, ext);
|
||||
|
||||
// Adapted from: http://stackoverflow.com/a/4827510/5018
|
||||
// Combined both Reserved Characters and Character Data
|
||||
// from http://en.wikipedia.org/wiki/Percent-encoding
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
const string reservedCharacters = "!*'();:@&=+$,/?%#[]-~{}\"<>\\^`| ";
|
||||
|
||||
foreach (var character in filePath)
|
||||
{
|
||||
if (reservedCharacters.IndexOf(character) == -1)
|
||||
stringBuilder.Append(character);
|
||||
else
|
||||
stringBuilder.Append("-");
|
||||
}
|
||||
|
||||
// Remove repeating dashes
|
||||
// From: http://stackoverflow.com/questions/5111967/regex-to-remove-a-specific-repeated-character
|
||||
var reducedString = Regex.Replace(stringBuilder.ToString(), "-+", "-");
|
||||
|
||||
return reducedString;
|
||||
// use string extensions
|
||||
return filePath.ToSafeFileName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -3,10 +3,11 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using Umbraco.Core.Macros;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
namespace Umbraco.Core.Macros
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver to return all IMacroGuiRendering objects
|
||||
@@ -24,9 +25,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <param name="macroEditors"></param>
|
||||
internal MacroFieldEditorsResolver(Func<IEnumerable<Type>> macroEditors)
|
||||
: base(macroEditors, ObjectLifetimeScope.Transient)
|
||||
{
|
||||
|
||||
}
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IMacroGuiRendering"/> implementations.
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -101,8 +103,11 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
set
|
||||
{
|
||||
_template = value;
|
||||
OnPropertyChanged(TemplateSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_template = value;
|
||||
return _template;
|
||||
}, _template, TemplateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,8 +145,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _published; }
|
||||
internal set
|
||||
{
|
||||
_published = value;
|
||||
OnPropertyChanged(PublishedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_published = value;
|
||||
return _published;
|
||||
}, _published, PublishedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,8 +165,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _language; }
|
||||
set
|
||||
{
|
||||
_language = value;
|
||||
OnPropertyChanged(LanguageSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_language = value;
|
||||
return _language;
|
||||
}, _language, LanguageSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,8 +182,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _releaseDate; }
|
||||
set
|
||||
{
|
||||
_releaseDate = value;
|
||||
OnPropertyChanged(ReleaseDateSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_releaseDate = value;
|
||||
return _releaseDate;
|
||||
}, _releaseDate, ReleaseDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,8 +199,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _expireDate; }
|
||||
set
|
||||
{
|
||||
_expireDate = value;
|
||||
OnPropertyChanged(ExpireDateSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_expireDate = value;
|
||||
return _expireDate;
|
||||
}, _expireDate, ExpireDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,8 +216,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _writer; }
|
||||
set
|
||||
{
|
||||
_writer = value;
|
||||
OnPropertyChanged(WriterSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_writer = value;
|
||||
return _writer;
|
||||
}, _writer, WriterSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,8 +235,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _nodeName; }
|
||||
set
|
||||
{
|
||||
_nodeName = value;
|
||||
OnPropertyChanged(NodeNameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_nodeName = value;
|
||||
return _nodeName;
|
||||
}, _nodeName, NodeNameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -13,6 +14,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Represents an abstract class for base Content properties and methods
|
||||
/// </summary>
|
||||
[DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentTypeBase.Alias}")]
|
||||
public abstract class ContentBase : Entity, IContentBase
|
||||
{
|
||||
protected IContentTypeComposition ContentTypeBase;
|
||||
@@ -118,8 +120,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +137,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,8 +154,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_level = value;
|
||||
return _level;
|
||||
}, _level, LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +171,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,8 +188,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _creatorId; }
|
||||
set
|
||||
{
|
||||
_creatorId = value;
|
||||
OnPropertyChanged(CreatorIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_creatorId = value;
|
||||
return _creatorId;
|
||||
}, _creatorId, CreatorIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,8 +207,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _trashed; }
|
||||
internal set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_trashed = value;
|
||||
return _trashed;
|
||||
}, _trashed, TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,8 +230,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _contentTypeId; }
|
||||
protected set
|
||||
{
|
||||
_contentTypeId = value;
|
||||
OnPropertyChanged(DefaultContentTypeIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_contentTypeId = value;
|
||||
return _contentTypeId;
|
||||
}, _contentTypeId, DefaultContentTypeIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
@@ -12,6 +13,7 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Media;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -19,6 +21,90 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public static class ContentExtensions
|
||||
{
|
||||
#region IContent
|
||||
/// <summary>
|
||||
/// Returns a list of the current contents ancestors, not including the content itself.
|
||||
/// </summary>
|
||||
/// <param name="content">Current content</param>
|
||||
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public static IEnumerable<IContent> Ancestors(this IContent content)
|
||||
{
|
||||
return ApplicationContext.Current.Services.ContentService.GetAncestors(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of the current contents children.
|
||||
/// </summary>
|
||||
/// <param name="content">Current content</param>
|
||||
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public static IEnumerable<IContent> Children(this IContent content)
|
||||
{
|
||||
return ApplicationContext.Current.Services.ContentService.GetChildren(content.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of the current contents descendants, not including the content itself.
|
||||
/// </summary>
|
||||
/// <param name="content">Current content</param>
|
||||
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public static IEnumerable<IContent> Descendants(this IContent content)
|
||||
{
|
||||
return ApplicationContext.Current.Services.ContentService.GetDescendants(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the parent of the current content.
|
||||
/// </summary>
|
||||
/// <param name="content">Current content</param>
|
||||
/// <returns>An <see cref="IContent"/> object</returns>
|
||||
public static IContent Parent(this IContent content)
|
||||
{
|
||||
return ApplicationContext.Current.Services.ContentService.GetById(content.ParentId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IMedia
|
||||
/// <summary>
|
||||
/// Returns a list of the current medias ancestors, not including the media itself.
|
||||
/// </summary>
|
||||
/// <param name="media">Current media</param>
|
||||
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
|
||||
public static IEnumerable<IMedia> Ancestors(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.MediaService.GetAncestors(media);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of the current medias children.
|
||||
/// </summary>
|
||||
/// <param name="media">Current media</param>
|
||||
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
|
||||
public static IEnumerable<IMedia> Children(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.MediaService.GetChildren(media.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of the current medias descendants, not including the media itself.
|
||||
/// </summary>
|
||||
/// <param name="media">Current media</param>
|
||||
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
|
||||
public static IEnumerable<IMedia> Descendants(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.MediaService.GetDescendants(media);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the parent of the current media.
|
||||
/// </summary>
|
||||
/// <param name="media">Current media</param>
|
||||
/// <returns>An <see cref="IMedia"/> object</returns>
|
||||
public static IMedia Parent(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.MediaService.GetById(media.ParentId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Set property values by alias with an annonymous object
|
||||
/// </summary>
|
||||
@@ -165,7 +251,7 @@ namespace Umbraco.Core.Models
|
||||
var thumbUrl = Resize(fs, fileName, extension, 100, "thumb");
|
||||
|
||||
//Look up Prevalues for this upload datatype - if it is an upload datatype
|
||||
var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c");
|
||||
var uploadFieldId = new Guid(Constants.PropertyEditors.UploadField);
|
||||
if (property.PropertyType.DataTypeId == uploadFieldId)
|
||||
{
|
||||
//Get Prevalues by the DataType's Id: property.PropertyType.DataTypeId
|
||||
@@ -337,8 +423,16 @@ namespace Umbraco.Core.Models
|
||||
return new Tuple<int, int, string>(widthTh, heightTh, newFileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this media item.
|
||||
/// </summary>
|
||||
public static IProfile GetCreatorProfile(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.UserService.GetProfileById(media.CreatorId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this content/media item.
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this content item.
|
||||
/// </summary>
|
||||
public static IProfile GetCreatorProfile(this IContentBase content)
|
||||
{
|
||||
@@ -366,6 +460,47 @@ namespace Umbraco.Core.Models
|
||||
return ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the full xml representation for the <see cref="IContent"/> object and all of it's descendants
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to generate xml for</param>
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
internal static XElement ToDeepXml(this IContent content)
|
||||
{
|
||||
var xml = content.ToXml();
|
||||
|
||||
var descendants = content.Descendants().ToArray();
|
||||
var currentChildren = descendants.Where(x => x.ParentId == content.Id);
|
||||
AddChildXml(descendants, currentChildren, xml);
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by ToDeepXml to recursively add children
|
||||
/// </summary>
|
||||
/// <param name="originalDescendants"></param>
|
||||
/// <param name="currentChildren"></param>
|
||||
/// <param name="currentXml"></param>
|
||||
private static void AddChildXml(
|
||||
IContent[] originalDescendants,
|
||||
IEnumerable<IContent> currentChildren,
|
||||
XElement currentXml)
|
||||
{
|
||||
foreach (var child in currentChildren)
|
||||
{
|
||||
//add the child's xml
|
||||
var childXml = child.ToXml();
|
||||
currentXml.Add(childXml);
|
||||
//copy local (out of closure)
|
||||
var c = child;
|
||||
//get this item's children
|
||||
var children = originalDescendants.Where(x => x.ParentId == c.Id);
|
||||
//recurse and add it's children to the child xml element
|
||||
AddChildXml(originalDescendants, children, childXml);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
@@ -373,8 +508,8 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
public static XElement ToXml(this IContent content)
|
||||
{
|
||||
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
|
||||
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : content.ContentType.Alias.ToSafeAliasWithForcingCheck();
|
||||
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
|
||||
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : content.ContentType.Alias.ToSafeAliasWithForcingCheck();
|
||||
|
||||
var x = content.ToXml(nodeName);
|
||||
x.Add(new XAttribute("nodeType", content.ContentType.Id));
|
||||
@@ -422,9 +557,10 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
private static XElement ToXml(this IContentBase contentBase, string nodeName)
|
||||
{
|
||||
var niceUrl = contentBase.Name.FormatUrl().ToLower();
|
||||
// note: that one will take care of umbracoUrlName
|
||||
var url = contentBase.GetUrlSegment();
|
||||
|
||||
var xml = new XElement(nodeName,
|
||||
var xml = new XElement(nodeName,
|
||||
new XAttribute("id", contentBase.Id),
|
||||
new XAttribute("parentID", contentBase.Level > 1 ? contentBase.ParentId : -1),
|
||||
new XAttribute("level", contentBase.Level),
|
||||
@@ -433,24 +569,15 @@ namespace Umbraco.Core.Models
|
||||
new XAttribute("createDate", contentBase.CreateDate.ToString("s")),
|
||||
new XAttribute("updateDate", contentBase.UpdateDate.ToString("s")),
|
||||
new XAttribute("nodeName", contentBase.Name),
|
||||
new XAttribute("urlName", niceUrl),//Format Url ?
|
||||
new XAttribute("urlName", url),
|
||||
new XAttribute("path", contentBase.Path),
|
||||
new XAttribute("isDoc", ""));
|
||||
|
||||
foreach (var property in contentBase.Properties)
|
||||
{
|
||||
if (property == null) continue;
|
||||
foreach (var property in contentBase.Properties.Where(p => p != null))
|
||||
xml.Add(property.ToXml());
|
||||
|
||||
xml.Add(property.ToXml());
|
||||
|
||||
//Check for umbracoUrlName convention
|
||||
if (property.Alias == "umbracoUrlName" && property.Value != null &&
|
||||
property.Value.ToString().Trim() != string.Empty)
|
||||
xml.SetAttributeValue("urlName", property.Value.ToString().FormatUrl().ToLower());
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IContent"/> object
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -47,8 +48,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _defaultTemplate; }
|
||||
set
|
||||
{
|
||||
_defaultTemplate = value;
|
||||
OnPropertyChanged(DefaultTemplateSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_defaultTemplate = value;
|
||||
return _defaultTemplate;
|
||||
}, _defaultTemplate, DefaultTemplateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +65,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedTemplates; }
|
||||
set
|
||||
{
|
||||
_allowedTemplates = value;
|
||||
OnPropertyChanged(AllowedTemplatesSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_allowedTemplates = value;
|
||||
return _allowedTemplates;
|
||||
}, _allowedTemplates, AllowedTemplatesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Umbraco.Core.Models
|
||||
private string _alias;
|
||||
private string _description;
|
||||
private int _sortOrder;
|
||||
private string _icon;
|
||||
private string _thumbnail;
|
||||
private string _icon = "folder.png";
|
||||
private string _thumbnail = "folder.png";
|
||||
private int _creatorId;
|
||||
private bool _allowedAsRoot;
|
||||
private bool _isContainer;
|
||||
@@ -31,6 +31,8 @@ namespace Umbraco.Core.Models
|
||||
private PropertyGroupCollection _propertyGroups;
|
||||
private PropertyTypeCollection _propertyTypes;
|
||||
private IEnumerable<ContentTypeSort> _allowedContentTypes;
|
||||
private bool _hasPropertyTypeBeenRemoved;
|
||||
|
||||
|
||||
protected ContentTypeBase(int parentId)
|
||||
{
|
||||
@@ -68,6 +70,8 @@ namespace Umbraco.Core.Models
|
||||
private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<ContentTypeSort>>(x => x.AllowedContentTypes);
|
||||
private static readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, PropertyGroupCollection>(x => x.PropertyGroups);
|
||||
private static readonly PropertyInfo PropertyTypeCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<PropertyType>>(x => x.PropertyTypes);
|
||||
private static readonly PropertyInfo HasPropertyTypeBeenRemovedSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.HasPropertyTypeBeenRemoved);
|
||||
|
||||
|
||||
protected void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
@@ -111,8 +115,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,8 +132,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_level = value;
|
||||
return _level;
|
||||
}, _level, LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,8 +149,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,8 +166,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value.ToSafeAlias();
|
||||
OnPropertyChanged(AliasSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value.ToSafeAlias();
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +183,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _description; }
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged(DescriptionSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_description = value;
|
||||
return _description;
|
||||
}, _description, DescriptionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,8 +200,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,8 +217,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _icon; }
|
||||
set
|
||||
{
|
||||
_icon = value;
|
||||
OnPropertyChanged(IconSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_icon = value;
|
||||
return _icon;
|
||||
}, _icon, IconSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,8 +234,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _thumbnail; }
|
||||
set
|
||||
{
|
||||
_thumbnail = value;
|
||||
OnPropertyChanged(ThumbnailSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_thumbnail = value;
|
||||
return _thumbnail;
|
||||
}, _thumbnail, ThumbnailSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,8 +251,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _creatorId; }
|
||||
set
|
||||
{
|
||||
_creatorId = value;
|
||||
OnPropertyChanged(CreatorIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_creatorId = value;
|
||||
return _creatorId;
|
||||
}, _creatorId, CreatorIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,8 +268,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedAsRoot; }
|
||||
set
|
||||
{
|
||||
_allowedAsRoot = value;
|
||||
OnPropertyChanged(AllowedAsRootSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_allowedAsRoot = value;
|
||||
return _allowedAsRoot;
|
||||
}, _allowedAsRoot, AllowedAsRootSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,8 +288,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _isContainer; }
|
||||
set
|
||||
{
|
||||
_isContainer = value;
|
||||
OnPropertyChanged(IsContainerSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_isContainer = value;
|
||||
return _isContainer;
|
||||
}, _isContainer, IsContainerSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,8 +306,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _trashed; }
|
||||
set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_trashed = value;
|
||||
return _trashed;
|
||||
}, _trashed, TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,8 +323,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedContentTypes; }
|
||||
set
|
||||
{
|
||||
_allowedContentTypes = value;
|
||||
OnPropertyChanged(AllowedContentTypesSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_allowedContentTypes = value;
|
||||
return _allowedContentTypes;
|
||||
}, _allowedContentTypes, AllowedContentTypesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,6 +365,24 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A boolean flag indicating if a property type has been removed from this instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is currently (specifically) used in order to know that we need to refresh the content cache which
|
||||
/// needs to occur when a property has been removed from a content type
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
internal bool HasPropertyTypeBeenRemoved
|
||||
{
|
||||
get { return _hasPropertyTypeBeenRemoved; }
|
||||
private set
|
||||
{
|
||||
_hasPropertyTypeBeenRemoved = value;
|
||||
OnPropertyChanged(HasPropertyTypeBeenRemovedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a PropertyType with a given alias already exists
|
||||
/// </summary>
|
||||
@@ -396,6 +457,15 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="propertyTypeAlias">Alias of the <see cref="PropertyType"/> to remove</param>
|
||||
public void RemovePropertyType(string propertyTypeAlias)
|
||||
{
|
||||
|
||||
//check if the property exist in one of our collections
|
||||
if (PropertyGroups.Any(group => group.PropertyTypes.Any(pt => pt.Alias == propertyTypeAlias))
|
||||
|| _propertyTypes.Any(x => x.Alias == propertyTypeAlias))
|
||||
{
|
||||
//set the flag that a property has been removed
|
||||
HasPropertyTypeBeenRemoved = true;
|
||||
}
|
||||
|
||||
foreach (var propertyGroup in PropertyGroups)
|
||||
{
|
||||
propertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias);
|
||||
@@ -403,7 +473,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
if (_propertyTypes.Any(x => x.Alias == propertyTypeAlias))
|
||||
{
|
||||
_propertyTypes.RemoveItem(propertyTypeAlias);
|
||||
_propertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal static class ContentTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all descendant content types
|
||||
/// </summary>
|
||||
/// <param name="contentType"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<IContentTypeBase> Descendants(this IContentTypeBase contentType)
|
||||
{
|
||||
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
|
||||
var descendants = contentTypeService.GetContentTypeChildren(contentType.Id)
|
||||
.FlattenList(type => contentTypeService.GetContentTypeChildren(type.Id));
|
||||
return descendants;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all descendant and self content types
|
||||
/// </summary>
|
||||
/// <param name="contentType"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<IContentTypeBase> DescendantsAndSelf(this IContentTypeBase contentType)
|
||||
{
|
||||
var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants());
|
||||
return descendantsAndSelf;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Returns the descendant content type Ids for the given content type
|
||||
///// </summary>
|
||||
///// <param name="contentType"></param>
|
||||
///// <returns></returns>
|
||||
//public static IEnumerable<int> DescendantIds(this IContentTypeBase contentType)
|
||||
//{
|
||||
// return ((ContentTypeService) ApplicationContext.Current.Services.ContentTypeService)
|
||||
// .GetDescendantContentTypeIds(contentType.Id);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -52,8 +53,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_parentId = value;
|
||||
return _parentId;
|
||||
}, _parentId, ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +70,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +87,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +104,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_level = value;
|
||||
return _level;
|
||||
}, _level, LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +121,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,8 +138,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _creatorId; }
|
||||
set
|
||||
{
|
||||
_creatorId = value;
|
||||
OnPropertyChanged(UserIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_creatorId = value;
|
||||
return _creatorId;
|
||||
}, _creatorId, UserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,8 +155,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _trashed; }
|
||||
internal set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_trashed = value;
|
||||
return _trashed;
|
||||
}, _trashed, TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,9 +171,12 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get { return _controlId; }
|
||||
private set
|
||||
{
|
||||
_controlId = value;
|
||||
OnPropertyChanged(ControlIdSelector);
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_controlId = value;
|
||||
return _controlId;
|
||||
}, _controlId, ControlIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,9 +188,12 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get { return _databaseType; }
|
||||
set
|
||||
{
|
||||
_databaseType = value;
|
||||
OnPropertyChanged(DatabaseTypeSelector);
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_databaseType = value;
|
||||
return _databaseType;
|
||||
}, _databaseType, DatabaseTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -41,8 +42,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_parentId = value;
|
||||
return _parentId;
|
||||
}, _parentId, ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +59,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _itemKey; }
|
||||
set
|
||||
{
|
||||
_itemKey = value;
|
||||
OnPropertyChanged(ItemKeySelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_itemKey = value;
|
||||
return _itemKey;
|
||||
}, _itemKey, ItemKeySelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +76,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _translations; }
|
||||
set
|
||||
{
|
||||
_translations = value;
|
||||
OnPropertyChanged(TranslationsSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_translations = value;
|
||||
return _translations;
|
||||
}, _translations, TranslationsSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -40,8 +41,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _language; }
|
||||
set
|
||||
{
|
||||
_language = value;
|
||||
OnPropertyChanged(LanguageSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_language = value;
|
||||
return _language;
|
||||
}, _language, LanguageSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +58,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _value; }
|
||||
set
|
||||
{
|
||||
_value = value;
|
||||
OnPropertyChanged(ValueSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_value = value;
|
||||
return _value;
|
||||
}, _value, ValueSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
@@ -12,12 +10,24 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public abstract class Entity : IEntity, ICanBeDirty
|
||||
[DebuggerDisplay("Id: {Id}")]
|
||||
public abstract class Entity : TracksChangesEntityBase, IEntity, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
private bool _hasIdentity;
|
||||
private int? _hash;
|
||||
private int _id;
|
||||
private Guid _key;
|
||||
private DateTime _createDate;
|
||||
private DateTime _updateDate;
|
||||
private bool _wasCancelled;
|
||||
|
||||
private static readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo<Entity, int>(x => x.Id);
|
||||
private static readonly PropertyInfo KeySelector = ExpressionHelper.GetPropertyInfo<Entity, Guid>(x => x.Key);
|
||||
private static readonly PropertyInfo CreateDateSelector = ExpressionHelper.GetPropertyInfo<Entity, DateTime>(x => x.CreateDate);
|
||||
private static readonly PropertyInfo UpdateDateSelector = ExpressionHelper.GetPropertyInfo<Entity, DateTime>(x => x.UpdateDate);
|
||||
private static readonly PropertyInfo HasIdentitySelector = ExpressionHelper.GetPropertyInfo<Entity, bool>(x => x.HasIdentity);
|
||||
private static readonly PropertyInfo WasCancelledSelector = ExpressionHelper.GetPropertyInfo<Entity, bool>(x => x.WasCancelled);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Integer Id
|
||||
@@ -31,8 +41,12 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
}
|
||||
set
|
||||
{
|
||||
_id = value;
|
||||
HasIdentity = true;
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_id = value;
|
||||
HasIdentity = true; //set the has Identity
|
||||
return _id;
|
||||
}, _id, IdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,46 +65,67 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
|
||||
return _key;
|
||||
}
|
||||
set { _key = value; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_key = value;
|
||||
return _key;
|
||||
}, _key, KeySelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Created Date
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public DateTime CreateDate { get; set; }
|
||||
public DateTime CreateDate
|
||||
{
|
||||
get { return _createDate; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_createDate = value;
|
||||
return _createDate;
|
||||
}, _createDate, CreateDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Modified Date
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the WasCancelled flag, which is used to track
|
||||
/// /// Gets or sets the WasCancelled flag, which is used to track
|
||||
/// whether some action against an entity was cancelled through some event.
|
||||
/// This only exists so we have a way to check if an event was cancelled through
|
||||
/// the new api, which also needs to take effect in the legacy api.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
internal bool WasCancelled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Method to call on a property setter.
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">The property info.</param>
|
||||
protected virtual void OnPropertyChanged(PropertyInfo propertyInfo)
|
||||
internal bool WasCancelled
|
||||
{
|
||||
_propertyChangedInfo[propertyInfo.Name] = true;
|
||||
|
||||
if (PropertyChanged != null)
|
||||
get { return _wasCancelled; }
|
||||
set
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name));
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_wasCancelled = value;
|
||||
return _wasCancelled;
|
||||
}, _wasCancelled, WasCancelledSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Modified Date
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public DateTime UpdateDate
|
||||
{
|
||||
get { return _updateDate; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_updateDate = value;
|
||||
return _updateDate;
|
||||
}, _updateDate, UpdateDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,42 +152,6 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
UpdateDate = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the properties that have changed
|
||||
/// </summary>
|
||||
private readonly IDictionary<string, bool> _propertyChangedInfo = new Dictionary<string, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>True if Property is dirty, otherwise False</returns>
|
||||
public virtual bool IsPropertyDirty(string propertyName)
|
||||
{
|
||||
return _propertyChangedInfo.Any(x => x.Key == propertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <returns>True if entity is dirty, otherwise False</returns>
|
||||
public virtual bool IsDirty()
|
||||
{
|
||||
return _propertyChangedInfo.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets dirty properties by clearing the dictionary used to track changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Please note that resetting the dirty properties could potentially
|
||||
/// obstruct the saving of a new or updated entity.
|
||||
/// </remarks>
|
||||
public virtual void ResetDirtyProperties()
|
||||
{
|
||||
_propertyChangedInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity has an identity, eg. Id.
|
||||
/// </summary>
|
||||
@@ -164,7 +163,11 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
}
|
||||
protected set
|
||||
{
|
||||
_hasIdentity = value;
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_hasIdentity = value;
|
||||
return _hasIdentity;
|
||||
}, _hasIdentity, HasIdentitySelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface that defines if the object is tracking property changes and that is is also
|
||||
/// remembering what property changes had been made after the changes were committed.
|
||||
/// </summary>
|
||||
public interface IRememberBeingDirty : ICanBeDirty
|
||||
{
|
||||
bool WasDirty();
|
||||
bool WasPropertyDirty(string propertyName);
|
||||
void ForgetPreviouslyDirtyProperties();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for use to implement IRememberBeingDirty/ICanBeDirty
|
||||
/// </summary>
|
||||
public abstract class TracksChangesEntityBase : IRememberBeingDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracks the properties that have changed
|
||||
/// </summary>
|
||||
private readonly IDictionary<string, bool> _propertyChangedInfo = new Dictionary<string, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the properties that we're changed before the last commit (or last call to ResetDirtyProperties)
|
||||
/// </summary>
|
||||
private IDictionary<string, bool> _lastPropertyChangedInfo = null;
|
||||
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Method to call on a property setter.
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">The property info.</param>
|
||||
protected virtual void OnPropertyChanged(PropertyInfo propertyInfo)
|
||||
{
|
||||
_propertyChangedInfo[propertyInfo.Name] = true;
|
||||
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>True if Property is dirty, otherwise False</returns>
|
||||
public virtual bool IsPropertyDirty(string propertyName)
|
||||
{
|
||||
return _propertyChangedInfo.Any(x => x.Key == propertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <returns>True if entity is dirty, otherwise False</returns>
|
||||
public virtual bool IsDirty()
|
||||
{
|
||||
return _propertyChangedInfo.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the entity had been changed and the changes were committed
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool WasDirty()
|
||||
{
|
||||
return _lastPropertyChangedInfo != null && _lastPropertyChangedInfo.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current entity was changed and the changes were committed
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>True if Property was changed, otherwise False. Returns false if the entity had not been previously changed.</returns>
|
||||
public virtual bool WasPropertyDirty(string propertyName)
|
||||
{
|
||||
return WasDirty() && _lastPropertyChangedInfo.Any(x => x.Key == propertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the remembered dirty properties from before the last commit
|
||||
/// </summary>
|
||||
public void ForgetPreviouslyDirtyProperties()
|
||||
{
|
||||
_lastPropertyChangedInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets dirty properties by clearing the dictionary used to track changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Please note that resetting the dirty properties could potentially
|
||||
/// obstruct the saving of a new or updated entity.
|
||||
/// </remarks>
|
||||
public virtual void ResetDirtyProperties()
|
||||
{
|
||||
ResetDirtyProperties(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets dirty properties by clearing the dictionary used to track changes.
|
||||
/// </summary>
|
||||
/// <param name="rememberPreviouslyChangedProperties">
|
||||
/// true if we are to remember the last changes made after resetting
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Please note that resetting the dirty properties could potentially
|
||||
/// obstruct the saving of a new or updated entity.
|
||||
/// </remarks>
|
||||
internal void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
if (rememberPreviouslyChangedProperties)
|
||||
{
|
||||
//copy the changed properties to the last changed properties
|
||||
_lastPropertyChangedInfo = _propertyChangedInfo.ToDictionary(v => v.Key, v => v.Value);
|
||||
}
|
||||
|
||||
_propertyChangedInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by inheritors to set the value of properties, this will detect if the property value actually changed and if it did
|
||||
/// it will ensure that the property has a dirty flag set.
|
||||
/// </summary>
|
||||
/// <param name="setValue"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="propertySelector"></param>
|
||||
/// <returns>returns true if the value changed</returns>
|
||||
/// <remarks>
|
||||
/// This is required because we don't want a property to show up as "dirty" if the value is the same. For example, when we
|
||||
/// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set
|
||||
/// to the same value, so it's really not dirty.
|
||||
/// </remarks>
|
||||
internal bool SetPropertyValueAndDetectChanges<T>(Func<T, T> setValue, T value, PropertyInfo propertySelector)
|
||||
{
|
||||
var initVal = value;
|
||||
var newVal = setValue(value);
|
||||
if (!Equals(initVal, newVal))
|
||||
{
|
||||
OnPropertyChanged(propertySelector);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -12,11 +13,17 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public abstract class File : Entity, IFile
|
||||
{
|
||||
private string _path;
|
||||
private string _content = string.Empty; //initialize to empty string, not null
|
||||
|
||||
protected File(string path)
|
||||
{
|
||||
Path = path;
|
||||
_path = path;
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo<File, string>(x => x.Content);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<File, string>(x => x.Path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name of the File including extension
|
||||
/// </summary>
|
||||
@@ -48,13 +55,35 @@ namespace Umbraco.Core.Models
|
||||
/// Gets or sets the Path to the File from the root of the site
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual string Path { get; set; }
|
||||
public virtual string Path
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Content of a File
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual string Content { get; set; }
|
||||
public virtual string Content
|
||||
{
|
||||
get { return _content; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_content = value;
|
||||
return _content;
|
||||
}, _content, ContentSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the file could be validated
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a Content object
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
public interface IContent : IContentBase
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Umbraco.Core.Models
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IMedia : IContentBase
|
||||
{
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
namespace Umbraco.Core.Models
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a ContentType, which Media is based on
|
||||
/// </summary>
|
||||
/// </summary
|
||||
public interface IMediaType : IContentTypeComposition
|
||||
{
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -33,8 +34,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _isoCode; }
|
||||
set
|
||||
{
|
||||
_isoCode = value;
|
||||
OnPropertyChanged(IsoCodeSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_isoCode = value;
|
||||
return _isoCode;
|
||||
}, _isoCode, IsoCodeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +51,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _cultureName; }
|
||||
set
|
||||
{
|
||||
_cultureName = value;
|
||||
OnPropertyChanged(CultureNameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_cultureName = value;
|
||||
return _cultureName;
|
||||
}, _cultureName, CultureNameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -12,81 +13,240 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
internal class Macro : Entity, IMacro
|
||||
{
|
||||
private string _alias;
|
||||
private string _name;
|
||||
private bool _useInEditor;
|
||||
private int _cacheDuration;
|
||||
private bool _cacheByPage;
|
||||
private bool _cacheByMember;
|
||||
private bool _dontRender;
|
||||
private string _scriptFile;
|
||||
private string _scriptAssembly;
|
||||
private string _python;
|
||||
private string _xslt;
|
||||
private List<IMacroProperty> _properties;
|
||||
|
||||
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.Alias);
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.Name);
|
||||
private static readonly PropertyInfo UseInEditorSelector = ExpressionHelper.GetPropertyInfo<Macro, bool>(x => x.UseInEditor);
|
||||
private static readonly PropertyInfo CacheDurationSelector = ExpressionHelper.GetPropertyInfo<Macro, int>(x => x.CacheDuration);
|
||||
private static readonly PropertyInfo CacheByPageSelector = ExpressionHelper.GetPropertyInfo<Macro, bool>(x => x.CacheByPage);
|
||||
private static readonly PropertyInfo CacheByMemberSelector = ExpressionHelper.GetPropertyInfo<Macro, bool>(x => x.CacheByMember);
|
||||
private static readonly PropertyInfo DontRenderSelector = ExpressionHelper.GetPropertyInfo<Macro, bool>(x => x.DontRender);
|
||||
private static readonly PropertyInfo ScriptFileSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.ScriptFile);
|
||||
private static readonly PropertyInfo ScriptAssemblySelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.ScriptAssembly);
|
||||
private static readonly PropertyInfo PythonSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.Python);
|
||||
private static readonly PropertyInfo XsltSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.Xslt);
|
||||
private static readonly PropertyInfo PropertiesSelector = ExpressionHelper.GetPropertyInfo<Macro, List<IMacroProperty>>(x => x.Properties);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alias of the Macro
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Alias { get; set; }
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the Macro
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name { get; set; }
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the Macro can be used in an Editor
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool UseInEditor { get; set; }
|
||||
public bool UseInEditor
|
||||
{
|
||||
get { return _useInEditor; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_useInEditor = value;
|
||||
return _useInEditor;
|
||||
}, _useInEditor, UseInEditorSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Cache Duration for the Macro
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int CacheDuration { get; set; }
|
||||
public int CacheDuration
|
||||
{
|
||||
get { return _cacheDuration; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_cacheDuration = value;
|
||||
return _cacheDuration;
|
||||
}, _cacheDuration, CacheDurationSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the Macro should be Cached by Page
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool CacheByPage { get; set; }
|
||||
public bool CacheByPage
|
||||
{
|
||||
get { return _cacheByPage; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_cacheByPage = value;
|
||||
return _cacheByPage;
|
||||
}, _cacheByPage, CacheByPageSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the Macro should be Cached Personally
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool CacheByMember { get; set; }
|
||||
public bool CacheByMember
|
||||
{
|
||||
get { return _cacheByMember; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_cacheByMember = value;
|
||||
return _cacheByMember;
|
||||
}, _cacheByMember, CacheByMemberSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the Macro should be rendered in an Editor
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool DontRender { get; set; }
|
||||
public bool DontRender
|
||||
{
|
||||
get { return _dontRender; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_dontRender = value;
|
||||
return _dontRender;
|
||||
}, _dontRender, DontRenderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the script file in use
|
||||
/// </summary>
|
||||
/// <remarks>Optional: Can only be one of three Script, Python or Xslt</remarks>
|
||||
[DataMember]
|
||||
public string ScriptFile { get; set; }
|
||||
public string ScriptFile
|
||||
{
|
||||
get { return _scriptFile; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_scriptFile = value;
|
||||
return _scriptFile;
|
||||
}, _scriptFile, ScriptFileSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the assembly, which should be used by the Macro
|
||||
/// </summary>
|
||||
/// <remarks>Will usually only be filled if the ScriptFile is a Usercontrol</remarks>
|
||||
[DataMember]
|
||||
public string ScriptAssembly { get; set; }
|
||||
public string ScriptAssembly
|
||||
{
|
||||
get { return _scriptAssembly; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_scriptAssembly = value;
|
||||
return _scriptAssembly;
|
||||
}, _scriptAssembly, ScriptAssemblySelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or set the path to the Python file in use
|
||||
/// </summary>
|
||||
/// <remarks>Optional: Can only be one of three Script, Python or Xslt</remarks>
|
||||
[DataMember]
|
||||
public string Python { get; set; }
|
||||
public string Python
|
||||
{
|
||||
get { return _python; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_python = value;
|
||||
return _python;
|
||||
}, _python, PythonSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the Xslt file in use
|
||||
/// </summary>
|
||||
/// <remarks>Optional: Can only be one of three Script, Python or Xslt</remarks>
|
||||
[DataMember]
|
||||
public string Xslt { get; set; }
|
||||
public string Xslt
|
||||
{
|
||||
get { return _xslt; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_xslt = value;
|
||||
return _xslt;
|
||||
}, _xslt, XsltSelector);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: This needs to be changed to a custom collection class so we can track the dirtyness of each property!
|
||||
/// <summary>
|
||||
/// Gets or sets a list of Macro Properties
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public List<IMacroProperty> Properties { get; set; }
|
||||
public List<IMacroProperty> Properties
|
||||
{
|
||||
get { return _properties; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_properties = value;
|
||||
return _properties;
|
||||
}, _properties, PropertiesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden this method in order to set a random Id
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -8,25 +10,68 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class MacroProperty : IMacroProperty
|
||||
internal class MacroProperty : TracksChangesEntityBase, IMacroProperty, IRememberBeingDirty
|
||||
{
|
||||
private string _alias;
|
||||
private string _name;
|
||||
private int _sortOrder;
|
||||
private IMacroPropertyType _propertyType;
|
||||
|
||||
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<MacroProperty, string>(x => x.Alias);
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<MacroProperty, string>(x => x.Name);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<MacroProperty, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo PropertyTypeSelector = ExpressionHelper.GetPropertyInfo<MacroProperty, IMacroPropertyType>(x => x.PropertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Alias of the Property
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Alias { get; set; }
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name of the Property
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name { get; set; }
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Sort Order of the Property
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int SortOrder { get; set; }
|
||||
public int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Type for this Property
|
||||
@@ -36,6 +81,18 @@ namespace Umbraco.Core.Models
|
||||
/// All types was previously contained in the database, but has been ported to code.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public IMacroPropertyType PropertyType { get; set; }
|
||||
public IMacroPropertyType PropertyType
|
||||
|
||||
{
|
||||
get { return _propertyType; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_propertyType = value;
|
||||
return _propertyType;
|
||||
}, _propertyType, PropertyTypeSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
|
||||
internal interface IUserType : IAggregateRoot
|
||||
{
|
||||
string Alias { get; set; }
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -82,8 +83,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _version; }
|
||||
set
|
||||
{
|
||||
_version = value;
|
||||
OnPropertyChanged(VersionSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_version = value;
|
||||
return _version;
|
||||
}, _version, VersionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +112,11 @@ namespace Umbraco.Core.Models
|
||||
"Type validation failed. The value type: '{0}' does not match the DataType in PropertyType with alias: '{1}'",
|
||||
value == null ? "null" : value.GetType().Name, Alias));
|
||||
|
||||
_value = value;
|
||||
OnPropertyChanged(ValueSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_value = value;
|
||||
return _value;
|
||||
}, _value, ValueSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -45,8 +46,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +86,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -72,8 +73,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +90,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
OnPropertyChanged(AliasSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +107,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _description; }
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged(DescriptionSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_description = value;
|
||||
return _description;
|
||||
}, _description, DescriptionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +125,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _dataTypeDefinitionId; }
|
||||
set
|
||||
{
|
||||
_dataTypeDefinitionId = value;
|
||||
OnPropertyChanged(DataTypeDefinitionIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_dataTypeDefinitionId = value;
|
||||
return _dataTypeDefinitionId;
|
||||
}, _dataTypeDefinitionId, DataTypeDefinitionIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,8 +143,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _dataTypeId; }
|
||||
internal set
|
||||
{
|
||||
_dataTypeId = value;
|
||||
OnPropertyChanged(DataTypeControlIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_dataTypeId = value;
|
||||
return _dataTypeId;
|
||||
}, _dataTypeId, DataTypeControlIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,8 +160,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _dataTypeDatabaseType; }
|
||||
set
|
||||
{
|
||||
_dataTypeDatabaseType = value;
|
||||
OnPropertyChanged(DataTypeDatabaseTypeSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_dataTypeDatabaseType = value;
|
||||
return _dataTypeDatabaseType;
|
||||
}, _dataTypeDatabaseType, DataTypeDatabaseTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,8 +177,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _propertyGroupId; }
|
||||
set
|
||||
{
|
||||
_propertyGroupId = value;
|
||||
OnPropertyChanged(PropertyGroupIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_propertyGroupId = value;
|
||||
return _propertyGroupId;
|
||||
}, _propertyGroupId, PropertyGroupIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +194,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _mandatory; }
|
||||
set
|
||||
{
|
||||
_mandatory = value;
|
||||
OnPropertyChanged(MandatorySelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_mandatory = value;
|
||||
return _mandatory;
|
||||
}, _mandatory, MandatorySelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,8 +211,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _helpText; }
|
||||
set
|
||||
{
|
||||
_helpText = value;
|
||||
OnPropertyChanged(HelpTextSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_helpText = value;
|
||||
return _helpText;
|
||||
}, _helpText, HelpTextSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,8 +228,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,8 +245,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _validationRegExp; }
|
||||
set
|
||||
{
|
||||
_validationRegExp = value;
|
||||
OnPropertyChanged(ValidationRegExpSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_validationRegExp = value;
|
||||
return _validationRegExp;
|
||||
}, _validationRegExp, ValidationRegExpSelector);
|
||||
}
|
||||
}
|
||||
//Note that Validation should eventually come from PropertyEditors like in v5
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoServer")]
|
||||
[PrimaryKey("id")]
|
||||
[ExplicitColumns]
|
||||
internal class ServerRegistrationDto
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(AutoIncrement = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("address")]
|
||||
[Length(500)]
|
||||
public string Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A unique column in the database, a computer name must always be unique!
|
||||
/// </summary>
|
||||
[Column("computerName")]
|
||||
[Length(255)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_computerName")]
|
||||
public string ComputerName { get; set; }
|
||||
|
||||
[Column("registeredDate")]
|
||||
[Constraint(Default = "getdate()")]
|
||||
public DateTime DateRegistered { get; set; }
|
||||
|
||||
[Column("lastNotifiedDate")]
|
||||
[Constraint(Default = "getdate()")]
|
||||
public DateTime LastNotified { get; set; }
|
||||
|
||||
[Column("isActive")]
|
||||
[Index(IndexTypes.NonClustered)]
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -39,8 +40,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_parentId = value;
|
||||
return _parentId;
|
||||
}, _parentId, ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +57,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _childId; }
|
||||
set
|
||||
{
|
||||
_childId = value;
|
||||
OnPropertyChanged(ChildIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_childId = value;
|
||||
return _childId;
|
||||
}, _childId, ChildIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +74,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _relationType; }
|
||||
set
|
||||
{
|
||||
_relationType = value;
|
||||
OnPropertyChanged(RelationTypeSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_relationType = value;
|
||||
return _relationType;
|
||||
}, _relationType, RelationTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +91,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _comment; }
|
||||
set
|
||||
{
|
||||
_comment = value;
|
||||
OnPropertyChanged(CommentSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_comment = value;
|
||||
return _comment;
|
||||
}, _comment, CommentSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -40,8 +41,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +58,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
OnPropertyChanged(AliasSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,8 +75,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _isBidrectional; }
|
||||
set
|
||||
{
|
||||
_isBidrectional = value;
|
||||
OnPropertyChanged(IsBidirectionalSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_isBidrectional = value;
|
||||
return _isBidrectional;
|
||||
}, _isBidrectional, IsBidirectionalSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +93,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _parentObjectType; }
|
||||
set
|
||||
{
|
||||
_parentObjectType = value;
|
||||
OnPropertyChanged(ParentObjectTypeSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_parentObjectType = value;
|
||||
return _parentObjectType;
|
||||
}, _parentObjectType, ParentObjectTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,8 +111,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _childObjectType; }
|
||||
set
|
||||
{
|
||||
_childObjectType = value;
|
||||
OnPropertyChanged(ChildObjectTypeSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_childObjectType = value;
|
||||
return _childObjectType;
|
||||
}, _childObjectType, ChildObjectTypeSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@ namespace Umbraco.Core.Models
|
||||
dirs += "," + SystemDirectories.MvcViews;*/
|
||||
|
||||
//Validate file
|
||||
var validFile = IOHelper.ValidateEditPath(Path, dirs.Split(','));
|
||||
var validFile = IOHelper.VerifyEditPath(Path, dirs.Split(','));
|
||||
|
||||
//Validate extension
|
||||
var validExtension = IOHelper.ValidateFileExtension(Path, exts);
|
||||
var validExtension = IOHelper.VerifyFileExtension(Path, exts);
|
||||
|
||||
return validFile && validExtension;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal class ServerRegistration : Entity, IServerAddress, IAggregateRoot
|
||||
{
|
||||
private string _serverAddress;
|
||||
private string _computerName;
|
||||
private bool _isActive;
|
||||
|
||||
private static readonly PropertyInfo ServerAddressSelector = ExpressionHelper.GetPropertyInfo<ServerRegistration, string>(x => x.ServerAddress);
|
||||
private static readonly PropertyInfo ComputerNameSelector = ExpressionHelper.GetPropertyInfo<ServerRegistration, string>(x => x.ComputerName);
|
||||
private static readonly PropertyInfo IsActiveSelector = ExpressionHelper.GetPropertyInfo<ServerRegistration, bool>(x => x.IsActive);
|
||||
|
||||
public ServerRegistration()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an item with pre-filled properties
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="serverAddress"></param>
|
||||
/// <param name="computerName"></param>
|
||||
/// <param name="createDate"></param>
|
||||
/// <param name="updateDate"></param>
|
||||
/// <param name="isActive"></param>
|
||||
public ServerRegistration(int id, string serverAddress, string computerName, DateTime createDate, DateTime updateDate, bool isActive)
|
||||
{
|
||||
UpdateDate = updateDate;
|
||||
CreateDate = createDate;
|
||||
Key = Id.ToString().EncodeAsGuid();
|
||||
Id = id;
|
||||
ServerAddress = serverAddress;
|
||||
ComputerName = computerName;
|
||||
IsActive = isActive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for persisting a new item
|
||||
/// </summary>
|
||||
/// <param name="serverAddress"></param>
|
||||
/// <param name="computerName"></param>
|
||||
/// <param name="createDate"></param>
|
||||
public ServerRegistration(string serverAddress, string computerName, DateTime createDate)
|
||||
{
|
||||
CreateDate = createDate;
|
||||
UpdateDate = createDate;
|
||||
Key = 0.ToString().EncodeAsGuid();
|
||||
ServerAddress = serverAddress;
|
||||
ComputerName = computerName;
|
||||
}
|
||||
|
||||
public string ServerAddress
|
||||
{
|
||||
get { return _serverAddress; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_serverAddress = value;
|
||||
return _serverAddress;
|
||||
}, _serverAddress, ServerAddressSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public string ComputerName
|
||||
{
|
||||
get { return _computerName; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_computerName = value;
|
||||
return _computerName;
|
||||
}, _computerName, ComputerNameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get { return _isActive; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_isActive = value;
|
||||
return _isActive;
|
||||
}, _isActive, IsActiveSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models.Css;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -119,10 +118,10 @@ namespace Umbraco.Core.Models
|
||||
var dirs = SystemDirectories.Css;
|
||||
|
||||
//Validate file
|
||||
var validFile = IOHelper.ValidateEditPath(Path, dirs.Split(','));
|
||||
var validFile = IOHelper.VerifyEditPath(Path, dirs.Split(','));
|
||||
|
||||
//Validate extension
|
||||
var validExtension = IOHelper.ValidateFileExtension(Path, new List<string> {"css"});
|
||||
var validExtension = IOHelper.VerifyFileExtension(Path, new List<string> {"css"});
|
||||
|
||||
return validFile && validExtension;
|
||||
}
|
||||
@@ -159,25 +158,4 @@ namespace Umbraco.Core.Models
|
||||
get { return string.IsNullOrEmpty(Path) == false; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Stylesheet Property
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Properties are always formatted to have a single selector, so it can be used in the backoffice
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class StylesheetProperty : IValueObject
|
||||
{
|
||||
public StylesheetProperty(string @alias, string value)
|
||||
{
|
||||
Alias = alias;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string Alias { get; set; }
|
||||
public string Value { get; set; }
|
||||
public bool IsPartOfAtRule { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Stylesheet Property
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Properties are always formatted to have a single selector, so it can be used in the backoffice
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class StylesheetProperty : IValueObject
|
||||
{
|
||||
public StylesheetProperty(string @alias, string value)
|
||||
{
|
||||
Alias = alias;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string Alias { get; set; }
|
||||
public string Value { get; set; }
|
||||
public bool IsPartOfAtRule { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _closed; }
|
||||
set
|
||||
{
|
||||
_closed = value;
|
||||
OnPropertyChanged(ClosedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_closed = value;
|
||||
return _closed;
|
||||
}, _closed, ClosedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +57,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _taskType; }
|
||||
set
|
||||
{
|
||||
_taskType = value;
|
||||
OnPropertyChanged(TaskTypeSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_taskType = value;
|
||||
return _taskType;
|
||||
}, _taskType, TaskTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,8 +74,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _entityId; }
|
||||
set
|
||||
{
|
||||
_entityId = value;
|
||||
OnPropertyChanged(EntityIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_entityId = value;
|
||||
return _entityId;
|
||||
}, _entityId, EntityIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +91,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _ownerUserId; }
|
||||
set
|
||||
{
|
||||
_ownerUserId = value;
|
||||
OnPropertyChanged(OwnerUserIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_ownerUserId = value;
|
||||
return _ownerUserId;
|
||||
}, _ownerUserId, OwnerUserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,8 +108,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _assigneeUserId; }
|
||||
set
|
||||
{
|
||||
_assigneeUserId = value;
|
||||
OnPropertyChanged(AssigneeUserIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_assigneeUserId = value;
|
||||
return _assigneeUserId;
|
||||
}, _assigneeUserId, AssigneeUserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +125,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _comment; }
|
||||
set
|
||||
{
|
||||
_comment = value;
|
||||
OnPropertyChanged(CommentSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_comment = value;
|
||||
return _comment;
|
||||
}, _comment, CommentSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
OnPropertyChanged(AliasSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
@@ -15,6 +16,22 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
private readonly string _alias;
|
||||
private readonly string _name;
|
||||
private int _creatorId;
|
||||
private int _level;
|
||||
private int _sortOrder;
|
||||
private int _parentId;
|
||||
private string _nodePath;
|
||||
private int _masterTemplateId;
|
||||
private string _masterTemplateAlias;
|
||||
|
||||
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.CreatorId);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.Level);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo NodePathSelector = ExpressionHelper.GetPropertyInfo<Template, string>(x => x.NodePath);
|
||||
//private static readonly PropertyInfo MasterTemplateIdSelector = ExpressionHelper.GetPropertyInfo<Template, int>(x => x.MasterTemplateId);
|
||||
private static readonly PropertyInfo MasterTemplateAliasSelector = ExpressionHelper.GetPropertyInfo<Template, string>(x => x.MasterTemplateAlias);
|
||||
|
||||
|
||||
internal Template(string path)
|
||||
: base(path)
|
||||
@@ -37,25 +54,91 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal int CreatorId { get; set; }
|
||||
internal int CreatorId
|
||||
{
|
||||
get { return _creatorId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_creatorId = value;
|
||||
return _creatorId;
|
||||
}, _creatorId, CreatorIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal int Level { get; set; }
|
||||
internal int Level
|
||||
{
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_level = value;
|
||||
return _level;
|
||||
}, _level, LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal int SortOrder { get; set; }
|
||||
internal int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal int ParentId { get; set; }
|
||||
internal int ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_parentId = value;
|
||||
return _parentId;
|
||||
}, _parentId, ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal string NodePath { get; set; }
|
||||
internal string NodePath
|
||||
{
|
||||
get { return _nodePath; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_nodePath = value;
|
||||
return _nodePath;
|
||||
}, _nodePath, NodePathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
internal Lazy<int> MasterTemplateId { get; set; }
|
||||
|
||||
[DataMember]
|
||||
internal string MasterTemplateAlias { get; set; }
|
||||
internal string MasterTemplateAlias
|
||||
{
|
||||
get { return _masterTemplateAlias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_masterTemplateAlias = value;
|
||||
return _masterTemplateAlias;
|
||||
}, _masterTemplateAlias, MasterTemplateAliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public override string Alias
|
||||
@@ -101,7 +184,7 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
else
|
||||
{
|
||||
exts.Add(UmbracoSettings.UseAspNetMasterPages ? "masterpage" : "aspx");
|
||||
exts.Add(UmbracoSettings.UseAspNetMasterPages ? "master" : "aspx");
|
||||
}
|
||||
|
||||
var dirs = SystemDirectories.Masterpages;
|
||||
@@ -109,10 +192,10 @@ namespace Umbraco.Core.Models
|
||||
dirs += "," + SystemDirectories.MvcViews;
|
||||
|
||||
//Validate file
|
||||
var validFile = IOHelper.ValidateEditPath(Path, dirs.Split(','));
|
||||
var validFile = IOHelper.VerifyEditPath(Path, dirs.Split(','));
|
||||
|
||||
//Validate extension
|
||||
var validExtension = IOHelper.ValidateFileExtension(Path, exts);
|
||||
var validExtension = IOHelper.VerifyFileExtension(Path, exts);
|
||||
|
||||
return validFile && validExtension;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of the <see cref="IUmbracoEntity"/> for internal use.
|
||||
/// </summary>
|
||||
internal class UmbracoEntity : Entity, IUmbracoEntity
|
||||
{
|
||||
private int _creatorId;
|
||||
private int _level;
|
||||
private string _name;
|
||||
private int _parentId;
|
||||
private string _path;
|
||||
private int _sortOrder;
|
||||
private bool _trashed;
|
||||
private bool _hasChildren;
|
||||
private bool _isPublished;
|
||||
private bool _isDraft;
|
||||
private bool _hasPendingChanges;
|
||||
private string _contentTypeAlias;
|
||||
private string _umbracoFile;
|
||||
private Guid _nodeObjectTypeId;
|
||||
|
||||
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, int>(x => x.CreatorId);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, int>(x => x.Level);
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, string>(x => x.Path);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, bool>(x => x.Trashed);
|
||||
private static readonly PropertyInfo HasChildrenSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, bool>(x => x.HasChildren);
|
||||
private static readonly PropertyInfo IsPublishedSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, bool>(x => x.IsPublished);
|
||||
private static readonly PropertyInfo IsDraftSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, bool>(x => x.IsDraft);
|
||||
private static readonly PropertyInfo HasPendingChangesSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, bool>(x => x.HasPendingChanges);
|
||||
private static readonly PropertyInfo ContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, string>(x => x.ContentTypeAlias);
|
||||
private static readonly PropertyInfo ContentTypeIconSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, string>(x => x.ContentTypeIcon);
|
||||
private static readonly PropertyInfo ContentTypeThumbnailSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, string>(x => x.ContentTypeThumbnail);
|
||||
private static readonly PropertyInfo UmbracoFileSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, string>(x => x.UmbracoFile);
|
||||
private static readonly PropertyInfo NodeObjectTypeIdSelector = ExpressionHelper.GetPropertyInfo<UmbracoEntity, Guid>(x => x.NodeObjectTypeId);
|
||||
private string _contentTypeIcon;
|
||||
private string _contentTypeThumbnail;
|
||||
|
||||
public UmbracoEntity()
|
||||
{
|
||||
}
|
||||
|
||||
public UmbracoEntity(bool trashed)
|
||||
{
|
||||
Trashed = trashed;
|
||||
}
|
||||
|
||||
public int CreatorId
|
||||
{
|
||||
get { return _creatorId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_creatorId = value;
|
||||
return _creatorId;
|
||||
}, _creatorId, CreatorIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public int Level
|
||||
{
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_level = value;
|
||||
return _level;
|
||||
}, _level, LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public int ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_parentId = value;
|
||||
return _parentId;
|
||||
}, _parentId, ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Trashed
|
||||
{
|
||||
get { return _trashed; }
|
||||
private set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_trashed = value;
|
||||
return _trashed;
|
||||
}, _trashed, TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasChildren
|
||||
{
|
||||
get { return _hasChildren; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_hasChildren = value;
|
||||
return _hasChildren;
|
||||
}, _hasChildren, HasChildrenSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPublished
|
||||
{
|
||||
get { return _isPublished; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_isPublished = value;
|
||||
return _isPublished;
|
||||
}, _isPublished, IsPublishedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDraft
|
||||
{
|
||||
get { return _isPublished; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_isDraft = value;
|
||||
return _isDraft;
|
||||
}, _isDraft, IsDraftSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasPendingChanges
|
||||
{
|
||||
get { return _hasPendingChanges; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_hasPendingChanges = value;
|
||||
return _hasPendingChanges;
|
||||
}, _hasPendingChanges, HasPendingChangesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public string ContentTypeAlias
|
||||
{
|
||||
get { return _contentTypeAlias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_contentTypeAlias = value;
|
||||
return _contentTypeAlias;
|
||||
}, _contentTypeAlias, ContentTypeAliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public string ContentTypeIcon
|
||||
{
|
||||
get { return _contentTypeIcon; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_contentTypeIcon = value;
|
||||
return _contentTypeIcon;
|
||||
}, _contentTypeIcon, ContentTypeIconSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public string ContentTypeThumbnail
|
||||
{
|
||||
get { return _contentTypeThumbnail; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_contentTypeThumbnail = value;
|
||||
return _contentTypeThumbnail;
|
||||
}, _contentTypeThumbnail, ContentTypeThumbnailSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public string UmbracoFile
|
||||
{
|
||||
get { return _umbracoFile; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_umbracoFile = value;
|
||||
return _umbracoFile;
|
||||
}, _umbracoFile, UmbracoFileSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public Guid NodeObjectTypeId
|
||||
{
|
||||
get { return _nodeObjectTypeId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_nodeObjectTypeId = value;
|
||||
return _nodeObjectTypeId;
|
||||
}, _nodeObjectTypeId, NodeObjectTypeIdSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum used to represent the Umbraco Object Types and thier associated GUIDs
|
||||
/// </summary>
|
||||
public enum UmbracoObjectTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Default value
|
||||
/// </summary>
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// Content Item Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.ContentItemType)]
|
||||
[FriendlyName("Content Item Type")]
|
||||
ContentItemType,
|
||||
|
||||
/// <summary>
|
||||
/// Root
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.SystemRoot)]
|
||||
[FriendlyName("Root")]
|
||||
ROOT,
|
||||
|
||||
/// <summary>
|
||||
/// Document
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Document, typeof(IContent))]
|
||||
[FriendlyName("Document")]
|
||||
Document,
|
||||
|
||||
/// <summary>
|
||||
/// Media
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Media, typeof(IMedia))]
|
||||
[FriendlyName("Media")]
|
||||
Media,
|
||||
|
||||
/// <summary>
|
||||
/// Member Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.MemberType)]
|
||||
[FriendlyName("Member Type")]
|
||||
MemberType,
|
||||
|
||||
/// <summary>
|
||||
/// Template
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Template, typeof(ITemplate))]
|
||||
[FriendlyName("Template")]
|
||||
Template,
|
||||
|
||||
/// <summary>
|
||||
/// Member Group
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.MemberGroup)]
|
||||
[FriendlyName("Member Group")]
|
||||
MemberGroup,
|
||||
|
||||
/// <summary>
|
||||
/// Content Item
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.ContentItem)]
|
||||
[FriendlyName("Content Item")]
|
||||
ContentItem,
|
||||
|
||||
/// <summary>
|
||||
/// "Media Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.MediaType, typeof(IMediaType))]
|
||||
[FriendlyName("Media Type")]
|
||||
MediaType,
|
||||
|
||||
/// <summary>
|
||||
/// Document Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.DocumentType, typeof(IContentType))]
|
||||
[FriendlyName("Document Type")]
|
||||
DocumentType,
|
||||
|
||||
/// <summary>
|
||||
/// Recycle Bin
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.ContentRecycleBin)]
|
||||
[FriendlyName("Recycle Bin")]
|
||||
RecycleBin,
|
||||
|
||||
/// <summary>
|
||||
/// Stylesheet
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Stylesheet)]
|
||||
[FriendlyName("Stylesheet")]
|
||||
Stylesheet,
|
||||
|
||||
/// <summary>
|
||||
/// Member
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.Member)]
|
||||
[FriendlyName("Member")]
|
||||
Member,
|
||||
|
||||
/// <summary>
|
||||
/// Data Type
|
||||
/// </summary>
|
||||
[UmbracoObjectTypeAttribute(Constants.ObjectTypes.DataType, typeof(IDataTypeDefinition))]
|
||||
[FriendlyName("Data Type")]
|
||||
DataType
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for the UmbracoObjectTypes enum
|
||||
/// </summary>
|
||||
public static class UmbracoObjectTypesExtensions
|
||||
{
|
||||
private static readonly Dictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new Dictionary<UmbracoObjectTypes,Guid>();
|
||||
|
||||
/// <summary>
|
||||
/// Get an UmbracoObjectTypes value from it's name
|
||||
/// </summary>
|
||||
/// <param name="name">Enum value name</param>
|
||||
/// <returns>an UmbracoObjectTypes Enum value</returns>
|
||||
public static UmbracoObjectTypes GetUmbracoObjectType(string name)
|
||||
{
|
||||
return (UmbracoObjectTypes)Enum.Parse(typeof(UmbracoObjectTypes), name, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an instance of an UmbracoObjectTypes enum value from it's GUID
|
||||
/// </summary>
|
||||
/// <param name="guid">Enum value GUID</param>
|
||||
/// <returns>an UmbracoObjectTypes Enum value</returns>
|
||||
public static UmbracoObjectTypes GetUmbracoObjectType(Guid guid)
|
||||
{
|
||||
var umbracoObjectType = UmbracoObjectTypes.Unknown;
|
||||
|
||||
foreach (var name in Enum.GetNames(typeof(UmbracoObjectTypes)))
|
||||
{
|
||||
if (GetUmbracoObjectType(name).GetGuid() == guid)
|
||||
{
|
||||
umbracoObjectType = GetUmbracoObjectType(name);
|
||||
}
|
||||
}
|
||||
|
||||
return umbracoObjectType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method for the UmbracoObjectTypes enum to return the enum GUID
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType">UmbracoObjectTypes Enum value</param>
|
||||
/// <returns>a GUID value of the UmbracoObjectTypes</returns>
|
||||
public static Guid GetGuid(this UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
if (UmbracoObjectTypeCache.ContainsKey(umbracoObjectType))
|
||||
return UmbracoObjectTypeCache[umbracoObjectType];
|
||||
|
||||
var type = typeof(UmbracoObjectTypes);
|
||||
var memInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
|
||||
false);
|
||||
|
||||
if (attributes.Length == 0)
|
||||
return Guid.Empty;
|
||||
|
||||
var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
|
||||
if (attribute == null)
|
||||
return Guid.Empty;
|
||||
|
||||
UmbracoObjectTypeCache.Add(umbracoObjectType, attribute.ObjectId);
|
||||
|
||||
return attribute.ObjectId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method for the UmbracoObjectTypes enum to return the enum name
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType">UmbracoObjectTypes value</param>
|
||||
/// <returns>The enum name of the UmbracoObjectTypes value</returns>
|
||||
public static string GetName(this UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
return Enum.GetName(typeof(UmbracoObjectTypes), umbracoObjectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method for the UmbracoObejctTypes enum to return the enum friendly name
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType">UmbracoObjectTypes value</param>
|
||||
/// <returns>a string of the FriendlyName</returns>
|
||||
public static string GetFriendlyName(this UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
var type = typeof(UmbracoObjectTypes);
|
||||
var memInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
|
||||
false);
|
||||
|
||||
if (attributes.Length == 0)
|
||||
return string.Empty;
|
||||
|
||||
var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
|
||||
if (attribute == null)
|
||||
return string.Empty;
|
||||
|
||||
return attribute.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,19 @@ namespace Umbraco.Core
|
||||
public static Attempt<T> TryConvertTo<T>(this object input)
|
||||
{
|
||||
var result = TryConvertTo(input, typeof(T));
|
||||
if (!result.Success)
|
||||
{
|
||||
//just try a straight up conversion
|
||||
try
|
||||
{
|
||||
var converted = (T) input;
|
||||
return new Attempt<T>(true, converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<T>(e);
|
||||
}
|
||||
}
|
||||
return !result.Success ? Attempt<T>.False : new Attempt<T>(true, (T)result.Result);
|
||||
}
|
||||
|
||||
@@ -72,11 +85,21 @@ namespace Umbraco.Core
|
||||
|
||||
if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable<>))
|
||||
{
|
||||
//TODO: Do a check for destination type being IEnumerable<T> and source type implementing IEnumerable<T> with
|
||||
// the same 'T', then we'd have to find the extension method for the type AsEnumerable() and execute it.
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom(destinationType, input.GetType())
|
||||
&& TypeHelper.IsTypeAssignableFrom<IConvertible>(input))
|
||||
{
|
||||
var casted = Convert.ChangeType(input, destinationType);
|
||||
return new Attempt<object>(true, casted);
|
||||
try
|
||||
{
|
||||
var casted = Convert.ChangeType(input, destinationType);
|
||||
return new Attempt<object>(true, casted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,11 +61,6 @@ namespace Umbraco.Core.ObjectResolution
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected override bool SupportsRemove
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private class LegacyStartupHandlerResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>
|
||||
{
|
||||
internal LegacyStartupHandlerResolver(IEnumerable<Type> legacyStartupHandlers)
|
||||
@@ -78,7 +73,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
get { return Values; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,124 +6,146 @@ using System.Web;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for lazily resolving types for a resolver
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver"></typeparam>
|
||||
/// <typeparam name="TResolved"></typeparam>
|
||||
/// <remarks>
|
||||
/// This is a special case resolver for when types get lazily resolved in order to resolve the actual types. This is useful
|
||||
/// for when there is some processing overhead (i.e. Type finding in assemblies) to return the Types used to instantiate the instances.
|
||||
/// In some these cases we don't want to have to type find during application startup, only when we need to resolve the instances.
|
||||
///
|
||||
/// Important notes about this resolver: This does not support Insert or Remove and therefore does not support any ordering unless
|
||||
/// the types are marked with the WeightedPluginAttribute.
|
||||
/// <summary>
|
||||
/// The base class for all lazy many-objects resolvers.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
|
||||
/// <typeparam name="TResolved">The type of the resolved objects.</typeparam>
|
||||
/// <remarks>
|
||||
/// <para>This is a special case resolver for when types get lazily resolved in order to resolve the actual types. This is useful
|
||||
/// for when there is some processing overhead (i.e. Type finding in assemblies) to return the Types used to instantiate the instances.
|
||||
/// In some these cases we don't want to have to type-find during application startup, only when we need to resolve the instances.</para>
|
||||
/// <para>Important notes about this resolver: it does not support Insert or Remove and therefore does not support any ordering unless
|
||||
/// the types are marked with the WeightedPluginAttribute.</para>
|
||||
/// </remarks>
|
||||
internal abstract class LazyManyObjectsResolverBase<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
where TResolver : ResolverBase
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
|
||||
/// with creation of objects based on an HttpRequest lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
|
||||
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
||||
protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: base(scope)
|
||||
{
|
||||
}
|
||||
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
|
||||
/// with creation of objects based on an HttpRequest lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext)
|
||||
: base(httpContext)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a list of lazy types
|
||||
/// </summary>
|
||||
/// <param name="listOfLazyTypes"></param>
|
||||
/// <param name="scope"></param>
|
||||
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> listOfLazyTypes, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list
|
||||
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
||||
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> lazyTypeList, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
AddTypes(listOfLazyTypes);
|
||||
AddTypes(lazyTypeList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a delegate to return a list of types
|
||||
/// </summary>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
/// <param name="scope"></param>
|
||||
protected LazyManyObjectsResolverBase(Func<IEnumerable<Type>> typeListDelegate, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list
|
||||
/// of functions producing types, and an optional lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="typeListProducerList">The list of functions producing types.</param>
|
||||
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
|
||||
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
||||
protected LazyManyObjectsResolverBase(Func<IEnumerable<Type>> typeListProducerList, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
_typeListProducerList.Add(typeListProducerList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a list of lazy types
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="listOfLazyTypes"></param>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Lazy<Type>> listOfLazyTypes)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of
|
||||
/// lazy object types, with creation of objects based on an HttpRequest lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
||||
/// <param name="lazyTypeList">The list of lazy object types.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Lazy<Type>> lazyTypeList)
|
||||
: this(httpContext)
|
||||
{
|
||||
AddTypes(listOfLazyTypes);
|
||||
AddTypes(lazyTypeList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a delegate to return a list of types
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func<IEnumerable<Type>> typeListDelegate)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of
|
||||
/// functions producing types, with creation of objects based on an HttpRequest lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
||||
/// <param name="typeListProducerList">The list of functions producing types.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func<IEnumerable<Type>> typeListProducerList)
|
||||
: this(httpContext)
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
_typeListProducerList.Add(typeListProducerList);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly List<Lazy<Type>> _lazyTypeList = new List<Lazy<Type>>();
|
||||
private readonly List<Func<IEnumerable<Type>>> _listOfTypeListDelegates = new List<Func<IEnumerable<Type>>>();
|
||||
private readonly List<Func<IEnumerable<Type>>> _typeListProducerList = new List<Func<IEnumerable<Type>>>();
|
||||
private readonly List<Type> _excludedTypesList = new List<Type>();
|
||||
|
||||
private List<Type> _resolvedTypes = null;
|
||||
private readonly ReaderWriterLockSlim _typeResolutionLock = new ReaderWriterLockSlim();
|
||||
private readonly ReaderWriterLockSlim _resolvedTypesLock = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Used for unit tests
|
||||
/// Gets a value indicating whether the resolver has resolved types to create instances from.
|
||||
/// </summary>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal bool HasResolvedTypes
|
||||
{
|
||||
get { return _resolvedTypes != null; }
|
||||
get
|
||||
{
|
||||
using (new ReadLock(_resolvedTypesLock))
|
||||
{
|
||||
return _resolvedTypes != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Once this is called this will resolve all types registered in the lazy list
|
||||
/// </summary>
|
||||
protected override IEnumerable<Type> InstanceTypes
|
||||
/// <summary>
|
||||
/// Gets the list of types to create instances from.
|
||||
/// </summary>
|
||||
/// <remarks>When called, will get the types from the lazy list.</remarks>
|
||||
protected override IEnumerable<Type> InstanceTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
using (var lck = new UpgradeableReadLock(_typeResolutionLock))
|
||||
using (var lck = new UpgradeableReadLock(_resolvedTypesLock))
|
||||
{
|
||||
var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray();
|
||||
var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray();
|
||||
|
||||
//we need to validate each resolved type now since we could not do it before when inserting the lazy delegates
|
||||
if (!HasResolvedTypes)
|
||||
if (_resolvedTypes == null)
|
||||
{
|
||||
lck.UpgradeToWriteLock();
|
||||
lck.UpgradeToWriteLock();
|
||||
|
||||
_resolvedTypes = new List<Type>();
|
||||
_resolvedTypes = new List<Type>();
|
||||
|
||||
//first iterate the lazy type list
|
||||
foreach (var l in lazyTypeList)
|
||||
{
|
||||
UpdateUniqueList(_resolvedTypes, l);
|
||||
}
|
||||
|
||||
//next iterate the list of list type delegates
|
||||
foreach (var l in listofTypeListDelegates)
|
||||
{
|
||||
UpdateUniqueList(_resolvedTypes, l);
|
||||
}
|
||||
// get the types by evaluating the lazy & producers
|
||||
var types = new List<Type>();
|
||||
types.AddRange(_lazyTypeList.Select(x => x.Value));
|
||||
types.AddRange(_typeListProducerList.SelectMany(x => x()));
|
||||
|
||||
// we need to validate each resolved type now since we could
|
||||
// not do it before evaluating the lazy & producers
|
||||
foreach (var type in types.Where(x => !_excludedTypesList.Contains(x)))
|
||||
{
|
||||
AddValidAndNoDuplicate(_resolvedTypes, type);
|
||||
}
|
||||
}
|
||||
|
||||
return _resolvedTypes;
|
||||
@@ -131,27 +153,46 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateUniqueList(List<Type> uniqueList, Type toAdd)
|
||||
/// <summary>
|
||||
/// Ensures that type is valid and not a duplicate
|
||||
/// then appends the type to the end of the list
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="type"></param>
|
||||
private void AddValidAndNoDuplicate(List<Type> list, Type type)
|
||||
{
|
||||
EnsureCorrectType(toAdd);
|
||||
if (uniqueList.Contains(toAdd))
|
||||
EnsureCorrectType(type);
|
||||
if (list.Contains(type))
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + toAdd + " already exists in the collection");
|
||||
}
|
||||
uniqueList.Add(toAdd);
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", type.FullName));
|
||||
}
|
||||
list.Add(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows adding of multiple lazy types at once
|
||||
#region Types collection manipulation
|
||||
|
||||
/// <summary>
|
||||
/// Removes types from the list of types, once it has been lazily evaluated, and before actual objects are instanciated.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to remove.</param>
|
||||
public override void RemoveType(Type value)
|
||||
{
|
||||
EnsureSupportsRemove();
|
||||
|
||||
_excludedTypesList.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lazily adds types from lazy types.
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
/// <param name="types">The lazy types, to add.</param>
|
||||
protected void AddTypes(IEnumerable<Lazy<Type>> types)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
EnsureSupportsAdd();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (GetWriteLock())
|
||||
{
|
||||
foreach (var t in types)
|
||||
{
|
||||
@@ -161,41 +202,40 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a type list delegate to the collection
|
||||
/// Lazily adds types from a function producing types.
|
||||
/// </summary>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
public void AddTypeListDelegate(Func<IEnumerable<Type>> typeListDelegate)
|
||||
/// <param name="typeListProducer">The functions producing types, to add.</param>
|
||||
public void AddTypeListDelegate(Func<IEnumerable<Type>> typeListProducer)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
EnsureSupportsAdd();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
_typeListProducerList.Add(typeListProducer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a lazy type to the list
|
||||
/// Lazily adds a type from a lazy type.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="value">The lazy type, to add.</param>
|
||||
public void AddType(Lazy<Type> value)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
EnsureSupportsAdd();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_lazyTypeList.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the static type added to a lazy type and adds it to the internal list
|
||||
/// Lazily adds a type from an actual type.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="value">The actual type, to add.</param>
|
||||
/// <remarks>The type is converted to a lazy type.</remarks>
|
||||
public override void AddType(Type value)
|
||||
{
|
||||
AddType(new Lazy<Type>(() => value));
|
||||
@@ -206,30 +246,27 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
EnsureClearSupport();
|
||||
EnsureSupportsClear();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_lazyTypeList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does not support removal
|
||||
/// </summary>
|
||||
protected override bool SupportsRemove
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Types collection manipulation support
|
||||
|
||||
/// <summary>
|
||||
/// Does not support insert
|
||||
/// Gets a <c>false</c> value indicating that the resolver does NOT support inserting types.
|
||||
/// </summary>
|
||||
protected override bool SupportsInsert
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,10 @@ using System.Threading;
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A base resolver used for old legacy factories such as the DataTypeFactory or CacheResolverFactory.
|
||||
/// The base class for old legacy factories such as the DataTypeFactory or CacheResolverFactory.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver"></typeparam>
|
||||
/// <typeparam name="TResolved"> </typeparam>
|
||||
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
|
||||
/// <typeparam name="TResolved">The type of the resolved objects.</typeparam>
|
||||
/// <remarks>
|
||||
/// This class contains basic functionality to mimic the functionality in these old factories since they all return
|
||||
/// transient objects (though this should be changed) and the method GetById needs to lookup a type to an ID and since
|
||||
@@ -19,67 +19,67 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </remarks>
|
||||
internal abstract class LegacyTransientObjectsResolver<TResolver, TResolved> : LazyManyObjectsResolverBase<TResolver, TResolved>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
where TResolver : ResolverBase
|
||||
{
|
||||
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
private ConcurrentDictionary<Guid, Type> _id2type;
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// Initializes a new instance of the <see cref="LegacyTransientObjectsResolver{TResolver, TResolved}"/> class with an initial list of object types.
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
/// <param name="value">A function returning the list of object types.</param>
|
||||
/// <remarks>
|
||||
/// We are creating Transient instances (new instances each time) because this is how the legacy code worked and
|
||||
/// I don't want to muck anything up by changing them to application based instances.
|
||||
/// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier.
|
||||
/// </remarks>
|
||||
protected LegacyTransientObjectsResolver(Func<IEnumerable<Type>> types)
|
||||
: base(types, ObjectLifetimeScope.Transient) // new objects every time
|
||||
{
|
||||
}
|
||||
protected LegacyTransientObjectsResolver(Func<IEnumerable<Type>> value)
|
||||
: base(value, ObjectLifetimeScope.Transient) // new objects every time
|
||||
{ }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Maintains a list of Ids and their types when first call to CacheResolvers or GetById occurs, this is used
|
||||
/// in order to return a single object by id without instantiating the entire type stack.
|
||||
/// Returns the unique identifier of the type of a specified object.
|
||||
/// </summary>
|
||||
private ConcurrentDictionary<Guid, Type> _trackIdToType;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
/// <param name="value">The object.</param>
|
||||
/// <returns>The unique identifier of the type of <paramref name="value"/>.</returns>
|
||||
protected abstract Guid GetUniqueIdentifier(TResolved value);
|
||||
|
||||
/// <summary>
|
||||
/// method to return the unique id for type T
|
||||
/// Returns a new instance for the type identified by its unique type identifier.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract Guid GetUniqueIdentifier(TResolved obj);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new TResolved instance by id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="id">The type identifier.</param>
|
||||
/// <returns>The value of the type uniquely identified by <paramref name="id"/>.</returns>
|
||||
public TResolved GetById(Guid id)
|
||||
{
|
||||
EnsureIdsAreTracked();
|
||||
return !_trackIdToType.ContainsKey(id)
|
||||
EnsureIsInitialized();
|
||||
return !_id2type.ContainsKey(id)
|
||||
? null
|
||||
: PluginManager.Current.CreateInstance<TResolved>(_trackIdToType[id]);
|
||||
: PluginManager.Current.CreateInstance<TResolved>(_id2type[id]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the ids -> Type dictionary to allow us to instantiate a type by Id since these legacy types doesn't contain any metadata
|
||||
/// Populates the identifiers-to-types dictionnary.
|
||||
/// </summary>
|
||||
protected void EnsureIdsAreTracked()
|
||||
/// <remarks>
|
||||
/// <para>This allow us to instantiate a type by ID since these legacy types doesn't contain any metadata.</para>
|
||||
/// <para>We instanciate all types once to get their unique identifier, then build the dictionary so that
|
||||
/// when GetById is called, we can instanciate a single object.</para>
|
||||
/// </remarks>
|
||||
protected void EnsureIsInitialized()
|
||||
{
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
if (_trackIdToType == null)
|
||||
if (_id2type == null)
|
||||
{
|
||||
l.UpgradeToWriteLock();
|
||||
_trackIdToType = new ConcurrentDictionary<Guid, Type>();
|
||||
foreach (var v in Values)
|
||||
|
||||
_id2type = new ConcurrentDictionary<Guid, Type>();
|
||||
foreach (var value in Values)
|
||||
{
|
||||
_trackIdToType.TryAdd(GetUniqueIdentifier(v), v.GetType());
|
||||
_id2type.TryAdd(GetUniqueIdentifier(value), value.GetType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,82 +6,102 @@ using System.Web;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
internal abstract class ManyObjectsResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
/// <summary>
|
||||
/// The base class for all many-objects resolvers.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
|
||||
/// <typeparam name="TResolved">The type of the resolved objects.</typeparam>
|
||||
public abstract class ManyObjectsResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
||||
where TResolved : class
|
||||
where TResolver : ResolverBase
|
||||
{
|
||||
private List<TResolved> _applicationInstances = null;
|
||||
private IEnumerable<TResolved> _applicationInstances = null;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
private readonly List<Type> _instanceTypes = new List<Type>();
|
||||
private readonly string _httpContextKey;
|
||||
private readonly List<Type> _instanceTypes = new List<Type>();
|
||||
private IEnumerable<TResolved> _sortedValues = null;
|
||||
|
||||
private int _defaultPluginWeight = 10;
|
||||
|
||||
#region Constructors
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects.
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
|
||||
/// and an optional lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application</param>
|
||||
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
|
||||
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
||||
protected ManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
{
|
||||
CanResolveBeforeFrozen = false;
|
||||
if (scope == ObjectLifetimeScope.HttpRequest)
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
{
|
||||
throw new InvalidOperationException("Use alternative constructor accepting a HttpContextBase object in order to set the lifetime scope to HttpRequest when HttpContext.Current is null");
|
||||
}
|
||||
|
||||
CurrentHttpContext = new HttpContextWrapper(HttpContext.Current);
|
||||
}
|
||||
|
||||
LifetimeScope = scope;
|
||||
if (scope == ObjectLifetimeScope.HttpRequest)
|
||||
_httpContextKey = this.GetType().FullName;
|
||||
_instanceTypes = new List<Type>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects.
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an empty list of objects,
|
||||
/// with creation of objects based on an HttpRequest lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
||||
protected ManyObjectsResolverBase(HttpContextBase httpContext)
|
||||
{
|
||||
CanResolveBeforeFrozen = false;
|
||||
if (httpContext == null) throw new ArgumentNullException("httpContext");
|
||||
if (httpContext == null)
|
||||
throw new ArgumentNullException("httpContext");
|
||||
LifetimeScope = ObjectLifetimeScope.HttpRequest;
|
||||
_httpContextKey = this.GetType().FullName;
|
||||
CurrentHttpContext = httpContext;
|
||||
_instanceTypes = new List<Type>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of objects.
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of object types,
|
||||
/// and an optional lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="value">The list of objects.</param>
|
||||
/// <param name="scope">If set to true will resolve singleton objects which will be created once for the lifetime of the application</param>
|
||||
/// <param name="value">The list of object types.</param>
|
||||
/// <param name="scope">The lifetime scope of instantiated objects, default is per Application.</param>
|
||||
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
||||
protected ManyObjectsResolverBase(IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
_instanceTypes = new List<Type>(value);
|
||||
_instanceTypes = value.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of objects
|
||||
/// Initializes a new instance of the <see cref="ManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list of objects,
|
||||
/// with creation of objects based on an HttpRequest lifetime scope.
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="httpContext">The HttpContextBase corresponding to the HttpRequest.</param>
|
||||
/// <param name="value">The list of object types.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="httpContext"/> is <c>null</c>.</exception>
|
||||
protected ManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Type> value)
|
||||
: this(httpContext)
|
||||
{
|
||||
_instanceTypes = new List<Type>(value);
|
||||
_instanceTypes = value.ToList();
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// used internally for special resolvers to be able to resolve objects before resolution is frozen.
|
||||
/// Gets or sets a value indicating whether the resolver can resolve objects before resolution is frozen.
|
||||
/// </summary>
|
||||
/// <remarks>This is false by default and is used for some special internal resolvers.</remarks>
|
||||
internal bool CanResolveBeforeFrozen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the list of Types registered that instances will be created from
|
||||
/// Gets the list of types to create instances from.
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<Type> InstanceTypes
|
||||
{
|
||||
@@ -89,114 +109,137 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Current HttpContextBase used to construct this object if one exists.
|
||||
/// If one exists then the LifetimeScope will be ObjectLifetimeScope.HttpRequest
|
||||
/// Gets or sets the <see cref="HttpContextBase"/> used to initialize this object, if any.
|
||||
/// </summary>
|
||||
/// <remarks>If not null, then <c>LifetimeScope</c> will be <c>ObjectLifetimeScope.HttpRequest</c>.</remarks>
|
||||
protected HttpContextBase CurrentHttpContext { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ObjectLifetimeScope for created objects
|
||||
/// Gets or sets the lifetime scope of resolved objects.
|
||||
/// </summary>
|
||||
protected ObjectLifetimeScope LifetimeScope { get; private set; }
|
||||
|
||||
private int _defaultPluginWeight = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Used in conjunction with GetSortedValues and WeightedPluginAttribute, if any of the objects
|
||||
/// being resolved do not contain the WeightedPluginAttribute then this will be the default weight applied
|
||||
/// to the object.
|
||||
/// Gets the resolved object instances, sorted by weight.
|
||||
/// </summary>
|
||||
/// <returns>The sorted resolved object instances.</returns>
|
||||
/// <remarks>
|
||||
/// <para>The order is based upon the <c>WeightedPluginAttribute</c> and <c>DefaultPluginWeight</c>.</para>
|
||||
/// <para>Weights are sorted ascendingly (lowest weights come first).</para>
|
||||
/// </remarks>
|
||||
protected IEnumerable<TResolved> GetSortedValues()
|
||||
{
|
||||
if (_sortedValues == null)
|
||||
{
|
||||
var values = Values.ToList();
|
||||
values.Sort((f1, f2) => GetObjectWeight(f1).CompareTo(GetObjectWeight(f2)));
|
||||
_sortedValues = values;
|
||||
}
|
||||
return _sortedValues;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default type weight.
|
||||
/// </summary>
|
||||
/// <remarks>Determines the weight of types that do not have a <c>WeightedPluginAttribute</c> set on
|
||||
/// them, when calling <c>GetSortedValues</c>.</remarks>
|
||||
protected virtual int DefaultPluginWeight
|
||||
{
|
||||
get { return _defaultPluginWeight; }
|
||||
set { _defaultPluginWeight = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If a resolver requries that objects are resolved with a specific order using the WeightedPluginAttribute
|
||||
/// then this method should be used instead of the Values property.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected IEnumerable<TResolved> GetSortedValues()
|
||||
/// <summary>
|
||||
/// Returns the weight of an object for user with GetSortedValues
|
||||
/// </summary>
|
||||
/// <param name="o"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual int GetObjectWeight(object o)
|
||||
{
|
||||
var vals = Values.ToList();
|
||||
//ensure they are sorted
|
||||
vals.Sort((f1, f2) =>
|
||||
{
|
||||
Func<object, int> getWeight = o =>
|
||||
{
|
||||
var weightAttribute = f1.GetType().GetCustomAttribute<WeightedPluginAttribute>(true);
|
||||
return weightAttribute != null ? weightAttribute.Weight : DefaultPluginWeight;
|
||||
};
|
||||
return getWeight(f1).CompareTo(getWeight(f2));
|
||||
});
|
||||
return vals;
|
||||
}
|
||||
var type = o.GetType();
|
||||
var attr = type.GetCustomAttribute<WeightedPluginAttribute>(true);
|
||||
return attr == null ? DefaultPluginWeight : attr.Weight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the list of new object instances.
|
||||
/// Gets the resolved object instances.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"><c>CanResolveBeforeFrozen</c> is false, and resolution is not frozen.</exception>
|
||||
protected IEnumerable<TResolved> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
//We cannot return values unless resolution is locked
|
||||
if (!CanResolveBeforeFrozen && !Resolution.IsFrozen)
|
||||
throw new InvalidOperationException("Values cannot be returned until Resolution is frozen");
|
||||
{
|
||||
// ensure we can
|
||||
if (!CanResolveBeforeFrozen)
|
||||
Resolution.EnsureIsFrozen();
|
||||
|
||||
// note: we apply .ToArray() to the output of CreateInstance() because that is an IEnumerable that
|
||||
// comes from the PluginManager we want to be _sure_ that it's not a Linq of some sort, but the
|
||||
// instances have actually been instanciated when we return.
|
||||
|
||||
switch (LifetimeScope)
|
||||
{
|
||||
case ObjectLifetimeScope.HttpRequest:
|
||||
//create new instances per HttpContext, this means we'll lazily create them and once created, cache them in the HttpContext
|
||||
//create new instances per application, this means we'll lazily create them and once created, cache them
|
||||
// create new instances per HttpContext
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
//check if the items contain the key (based on the full type name)
|
||||
if (CurrentHttpContext.Items[this.GetType().FullName] == null)
|
||||
// create if not already there
|
||||
if (CurrentHttpContext.Items[_httpContextKey] == null)
|
||||
{
|
||||
l.UpgradeToWriteLock();
|
||||
//add the items to the context items (based on full type name)
|
||||
CurrentHttpContext.Items[this.GetType().FullName] = new List<TResolved>(CreateInstances());
|
||||
CurrentHttpContext.Items[_httpContextKey] = CreateInstances().ToArray();
|
||||
}
|
||||
return (List<TResolved>)CurrentHttpContext.Items[this.GetType().FullName];
|
||||
return (TResolved[])CurrentHttpContext.Items[_httpContextKey];
|
||||
}
|
||||
|
||||
case ObjectLifetimeScope.Application:
|
||||
//create new instances per application, this means we'll lazily create them and once created, cache them
|
||||
// create new instances per application
|
||||
using(var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
// create if not already there
|
||||
if (_applicationInstances == null)
|
||||
{
|
||||
l.UpgradeToWriteLock();
|
||||
_applicationInstances = new List<TResolved>(CreateInstances());
|
||||
_applicationInstances = CreateInstances().ToArray();
|
||||
}
|
||||
return _applicationInstances;
|
||||
}
|
||||
|
||||
case ObjectLifetimeScope.Transient:
|
||||
default:
|
||||
//create new instances each time
|
||||
return CreateInstances();
|
||||
// create new instances each time
|
||||
return CreateInstances().ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the object instances for the types contained in the types collection.
|
||||
/// </summary>
|
||||
/// <returns>A list of objects of type <typeparamref name="TResolved"/>.</returns>
|
||||
protected virtual IEnumerable<TResolved> CreateInstances()
|
||||
{
|
||||
return PluginManager.Current.CreateInstances<TResolved>(InstanceTypes);
|
||||
}
|
||||
}
|
||||
|
||||
#region Types collection manipulation
|
||||
|
||||
/// <summary>
|
||||
/// Removes a type.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to remove.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
|
||||
/// the type is not a valid type for the resolver.</exception>
|
||||
public virtual void RemoveType(Type value)
|
||||
{
|
||||
EnsureRemoveSupport();
|
||||
EnsureSupportsRemove();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_instanceTypes.Remove(value);
|
||||
}
|
||||
}
|
||||
@@ -204,114 +247,231 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Removes a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="T">The type to remove.</typeparam>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
|
||||
/// the type is not a valid type for the resolver.</exception>
|
||||
public void RemoveType<T>()
|
||||
where T : TResolved
|
||||
{
|
||||
RemoveType(typeof (T));
|
||||
RemoveType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// protected method allow the inheritor to add many types at once
|
||||
/// Adds types.
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
/// <param name="types">The types to add.</param>
|
||||
/// <remarks>The types are appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// a type is not a valid type for the resolver, or a type is already in the collection of types.</exception>
|
||||
protected void AddTypes(IEnumerable<Type> types)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
EnsureSupportsAdd();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (new WriteLock(_lock))
|
||||
{
|
||||
foreach(var t in types)
|
||||
{
|
||||
EnsureCorrectType(t);
|
||||
if (InstanceTypes.Contains(t))
|
||||
if (_instanceTypes.Contains(t))
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + t + " already exists in the collection");
|
||||
};
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", t.FullName));
|
||||
}
|
||||
_instanceTypes.Add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a Type to the end of the list.
|
||||
/// Adds a type.
|
||||
/// </summary>
|
||||
/// <param name="value">The object to be added.</param>
|
||||
/// <param name="value">The type to add.</param>
|
||||
/// <remarks>The type is appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public virtual void AddType(Type value)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
EnsureSupportsAdd();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
if (InstanceTypes.Contains(value))
|
||||
if (_instanceTypes.Contains(value))
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
|
||||
};
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", value.FullName));
|
||||
}
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_instanceTypes.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a Type to the end of the list.
|
||||
/// Adds a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="T">The type to add.</typeparam>
|
||||
/// <remarks>The type is appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public void AddType<T>()
|
||||
where T : TResolved
|
||||
{
|
||||
AddType(typeof (T));
|
||||
AddType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the list.
|
||||
/// Clears the list of types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support clearing types.</exception>
|
||||
public virtual void Clear()
|
||||
{
|
||||
EnsureClearSupport();
|
||||
EnsureSupportsClear();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (new WriteLock(_lock))
|
||||
{
|
||||
_instanceTypes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a Type at the specified index.
|
||||
/// Inserts a type at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index at which the object should be inserted.</param>
|
||||
/// <param name="value">The object to insert.</param>
|
||||
/// <param name="index">The zero-based index at which the type should be inserted.</param>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
|
||||
public virtual void InsertType(int index, Type value)
|
||||
{
|
||||
EnsureInsertSupport();
|
||||
EnsureSupportsInsert();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (var l = GetWriteLock())
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
if (InstanceTypes.Contains(value))
|
||||
if (_instanceTypes.Contains(value))
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
|
||||
};
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", value.FullName));
|
||||
}
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_instanceTypes.Insert(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type at the beginning of the list.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public virtual void InsertType(Type value)
|
||||
{
|
||||
InsertType(0, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type at the specified index.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to insert.</typeparam>
|
||||
/// <param name="index">The zero-based index at which the type should be inserted.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
|
||||
public void InsertType<T>(int index)
|
||||
where T : TResolved
|
||||
{
|
||||
InsertType(index, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type at the beginning of the list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to insert.</typeparam>
|
||||
public void InsertType<T>()
|
||||
where T : TResolved
|
||||
{
|
||||
InsertType(0, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a type before a specified, already existing type.
|
||||
/// </summary>
|
||||
/// <param name="existingType">The existing type before which to insert.</param>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
|
||||
/// or the new type is already in the collection of types.</exception>
|
||||
public virtual void InsertTypeBefore(Type existingType, Type value)
|
||||
{
|
||||
EnsureSupportsInsert();
|
||||
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
EnsureCorrectType(existingType);
|
||||
EnsureCorrectType(value);
|
||||
if (!_instanceTypes.Contains(existingType))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is not in the collection of types.", existingType.FullName));
|
||||
}
|
||||
if (_instanceTypes.Contains(value))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is already in the collection of types.", value.FullName));
|
||||
}
|
||||
int index = _instanceTypes.IndexOf(existingType);
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_instanceTypes.Insert(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a Type at the specified index.
|
||||
/// Inserts a type before a specified, already existing type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="index"></param>
|
||||
public void InsertType<T>(int index)
|
||||
/// <typeparam name="TExisting">The existing type before which to insert.</typeparam>
|
||||
/// <typeparam name="T">The type to insert.</typeparam>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
|
||||
/// or the new type is already in the collection of types.</exception>
|
||||
public void InsertTypeBefore<TExisting, T>()
|
||||
where TExisting : TResolved
|
||||
where T : TResolved
|
||||
{
|
||||
InsertType(index, typeof (T));
|
||||
InsertTypeBefore(typeof(TExisting), typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified type is already in the collection of types.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to look for.</param>
|
||||
/// <returns>A value indicating whether the type is already in the collection of types.</returns>
|
||||
public virtual bool ContainsType(Type value)
|
||||
{
|
||||
using (new ReadLock(_lock))
|
||||
{
|
||||
return _instanceTypes.Contains(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the specified type is already in the collection of types.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to look for.</typeparam>
|
||||
/// <returns>A value indicating whether the type is already in the collection of types.</returns>
|
||||
public bool ContainsType<T>()
|
||||
where T : TResolved
|
||||
{
|
||||
return ContainsType(typeof(T));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns a WriteLock to use when modifying collections
|
||||
/// </summary>
|
||||
@@ -320,80 +480,96 @@ namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
return new WriteLock(_lock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if resolution is frozen
|
||||
/// </summary>
|
||||
protected void EnsureResolutionNotFrozen()
|
||||
{
|
||||
if (Resolution.IsFrozen)
|
||||
throw new InvalidOperationException("The type list cannot be modified after resolution has been frozen");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Remove
|
||||
/// </summary>
|
||||
protected void EnsureRemoveSupport()
|
||||
#region Type utilities
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that a type is a valid type for the resolver.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to test.</param>
|
||||
/// <exception cref="InvalidOperationException">the type is not a valid type for the resolver.</exception>
|
||||
protected void EnsureCorrectType(Type value)
|
||||
{
|
||||
if (!TypeHelper.IsTypeAssignableFrom<TResolved>(value))
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Type {0} is not an acceptable type for resolver {1}.", value.FullName, this.GetType().FullName));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Types collection manipulation support
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the resolver supports removing types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The resolver does not support removing types.</exception>
|
||||
protected void EnsureSupportsRemove()
|
||||
{
|
||||
if (!SupportsRemove)
|
||||
throw new InvalidOperationException("This resolver does not support Removing types");
|
||||
throw new InvalidOperationException("This resolver does not support removing types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Clear
|
||||
/// </summary>
|
||||
protected void EnsureClearSupport()
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures that the resolver supports clearing types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The resolver does not support clearing types.</exception>
|
||||
protected void EnsureSupportsClear() {
|
||||
if (!SupportsClear)
|
||||
throw new InvalidOperationException("This resolver does not support Clearing types");
|
||||
throw new InvalidOperationException("This resolver does not support clearing types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Add
|
||||
/// </summary>
|
||||
protected void EnsureAddSupport()
|
||||
/// <summary>
|
||||
/// Ensures that the resolver supports adding types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The resolver does not support adding types.</exception>
|
||||
protected void EnsureSupportsAdd()
|
||||
{
|
||||
if (!SupportsAdd)
|
||||
throw new InvalidOperationException("This resolver does not support Adding new types");
|
||||
throw new InvalidOperationException("This resolver does not support adding new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support insert
|
||||
/// </summary>
|
||||
protected void EnsureInsertSupport()
|
||||
/// <summary>
|
||||
/// Ensures that the resolver supports inserting types.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">The resolver does not support inserting types.</exception>
|
||||
protected void EnsureSupportsInsert()
|
||||
{
|
||||
if (!SupportsInsert)
|
||||
throw new InvalidOperationException("This resolver does not support Inserting new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if the type is not of the TResolved type
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
protected void EnsureCorrectType(Type t)
|
||||
{
|
||||
if (!TypeHelper.IsTypeAssignableFrom<TResolved>(t))
|
||||
throw new InvalidOperationException("The resolver " + this.GetType() + " can only accept types of " + typeof(TResolved) + ". The Type passed in to this method is " + t);
|
||||
throw new InvalidOperationException("This resolver does not support inserting new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolver supports adding types.
|
||||
/// </summary>
|
||||
protected virtual bool SupportsAdd
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsInsert
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolver supports inserting types.
|
||||
/// </summary>
|
||||
protected virtual bool SupportsInsert
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsClear
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolver supports clearing types.
|
||||
/// </summary>
|
||||
protected virtual bool SupportsClear
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsRemove
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolver supports removing types.
|
||||
/// </summary>
|
||||
protected virtual bool SupportsRemove
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,23 @@
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
internal enum ObjectLifetimeScope
|
||||
/// <summary>
|
||||
/// Specifies the lifetime scope of resolved objects.
|
||||
/// </summary>
|
||||
public enum ObjectLifetimeScope
|
||||
{
|
||||
/// <summary>
|
||||
/// A per-request object instance is created.
|
||||
/// </summary>
|
||||
HttpRequest,
|
||||
|
||||
/// <summary>
|
||||
/// A single application-wide object instance is created.
|
||||
/// </summary>
|
||||
Application,
|
||||
|
||||
/// <summary>
|
||||
/// A new object instance is created each time one is requested.
|
||||
/// </summary>
|
||||
Transient
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,93 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
|
||||
|
||||
|
||||
// notes: nothing in Resolving is thread-safe because everything should happen when the app is starting
|
||||
|
||||
internal class Resolution
|
||||
/// <summary>
|
||||
/// Represents the status of objects resolution.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Before resolution is frozen it is possible to access its configuration, but not to get values.</para>
|
||||
/// <para>Once resolution is frozen, it is not possible to access its configuration anymore, but it is possible to get values.</para>
|
||||
/// </remarks>
|
||||
internal static class Resolution
|
||||
{
|
||||
private static readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when resolution is frozen.
|
||||
/// </summary>
|
||||
/// <remarks>Occurs only once, since resolution can be frozen only once.</remarks>
|
||||
public static event EventHandler Frozen;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating that resolution is frozen
|
||||
/// Gets or sets a value indicating whether resolution of objects is frozen.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The internal setter is normally used for unit tests
|
||||
/// </remarks>
|
||||
public static bool IsFrozen { get; internal set; }
|
||||
public static bool IsFrozen { get; private set; }
|
||||
|
||||
public static void EnsureNotFrozen()
|
||||
public static void EnsureIsFrozen()
|
||||
{
|
||||
if (Resolution.IsFrozen)
|
||||
throw new InvalidOperationException("Resolution is frozen. It is not possible to modify resolvers once resolution is frozen.");
|
||||
if (!IsFrozen)
|
||||
throw new InvalidOperationException("Resolution is not frozen, it is not yet possible to get values from it.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a disposable object that represents safe access to unfrozen resolution configuration.
|
||||
/// </summary>
|
||||
/// <remarks>Should be used in a <c>using(Resolution.Configuration) { ... }</c> mode.</remarks>
|
||||
public static IDisposable Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
IDisposable l = new WriteLock(_lock);
|
||||
if (Resolution.IsFrozen)
|
||||
{
|
||||
l.Dispose();
|
||||
throw new InvalidOperationException("Resolution is frozen, it is not possible to configure it anymore.");
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a disposable object that reprents dirty access to temporarily unfrozen resolution configuration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Should not be used.</para>
|
||||
/// <para>Should be used in a <c>using(Resolution.DirtyBackdoorToConfiguration) { ... }</c> mode.</para>
|
||||
/// <para>Because we just lift the frozen state, and we don't actually re-freeze, the <c>Frozen</c> event does not trigger.</para>
|
||||
/// </remarks>
|
||||
internal static IDisposable DirtyBackdoorToConfiguration
|
||||
{
|
||||
get { return new DirtyBackdoor(); }
|
||||
}
|
||||
|
||||
// keep the class here because it needs write-access to Resolution.IsFrozen
|
||||
private class DirtyBackdoor : IDisposable
|
||||
{
|
||||
private static readonly System.Threading.ReaderWriterLockSlim _dirtyLock = new ReaderWriterLockSlim();
|
||||
|
||||
private IDisposable _lock;
|
||||
private bool _frozen;
|
||||
|
||||
public DirtyBackdoor()
|
||||
{
|
||||
_lock = new WriteLock(_dirtyLock);
|
||||
_frozen = Resolution.IsFrozen;
|
||||
Resolution.IsFrozen = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Resolution.IsFrozen = _frozen;
|
||||
_lock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freezes resolution.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">resolution is already frozen.</exception>
|
||||
public static void Freeze()
|
||||
{
|
||||
if (Resolution.IsFrozen)
|
||||
@@ -34,5 +97,15 @@ namespace Umbraco.Core.ObjectResolution
|
||||
if (Frozen != null)
|
||||
Frozen(null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets resolution, ie unfreezes it and clears Frozen event.
|
||||
/// </summary>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal static void Reset()
|
||||
{
|
||||
IsFrozen = false;
|
||||
Frozen = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,24 +3,57 @@ using System.Threading;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// base class for resolvers which declare a singleton accessor
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver"></typeparam>
|
||||
internal abstract class ResolverBase<TResolver>
|
||||
where TResolver : class
|
||||
{
|
||||
static TResolver _resolver;
|
||||
|
||||
/// <summary>
|
||||
/// The lock for the singleton
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Though resharper says this is in error, it is actually correct. We want a different lock object for each generic type.
|
||||
/// See this for details: http://confluence.jetbrains.net/display/ReSharper/Static+field+in+generic+type
|
||||
/// </remarks>
|
||||
static readonly ReaderWriterLockSlim ResolversLock = new ReaderWriterLockSlim();
|
||||
/// <summary>
|
||||
/// Base non-generic class for resolvers
|
||||
/// </summary>
|
||||
public abstract class ResolverBase
|
||||
{
|
||||
protected ResolverBase(Action resetAction)
|
||||
{
|
||||
//add itself to the internal collection
|
||||
ResolverCollection.Add(this, resetAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The base class for all resolvers.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
|
||||
/// <remarks>Provides singleton management to all resolvers.</remarks>
|
||||
public abstract class ResolverBase<TResolver> : ResolverBase
|
||||
where TResolver : ResolverBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The underlying singleton object instance
|
||||
/// </summary>
|
||||
static TResolver _resolver;
|
||||
|
||||
/// <summary>
|
||||
/// The lock for the singleton.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Though resharper says this is in error, it is actually correct. We want a different lock object for each generic type.
|
||||
/// See this for details: http://confluence.jetbrains.net/display/ReSharper/Static+field+in+generic+type
|
||||
/// </remarks>
|
||||
static readonly ReaderWriterLockSlim ResolversLock = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Constructor set the reset action for the underlying object
|
||||
/// </summary>
|
||||
protected ResolverBase()
|
||||
: base(() => Reset())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the resolver singleton instance.
|
||||
/// </summary>
|
||||
/// <remarks>The value can be set only once, and cannot be read before it has been set.</remarks>
|
||||
/// <exception cref="InvalidOperationException">value is read before it has been set, or value is set again once it has already been set.</exception>
|
||||
/// <exception cref="ArgumentNullException">value is <c>null</c>.</exception>
|
||||
public static TResolver Current
|
||||
{
|
||||
get
|
||||
@@ -28,30 +61,67 @@ namespace Umbraco.Core.ObjectResolution
|
||||
using (new ReadLock(ResolversLock))
|
||||
{
|
||||
if (_resolver == null)
|
||||
throw new InvalidOperationException("Current has not been initialized on " + typeof(TResolver) + ". You must initialize Current before trying to read it.");
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Current has not been initialized on {0}. You must initialize Current before trying to read it.",
|
||||
typeof(TResolver).FullName));
|
||||
return _resolver;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
using (Resolution.Configuration)
|
||||
using (new WriteLock(ResolversLock))
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
if (_resolver != null)
|
||||
throw new InvalidOperationException("Current has already been initialized. It is not possible to re-initialize Current once it has been initialized.");
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Current has already been initialized on {0}. It is not possible to re-initialize Current once it has been initialized.",
|
||||
typeof(TResolver).FullName));
|
||||
_resolver = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a the singleton nstance has been set.
|
||||
/// </summary>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal static bool HasCurrent
|
||||
{
|
||||
get
|
||||
{
|
||||
using (new ReadLock(ResolversLock))
|
||||
{
|
||||
return _resolver != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// used in unit tests to reset current to null
|
||||
/// Resets the resolver singleton instance to null.
|
||||
/// </summary>
|
||||
internal static void Reset()
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
/// <param name="resetResolution">By default this is true because we always need to reset resolution before we reset a resolver, however in some insanely rare cases like unit testing you might not want to do this.</param>
|
||||
internal static void Reset(bool resetResolution = true)
|
||||
{
|
||||
_resolver = null;
|
||||
|
||||
//In order to reset a resolver, we always must reset the resolution
|
||||
if (resetResolution)
|
||||
{
|
||||
Resolution.Reset();
|
||||
}
|
||||
|
||||
//ensure its removed from the collection
|
||||
ResolverCollection.Remove(_resolver);
|
||||
|
||||
using (Resolution.Configuration)
|
||||
using (new WriteLock(ResolversLock))
|
||||
{
|
||||
_resolver = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// Simply used to track all ManyObjectsResolverBase instances so that we can
|
||||
/// reset them all at once really easily.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Normally we'd use TypeFinding for this but because many of the resolvers are internal this won't work.
|
||||
/// We'd rather not keep a static list of them so we'll dynamically add to this list based on the base
|
||||
/// class of the ManyObjectsResolverBase.
|
||||
/// </remarks>
|
||||
internal static class ResolverCollection
|
||||
{
|
||||
private static readonly ConcurrentDictionary<ResolverBase, Action> Resolvers = new ConcurrentDictionary<ResolverBase, Action>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of resolvers created
|
||||
/// </summary>
|
||||
internal static int Count
|
||||
{
|
||||
get { return Resolvers.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets all resolvers
|
||||
/// </summary>
|
||||
internal static void ResetAll()
|
||||
{
|
||||
//take out each item from the bag and reset it
|
||||
var keys = Resolvers.Keys.ToArray();
|
||||
foreach (var k in keys)
|
||||
{
|
||||
Action resetAction;
|
||||
while (Resolvers.TryRemove(k, out resetAction))
|
||||
{
|
||||
//call the reset action for the resolver
|
||||
resetAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called when the static Reset method or a ResolverBase{T} is called.
|
||||
/// </summary>
|
||||
internal static void Remove(ResolverBase resolver)
|
||||
{
|
||||
if (resolver == null) return;
|
||||
Action action;
|
||||
Resolvers.TryRemove(resolver, out action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a resolver to the collection
|
||||
/// </summary>
|
||||
/// <param name="resolver"></param>
|
||||
/// <param name="resetAction"></param>
|
||||
/// <remarks>
|
||||
/// This is called when the creation of a ResolverBase occurs
|
||||
/// </remarks>
|
||||
internal static void Add(ResolverBase resolver, Action resetAction)
|
||||
{
|
||||
Resolvers.TryAdd(resolver, resetAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,123 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A Resolver to return and set a Single registered object.
|
||||
/// The base class for all single-object resolvers.
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolved"></typeparam>
|
||||
/// <typeparam name="TResolver"> </typeparam>
|
||||
/// <typeparam name="TResolver">The type of the concrete resolver class.</typeparam>
|
||||
/// <typeparam name="TResolved">The type of the resolved object.</typeparam>
|
||||
/// <remarks>
|
||||
/// Used for 'singly' registered objects. An example is like the MVC Controller Factory, only one exists application wide and it can
|
||||
/// be get/set.
|
||||
/// Resolves "single" objects ie objects for which there is only one application-wide instance, such as the MVC Controller factory.
|
||||
/// </remarks>
|
||||
internal abstract class SingleObjectResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
||||
public abstract class SingleObjectResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
where TResolver : ResolverBase
|
||||
{
|
||||
TResolved _resolved;
|
||||
readonly bool _canBeNull;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
private readonly bool _canBeNull;
|
||||
private TResolved _value;
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="SingleObjectResolverBase{TResolver, TResolved}"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>By default <c>CanBeNull</c> is false, so <c>Value</c> has to be initialized before being read,
|
||||
/// otherwise an exception will be thrown when reading it.</remarks>
|
||||
protected SingleObjectResolverBase()
|
||||
: this(false)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="SingleObjectResolverBase{TResolver, TResolved}"/> class with an instance of the resolved object.
|
||||
/// </summary>
|
||||
/// <param name="value">An instance of the resolved object.</param>
|
||||
/// <remarks>By default <c>CanBeNull</c> is false, so <c>value</c> has to be non-null, or <c>Value</c> has to be
|
||||
/// initialized before being accessed, otherwise an exception will be thrown when reading it.</remarks>
|
||||
protected SingleObjectResolverBase(TResolved value)
|
||||
: this(false)
|
||||
{
|
||||
_resolved = value;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="SingleObjectResolverBase{TResolver, TResolved}"/> class with a value indicating whether the resolved object instance can be null.
|
||||
/// </summary>
|
||||
/// <param name="canBeNull">A value indicating whether the resolved object instance can be null.</param>
|
||||
/// <remarks>If <c>CanBeNull</c> is false, <c>Value</c> has to be initialized before being read,
|
||||
/// otherwise an exception will be thrown when reading it.</remarks>
|
||||
protected SingleObjectResolverBase(bool canBeNull)
|
||||
{
|
||||
_canBeNull = canBeNull;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="SingleObjectResolverBase{TResolver, TResolved}"/> class with an instance of the resolved object,
|
||||
/// and a value indicating whether that instance can be null.
|
||||
/// </summary>
|
||||
/// <param name="value">An instance of the resolved object.</param>
|
||||
/// <param name="canBeNull">A value indicating whether the resolved object instance can be null.</param>
|
||||
/// <remarks>If <c>CanBeNull</c> is false, <c>value</c> has to be non-null, or <c>Value</c> has to be initialized before being read,
|
||||
/// otherwise an exception will be thrown when reading it.</remarks>
|
||||
protected SingleObjectResolverBase(TResolved value, bool canBeNull)
|
||||
{
|
||||
_resolved = value;
|
||||
_value = value;
|
||||
_canBeNull = canBeNull;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the value of the object
|
||||
/// Gets a value indicating whether the resolved object instance can be null.
|
||||
/// </summary>
|
||||
public bool CanBeNull
|
||||
{
|
||||
get { return _canBeNull; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the resolved object instance is null.
|
||||
/// </summary>
|
||||
public bool HasValue
|
||||
{
|
||||
get { return _value != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the resolved object instance.
|
||||
/// </summary>
|
||||
/// <remarks></remarks>
|
||||
/// <exception cref="ArgumentNullException">value is set to null, but cannot be null (<c>CanBeNull</c> is <c>false</c>).</exception>
|
||||
/// <exception cref="InvalidOperationException">value is read and is null, but cannot be null (<c>CanBeNull</c> is <c>false</c>),
|
||||
/// or value is set (read) and resolution is (not) frozen.</exception>
|
||||
protected TResolved Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _resolved;
|
||||
Resolution.EnsureIsFrozen();
|
||||
using (new ReadLock(_lock))
|
||||
{
|
||||
if (!_canBeNull && _value == null)
|
||||
throw new InvalidOperationException(string.Format(
|
||||
"Resolver {0} requires a value, and none was supplied.", this.GetType().FullName));
|
||||
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!_canBeNull && value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
_resolved = value;
|
||||
using (Resolution.Configuration)
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
{
|
||||
if (!_canBeNull && value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,23 @@ using System;
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// Some many object resolvers require that the objects that they resolve have weights applied to them so that
|
||||
/// the objects are returned in a sorted order, this attribute is used in these scenarios.
|
||||
/// Indicates the relative weight of a resolved object type.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
internal class WeightedPluginAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WeightedPluginAttribute"/> class with a weight.
|
||||
/// </summary>
|
||||
/// <param name="weight">The object type weight.</param>
|
||||
public WeightedPluginAttribute(int weight)
|
||||
{
|
||||
Weight = weight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the weight of the object type.
|
||||
/// </summary>
|
||||
public int Weight { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -45,5 +45,11 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
/// <param name="type"></param>
|
||||
/// <param name="entity"></param>
|
||||
void Delete(Type type, IEntity entity);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the cache by type
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
void Clear(Type type);
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,20 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
bool result = _cache.TryRemove(GetCompositeId(type, entity.Id), out entity1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear cache by type
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
public void Clear(Type type)
|
||||
{
|
||||
var keys = _cache.Keys;
|
||||
foreach (var key in keys.Where(x => x.StartsWith(string.Format("{0}-", type.Name))))
|
||||
{
|
||||
IEntity e;
|
||||
_cache.TryRemove(key, out e);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_cache.Clear();
|
||||
|
||||
@@ -46,6 +46,11 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
return;
|
||||
}
|
||||
|
||||
public void Clear(Type type)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Caching;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -25,7 +26,7 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
#endregion
|
||||
|
||||
//TODO Save this in cache as well, so its not limited to a single server usage
|
||||
private ConcurrentDictionary<string, string> _keyTracker = new ConcurrentDictionary<string, string>();
|
||||
private readonly ConcurrentHashSet<string> _keyTracker = new ConcurrentHashSet<string>();
|
||||
private ObjectCache _memoryCache = new MemoryCache("in-memory");
|
||||
private static readonly ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim();
|
||||
|
||||
@@ -46,7 +47,7 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
|
||||
public IEnumerable<IEntity> GetAllByType(Type type)
|
||||
{
|
||||
foreach (var key in _keyTracker.Keys)
|
||||
foreach (var key in _keyTracker)
|
||||
{
|
||||
if (key.StartsWith(type.Name))
|
||||
{
|
||||
@@ -59,8 +60,7 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
{
|
||||
var key = GetCompositeId(type, entity.Id);
|
||||
var exists = _memoryCache.GetCacheItem(key) != null;
|
||||
|
||||
_keyTracker.TryAdd(key, key);
|
||||
_keyTracker.TryAdd(key);
|
||||
if (exists)
|
||||
{
|
||||
_memoryCache.Set(key, entity, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(5) });
|
||||
@@ -72,16 +72,37 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
|
||||
public void Delete(Type type, IEntity entity)
|
||||
{
|
||||
string throwaway = null;
|
||||
var key = GetCompositeId(type, entity.Id);
|
||||
var keyBeSure = _keyTracker.TryGetValue(key, out throwaway);
|
||||
object itemRemoved = _memoryCache.Remove(key);
|
||||
_keyTracker.TryRemove(key, out throwaway);
|
||||
_memoryCache.Remove(key);
|
||||
_keyTracker.Remove(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear cache by type
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
public void Clear(Type type)
|
||||
{
|
||||
using (new WriteLock(ClearLock))
|
||||
{
|
||||
var keys = new string[_keyTracker.Count];
|
||||
_keyTracker.CopyTo(keys, 0);
|
||||
var keysToRemove = new List<string>();
|
||||
foreach (var key in keys.Where(x => x.StartsWith(string.Format("{0}-", type.Name))))
|
||||
{
|
||||
_keyTracker.Remove(key);
|
||||
keysToRemove.Add(key);
|
||||
}
|
||||
foreach (var key in keysToRemove)
|
||||
{
|
||||
_memoryCache.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
using (new ReadLock(ClearLock))
|
||||
using (new WriteLock(ClearLock))
|
||||
{
|
||||
_keyTracker.Clear();
|
||||
_memoryCache.DisposeIfDisposable();
|
||||
|
||||
@@ -62,7 +62,8 @@ namespace Umbraco.Core.Persistence
|
||||
//double check
|
||||
if (_globalInstance == null)
|
||||
{
|
||||
_globalInstance = string.IsNullOrEmpty(_providerName) == false && string.IsNullOrEmpty(_providerName) == false
|
||||
_globalInstance = string.IsNullOrEmpty(_connectionString) == false &&
|
||||
string.IsNullOrEmpty(_providerName) == false
|
||||
? new UmbracoDatabase(_connectionString, _providerName)
|
||||
: new UmbracoDatabase(_connectionStringName);
|
||||
}
|
||||
@@ -74,10 +75,11 @@ namespace Umbraco.Core.Persistence
|
||||
//we have an http context, so only create one per request
|
||||
if (!HttpContext.Current.Items.Contains(typeof(DefaultDatabaseFactory)))
|
||||
{
|
||||
HttpContext.Current.Items.Add(typeof (DefaultDatabaseFactory),
|
||||
string.IsNullOrEmpty(_providerName) == false && string.IsNullOrEmpty(_providerName) == false
|
||||
? new UmbracoDatabase(_connectionString, _providerName)
|
||||
: new UmbracoDatabase(_connectionStringName));
|
||||
HttpContext.Current.Items.Add(typeof (DefaultDatabaseFactory),
|
||||
string.IsNullOrEmpty(_connectionString) == false &&
|
||||
string.IsNullOrEmpty(_providerName) == false
|
||||
? new UmbracoDatabase(_connectionString, _providerName)
|
||||
: new UmbracoDatabase(_connectionStringName));
|
||||
}
|
||||
return (UmbracoDatabase)HttpContext.Current.Items[typeof(DefaultDatabaseFactory)];
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user