diff --git a/.gitignore b/.gitignore
index 576beabdf9..5b5e7660c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,6 +56,7 @@ build/*.nupkg
src/Umbraco.Tests/config/applications.config
src/Umbraco.Tests/config/trees.config
src/Umbraco.Web.UI/web.config
+src/Umbraco.Web.UI/Config/ClientDependency.config
*.orig
src/Umbraco.Tests/config/404handlers.config
src/Umbraco.Web.UI/[Vv]iews/*.cshtml
@@ -132,4 +133,11 @@ src/umbraco.sln.ide/*
build/UmbracoCms.*/
src/.vs/
src/Umbraco.Web.UI/umbraco/js/install.loader.js
-src/Umbraco.Tests/media
\ No newline at end of file
+src/Umbraco.Tests/media
+tools/docfx/*
+apidocs/_site/*
+apidocs/api/*
+build/docs.zip
+build/ui-docs.zip
+build/csharp-docs.zip
+build/msbuild.log
diff --git a/README.md b/README.md
index 53070b6917..8f89209328 100644
--- a/README.md
+++ b/README.md
@@ -3,9 +3,11 @@ Umbraco CMS
Umbraco is a free open source Content Management System built on the ASP.NET platform.
## Building Umbraco from source ##
-The easiest way to get started is to run `build/build.bat` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `grunt dev` in `src\Umbraco.Web.UI.Client`.
+The easiest way to get started is to run `build/build.bat` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `grunt vs` in `src\Umbraco.Web.UI.Client`.
-If you're interested in making changes to Belle make sure to read the [Belle ReadMe file](src/Umbraco.Web.UI.Client/README.md). Note that you can always [download a nightly build](http://nightly.umbraco.org/umbraco%207.0.0/) so you don't have to build the code yourself.
+If you're interested in making changes to Belle without running Visual Studio make sure to read the [Belle ReadMe file](src/Umbraco.Web.UI.Client/README.md).
+
+Note that you can always [download a nightly build (to be found in the artifacts tab)](https://ci.appveyor.com/project/Umbraco/umbraco-cms-hs8dx/history/branch/dev-v7) so you don't have to build the code yourself.
## Watch a introduction video ##
diff --git a/apidocs/docfx.filter.yml b/apidocs/docfx.filter.yml
new file mode 100644
index 0000000000..e96fbaafff
--- /dev/null
+++ b/apidocs/docfx.filter.yml
@@ -0,0 +1,18 @@
+apiRules:
+ - include:
+ uidRegex: ^Umbraco\.Core
+ - exclude:
+ uidRegex: ^umbraco\.Web\.org
+ - include:
+ uidRegex: ^Umbraco\.Web
+ - exclude:
+ hasAttribute:
+ uid: System.ComponentModel.EditorBrowsableAttribute
+ ctorArguments:
+ - System.ComponentModel.EditorBrowsableState.Never
+ - exclude:
+ uidRegex: ^umbraco\.
+ - exclude:
+ uidRegex: ^CookComputing\.
+ - exclude:
+ uidRegex: ^.*$
\ No newline at end of file
diff --git a/apidocs/docfx.json b/apidocs/docfx.json
new file mode 100644
index 0000000000..520622a0e0
--- /dev/null
+++ b/apidocs/docfx.json
@@ -0,0 +1,75 @@
+{
+ "metadata": [
+ {
+ "src": [
+ {
+ "files": [
+ "Umbraco.Core/Umbraco.Core.csproj",
+ "Umbraco.Web/Umbraco.Web.csproj"
+ ],
+ "exclude": [
+ "**/obj/**",
+ "**/bin/**",
+ "_site/**"
+ ],
+ "cwd": "../src"
+ }
+ ],
+ "dest": "../apidocs/api",
+ "filter": "../apidocs/docfx.filter.yml"
+ }
+ ],
+ "build": {
+ "content": [
+ {
+ "files": [
+ "api/**.yml",
+ "api/index.md"
+ ]
+ },
+ {
+ "files": [
+ "articles/**.md",
+ "articles/**/toc.yml",
+ "toc.yml",
+ "*.md"
+ ],
+ "exclude": [
+ "obj/**",
+ "_site/**"
+ ]
+ }
+ ],
+ "resource": [
+ {
+ "files": [
+ "images/**"
+ ],
+ "exclude": [
+ "obj/**",
+ "_site/**"
+ ]
+ }
+ ],
+ "overwrite": [
+ {
+ "files": [
+ "**.md"
+ ],
+ "exclude": [
+ "obj/**",
+ "_site/**"
+ ]
+ }
+ ],
+ "globalMetadata": {
+ "_appTitle": "Umbraco c# Api docs",
+ "_enableSearch": true,
+ "_disableContribution": false
+ },
+ "dest": "_site",
+ "template": [
+ "default", "umbracotemplate"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/apidocs/index.md b/apidocs/index.md
new file mode 100644
index 0000000000..b90b816312
--- /dev/null
+++ b/apidocs/index.md
@@ -0,0 +1,7 @@
+
+# Umbraco c# API reference
+
+## Quick Links:
+
+### [Umbraco.Core](api/Umbraco.Core.html) docs
+### [Umbraco.Web](api/Umbraco.Web.html) docs
diff --git a/apidocs/toc.yml b/apidocs/toc.yml
new file mode 100644
index 0000000000..6817825066
--- /dev/null
+++ b/apidocs/toc.yml
@@ -0,0 +1,5 @@
+
+- name: Umbraco.Core Documentation
+ href: https://our.umbraco.org/apidocs/csharp/api/Umbraco.Core.html
+- name: Umbraco.Web Documentation
+ href: https://our.umbraco.org/apidocs/csharp/api/Umbraco.Web.html
\ No newline at end of file
diff --git a/apidocs/umbracotemplate/partials/class.tmpl.partial b/apidocs/umbracotemplate/partials/class.tmpl.partial
new file mode 100644
index 0000000000..9153a863a4
--- /dev/null
+++ b/apidocs/umbracotemplate/partials/class.tmpl.partial
@@ -0,0 +1,257 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+{{^_disableContribution}}
+{{#sourceurl}}{{__global.viewSource}} {{/sourceurl}}
+{{/_disableContribution}}
+
{{>partials/title}}
+{{{summary}}}
+{{{conceptual}}}
+{{#inheritance.0}}
+
+
{{__global.inheritance}}
+{{#inheritance}}
+
{{{specName.0.value}}}
+{{/inheritance}}
+
{{item.name.0.value}}
+
+{{/inheritance.0}}
+{{__global.namespace}} :{{namespace}}
+{{__global.assembly}} :{{assemblies.0}}.dll
+{{__global.syntax}}
+
+
{{syntax.content.0.value}}
+
+{{#syntax.parameters.0}}
+{{__global.parameters}}
+
+
+
+ {{__global.type}}
+ {{__global.name}}
+ {{__global.description}}
+
+
+
+{{/syntax.parameters.0}}
+{{#syntax.parameters}}
+
+ {{{type.specName.0.value}}}
+ {{{id}}}
+ {{{description}}}
+
+{{/syntax.parameters}}
+{{#syntax.parameters.0}}
+
+
+{{/syntax.parameters.0}}
+{{#syntax.return}}
+{{__global.returns}}
+
+
+
+ {{__global.type}}
+ {{__global.description}}
+
+
+
+
+ {{{type.specName.0.value}}}
+ {{{description}}}
+
+
+
+{{/syntax.return}}
+{{#syntax.typeParameters.0}}
+{{__global.typeParameters}}
+
+
+
+ {{__global.name}}
+ {{__global.description}}
+
+
+
+{{/syntax.typeParameters.0}}
+{{#syntax.typeParameters}}
+
+ {{{id}}}
+ {{{description}}}
+
+{{/syntax.typeParameters}}
+{{#syntax.typeParameters.0}}
+
+
+{{/syntax.typeParameters.0}}
+{{#remarks}}
+
+
+{{/remarks}}
+{{#example.0}}
+{{__global.examples}}
+{{/example.0}}
+{{#example}}
+{{{.}}}
+{{/example}}
+{{#children}}
+{{>partials/classSubtitle}}
+{{#children}}
+{{^_disableContribution}}
+{{#sourceurl}}
+
+ {{__global.viewSource}}
+ {{/sourceurl}}
+{{/_disableContribution}}
+{{name.0.value}}
+{{{summary}}}
+{{{conceptual}}}
+{{__global.declaration}}
+{{#syntax}}
+
+
{{syntax.content.0.value}}
+
+{{#parameters.0}}
+{{__global.parameters}}
+
+
+
+ {{__global.type}}
+ {{__global.name}}
+ {{__global.description}}
+
+
+
+{{/parameters.0}}
+{{#parameters}}
+
+ {{{type.specName.0.value}}}
+ {{{id}}}
+ {{{description}}}
+
+{{/parameters}}
+{{#parameters.0}}
+
+
+{{/parameters.0}}
+{{#return}}
+{{__global.returns}}
+
+
+
+ {{__global.type}}
+ {{__global.description}}
+
+
+
+
+ {{{type.specName.0.value}}}
+ {{{description}}}
+
+
+
+{{/return}}
+{{#typeParameters.0}}
+{{__global.typeParameters}}
+
+
+
+ {{__global.name}}
+ {{__global.description}}
+
+
+
+{{/typeParameters.0}}
+{{#typeParameters}}
+
+ {{{id}}}
+ {{{description}}}
+
+{{/typeParameters}}
+{{#typeParameters.0}}
+
+
+{{/typeParameters.0}}
+{{#fieldValue}}
+{{__global.fieldValue}}
+
+
+
+ {{__global.type}}
+ {{__global.description}}
+
+
+
+
+ {{{type.specName.0.value}}}
+ {{{description}}}
+
+
+
+{{/fieldValue}}
+{{#propertyValue}}
+{{__global.propertyValue}}
+
+
+
+ {{__global.type}}
+ {{__global.description}}
+
+
+
+
+ {{{type.specName.0.value}}}
+ {{{description}}}
+
+
+
+{{/propertyValue}}
+{{#eventType}}
+{{__global.eventType}}
+
+
+
+ {{__global.type}}
+ {{__global.description}}
+
+
+
+
+ {{{type.specName.0.value}}}
+ {{{description}}}
+
+
+
+{{/eventType}}
+{{/syntax}}
+{{#remarks}}
+
+
+{{/remarks}}
+{{#example.0}}
+{{__global.examples}}
+{{/example.0}}
+{{#example}}
+{{{.}}}
+{{/example}}
+{{#exceptions.0}}
+{{__global.exceptions}}
+
+
+
+ {{__global.type}}
+ {{__global.condition}}
+
+
+
+{{/exceptions.0}}
+{{#exceptions}}
+
+ {{{type.specName.0.value}}}
+ {{{description}}}
+
+{{/exceptions}}
+{{#exceptions.0}}
+
+
+{{/exceptions.0}}
+{{/children}}
+{{/children}}
diff --git a/apidocs/umbracotemplate/partials/footer.tmpl.partial b/apidocs/umbracotemplate/partials/footer.tmpl.partial
new file mode 100644
index 0000000000..69f51a101f
--- /dev/null
+++ b/apidocs/umbracotemplate/partials/footer.tmpl.partial
@@ -0,0 +1,13 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+
diff --git a/apidocs/umbracotemplate/partials/head.tmpl.partial b/apidocs/umbracotemplate/partials/head.tmpl.partial
new file mode 100644
index 0000000000..591e1c1885
--- /dev/null
+++ b/apidocs/umbracotemplate/partials/head.tmpl.partial
@@ -0,0 +1,18 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+
+
+
+ {{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}
+
+
+
+ {{#_description}} {{/_description}}
+
+
+
+
+
+
+ {{#_enableSearch}} {{/_enableSearch}}
+
diff --git a/apidocs/umbracotemplate/partials/namespace.tmpl.partial b/apidocs/umbracotemplate/partials/namespace.tmpl.partial
new file mode 100644
index 0000000000..80ca30799a
--- /dev/null
+++ b/apidocs/umbracotemplate/partials/namespace.tmpl.partial
@@ -0,0 +1,18 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+{{^_disableContribution}}
+{{#sourceurl}}
+{{__global.viewSource}}
+{{/sourceurl}}
+{{/_disableContribution}}
+{{>partials/title}}
+{{{summary}}}
+{{{conceptual}}}
+
+{{#children}}
+ {{>partials/namespaceSubtitle}}
+ {{#children}}
+ {{{specName.0.value}}}
+
+ {{/children}}
+{{/children}}
diff --git a/apidocs/umbracotemplate/partials/navbar.tmpl.partial b/apidocs/umbracotemplate/partials/navbar.tmpl.partial
new file mode 100644
index 0000000000..e9ee0af1c7
--- /dev/null
+++ b/apidocs/umbracotemplate/partials/navbar.tmpl.partial
@@ -0,0 +1,22 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+
+
+
diff --git a/apidocs/umbracotemplate/partials/rest.tmpl.partial b/apidocs/umbracotemplate/partials/rest.tmpl.partial
new file mode 100644
index 0000000000..4306bf7db1
--- /dev/null
+++ b/apidocs/umbracotemplate/partials/rest.tmpl.partial
@@ -0,0 +1,101 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+{{^_disableContribution}}
+{{#sourceurl}}View Source {{/sourceurl}}
+{{/_disableContribution}}
+{{name}}
+{{#summary}}
+{{{summary}}}
+{{/summary}}
+{{#description}}
+{{{description}}}
+{{/description}}
+{{#conceptual}}
+ {{{conceptual}}}
+{{/conceptual}}
+{{#children}}
+{{^_disableContribution}}
+{{#sourceurl}}
+
+ View Source
+ {{/sourceurl}}
+{{/_disableContribution}}
+ {{operationId}}
+{{#summary}}
+{{{summary}}}
+{{/summary}}
+{{#description}}
+{{{description}}}
+{{/description}}
+{{#conceptual}}
+ {{{conceptual}}}
+{{/conceptual}}
+Request
+
+
{{operation}} {{path}}
+
+{{#parameters.0}}
+Parameters
+
+
+
+ Name
+ Type
+ Value
+ Notes
+
+
+
+{{/parameters.0}}
+{{#parameters}}
+
+ {{#required}}*{{/required}}{{name}}
+ {{type}}
+ {{default}}
+ {{{description}}}
+
+ {{/parameters}}
+ {{#parameters.0}}
+
+
+{{/parameters.0}}
+{{#responses.0}}
+
+
Responses
+
+
+
+ Status Code
+ Description
+ Samples
+
+
+
+{{/responses.0}}
+{{#responses}}
+
+ {{statusCode}}
+ {{{description}}}
+
+ {{#examples}}
+
+ Mime type: {{mimeType}}
+
+ {{content}}
+ {{/examples}}
+
+
+ {{/responses}}
+ {{#responses.0}}
+
+
+
+{{/responses.0}}
+{{#footer}}
+
+{{/footer}}
+{{/children}}
+{{#footer}}
+
+{{/footer}}
+
diff --git a/apidocs/umbracotemplate/styles/main.css b/apidocs/umbracotemplate/styles/main.css
new file mode 100644
index 0000000000..7756b2f7d4
--- /dev/null
+++ b/apidocs/umbracotemplate/styles/main.css
@@ -0,0 +1,73 @@
+body {
+ color: rgba(0,0,0,.8);
+}
+.navbar-inverse {
+ background: #a3db78;
+}
+.navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-text {
+ color: rgba(0,0,0,.8);
+}
+
+.navbar-inverse {
+ border-color: transparent;
+}
+
+.sidetoc {
+ background-color: #f5fbf1;
+}
+body .toc {
+ background-color: #f5fbf1;
+}
+.sidefilter {
+ background-color: #daf0c9;
+}
+.subnav {
+ background-color: #f5fbf1;
+}
+
+.navbar-inverse .navbar-nav>.active>a {
+ color: rgba(0,0,0,.8);
+ background-color: #daf0c9;
+}
+
+.navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover {
+ color: rgba(0,0,0,.8);
+ background-color: #daf0c9;
+}
+
+.btn-primary {
+ color: rgba(0,0,0,.8);
+ background-color: #fff;
+ border-color: rgba(0,0,0,.8);
+}
+.btn-primary:hover {
+ background-color: #daf0c9;
+ color: rgba(0,0,0,.8);
+ border-color: rgba(0,0,0,.8);
+}
+
+.toc .nav > li > a {
+ color: rgba(0,0,0,.8);
+}
+
+button, a {
+ color: #f36f21;
+}
+
+button:hover,
+button:focus,
+a:hover,
+a:focus {
+ color: #143653;
+ text-decoration: none;
+}
+
+.navbar-header .navbar-brand {
+ background: url(https://our.umbraco.org/assets/images/logo.svg) left center no-repeat;
+ background-size: 40px auto;
+ width:50px;
+}
+
+.toc .nav > li.active > a {
+ color: #f36f21;
+}
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000000..eaba82e666
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,46 @@
+version: '{build}'
+shallow_clone: true
+build_script:
+- cmd: >-
+ cd build
+
+ SET "release="
+
+ FOR /F "skip=1 delims=" %%i IN (UmbracoVersion.txt) DO IF NOT DEFINED release SET "release=%%i"
+
+ SET nuGetFolder=C:\Users\appveyor\.nuget\packages
+
+ ..\src\.nuget\NuGet.exe sources Add -Name MyGetUmbracoCore -Source https://www.myget.org/F/umbracocore/api/v2/ >NUL
+
+ ..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
+
+ IF EXIST ..\src\umbraco.businesslogic\packages.config ..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
+
+ ..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
+
+ ECHO Building Release %release% build%APPVEYOR_BUILD_NUMBER%
+
+ SET PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
+
+ SET MSBUILD="C:\Program Files (x86)\MSBuild\14.0\Bin\MsBuild.exe"
+
+ XCOPY "..\src\Umbraco.Tests\unit-test-log4net.CI.config" "..\src\Umbraco.Tests\unit-test-log4net.config" /Y
+
+ %MSBUILD% "..\src\Umbraco.Tests\Umbraco.Tests.csproj" /consoleloggerparameters:Summary;ErrorsOnly
+
+ build.bat nopause %release% build%APPVEYOR_BUILD_NUMBER%
+
+ ECHO %PATH%
+test:
+ assemblies: src\Umbraco.Tests\bin\Debug\Umbraco.Tests.dll
+artifacts:
+- path: build\UmbracoCms.*
+- path: build\msbuild.log
+notifications:
+- provider: Slack
+ auth_token:
+ secure: v2csJi2V5ghR0rPdODK8GJdOGNCA+XaK84iQ9MdPOClqB+VU+40ybdKp6gPirGSH
+ channel: '#build-umbraco-core'
+ on_build_success: false
+ on_build_failure: true
+ on_build_status_changed: false
\ No newline at end of file
diff --git a/build/ApiDocs/TOC.css b/build/ApiDocs/TOC.css
deleted file mode 100644
index 9c32aba214..0000000000
--- a/build/ApiDocs/TOC.css
+++ /dev/null
@@ -1,170 +0,0 @@
-/* File : TOC.css
-// Author : Eric Woodruff (Eric@EWoodruff.us)
-// Updated : 09/07/2007
-//
-// Stylesheet for the table of content
-*/
-
-*
-{
- margin: 0px 0px 0px 0px;
- padding: 0px 0px 0px 0px;
-}
-
-body
-{
- font-family: Segoe UI, Arial, Verdana, Helvetica, sans-serif;
- font-size: 0.9em;
- background-color: white;
- color: White;
- overflow: hidden;
-}
-
-input
-{
- padding:5px;
- margin: 3px 0px 3px 0px
-}
-
-img
-{
- border: 0;
- margin-left: 5px;
- margin-right: 2px;
-}
-
-img.TreeNodeImg
-{
- cursor: pointer;
-}
-
-img.TOCLink
-{
- cursor: pointer;
- margin-left: 0;
- margin-right: 0;
-}
-
-a.SelectedNode, a.UnselectedNode
-{
- color: #333;
- text-decoration: none;
- padding: 1px 3px 1px 3px;
- white-space: nowrap;
-}
-
-a.SelectedNode
-{
- background-color: #ffffff;
- border: solid 1px #999999;
- padding: 0px 2px 0px 2px;
-}
-
-a.UnselectedNode:hover, a.SelectedNode:hover
-{
- background-color: #cccccc;
- border: solid 1px #999999;
- padding: 0px 2px 0px 2px;
-}
-
-.Visible
-{
- display: block;
- margin-left: 2em;
-}
-
-.Hidden
-{
- display: none;
-}
-
-.Tree
-{
- background-color: #fff;
- color: #333;
- width: 300px;
- overflow: auto;
-}
-
-.TreeNode, .TreeItem
-{
- white-space: nowrap;
- margin: 2px 2px 2px 2px;
-}
-
-.TOCDiv
-{
- position: relative;
- float: left;
- width: 300px;
- height: 100%;
-}
-
-.TOCSizer
-{
- clear: none;
- float: left;
- width: 10px;
- height: 100%;
- background-image: url("Splitter.gif");
- background-position:center center;
- background-repeat:no-repeat;
- position: relative;
- cursor: w-resize;
- border-left: solid 1px #CCC;
-}
-
-.TopicContent
-{
- position: relative;
- float: right;
- background-color: white;
- height: 100%;
-}
-
-.SearchOpts
-{
- padding: 5px 5px 10px 5px;
- color: black;
- width: 300px;
- border-bottom: solid lightgrey 1px;
- height: 110px !important;
-}
-
-.NavOpts
-{
- padding: 5px 5px 6px 5px;
- color: black;
- width: 300px;
- border-bottom: solid lightgrey 1px;
-}
-
-.NavOpts img {
- display:inline-block;
- margin: 0px 5px 0px 5px;
-}
-
-.IndexOpts
-{
- padding: 5px 5px 6px 5px;
- color: black;
- width: 300px;
- border-bottom: solid lightgrey 1px;
-}
-
-.IndexItem
-{
- white-space: nowrap;
- margin: 2px 2px 2px 2px;
-}
-
-.IndexSubItem
-{
- white-space: nowrap;
- margin: 2px 2px 2px 12px;
-}
-
-.PaddedText
-{
- margin: 10px 10px 10px 10px;
-}
diff --git a/build/ApiDocs/csharp-api-docs.shfbproj b/build/ApiDocs/csharp-api-docs.shfbproj
deleted file mode 100644
index f635f2e2ee..0000000000
--- a/build/ApiDocs/csharp-api-docs.shfbproj
+++ /dev/null
@@ -1,172 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- 2.0
- {cb4d85f1-7390-40ee-b41f-a724bb8fddea}
- 1.9.5.0
-
- Documentation
- Documentation
- Documentation
-
- .NET Framework 4.5
- .\Output\
- UmbracoClassLibrary
- en-US
- OnlyErrors
- csharp-api-docs.log
- Website
- True
- False
- False
- False
- True
- CSharp
- Blank
- False
- VS2010
- False
- Guid
- Umbraco .Net Class Library
- AboveNamespaces
- Attributes, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected
-
-
-
-
-
-
- None
- None
- False
- True
- Summary, AutoDocumentCtors, AutoDocumentDispose
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/build/Build.bat b/build/Build.bat
index 1167d9fcb6..fc0d8a69ea 100644
--- a/build/Build.bat
+++ b/build/Build.bat
@@ -11,20 +11,28 @@ FOR /F "skip=1 delims=" %%i IN (UmbracoVersion.txt) DO IF NOT DEFINED release SE
FOR /F "skip=2 delims=" %%i IN (UmbracoVersion.txt) DO IF NOT DEFINED comment SET "comment=%%i"
REM If there's arguments on the command line overrule UmbracoVersion.txt and use that as the version
-IF [%1] NEQ [] (SET release=%1)
-IF [%2] NEQ [] (SET comment=%2) ELSE (IF [%1] NEQ [] (SET "comment="))
+IF [%2] NEQ [] (SET release=%2)
+IF [%3] NEQ [] (SET comment=%3) ELSE (IF [%2] NEQ [] (SET "comment="))
+
+REM Get the "is continuous integration" from the parameters
+SET "isci=0"
+IF [%1] NEQ [] (SET isci=1)
SET version=%release%
-
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
+
+ECHO.
ECHO Building Umbraco %version%
+ECHO.
ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %release%
+ECHO.
ECHO Removing the belle build folder and bower_components folder to make sure everything is clean as a whistle
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
RD ..\src\Umbraco.Web.UI.Client\bower_components /Q /S
+ECHO.
ECHO Removing existing built files to make sure everything is clean as a whistle
RMDIR /Q /S _BuildOutput
DEL /F /Q UmbracoCms.*.zip
@@ -32,27 +40,56 @@ DEL /F /Q UmbracoExamine.*.zip
DEL /F /Q UmbracoCms.*.nupkg
DEL /F /Q webpihash.txt
+ECHO.
ECHO Making sure Git is in the path so that the build can succeed
CALL InstallGit.cmd
-ECHO Performing MSBuild and producing Umbraco binaries zip files
-%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment% /verbosity:minimal
+REM Adding the default Git path so that if it's installed it can actually be found
+REM This is necessary because SETLOCAL is on in InstallGit.cmd so that one might find Git,
+REM but the path setting is lost due to SETLOCAL
+path=C:\Program Files (x86)\Git\cmd;C:\Program Files\Git\cmd;%PATH%
+
+ECHO.
+ECHO Making sure we have a web.config
+IF NOT EXIST %CD%\..\src\Umbraco.Web.UI\web.config COPY %CD%\..\src\Umbraco.Web.UI\web.Template.config %CD%\..\src\Umbraco.Web.UI\web.config
+
+ECHO.
+ECHO.
+ECHO Performing MSBuild and producing Umbraco binaries zip files
+ECHO This takes a few minutes and logging is set to report warnings
+ECHO and errors only so it might seems like nothing is happening for a while.
+ECHO You can check the msbuild.log file for progress.
+ECHO.
+%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment% /p:NugetPackagesDirectory=%nuGetFolder% /consoleloggerparameters:Summary;ErrorsOnly;WarningsOnly /fileLogger
+IF ERRORLEVEL 1 GOTO :error
+
+ECHO.
ECHO Setting node_modules folder to hidden to prevent VS13 from crashing on it while loading the websites project
attrib +h ..\src\Umbraco.Web.UI.Client\node_modules
+ECHO.
ECHO Adding Web.config transform files to the NuGet package
REN .\_BuildOutput\WebApp\Views\Web.config Web.config.transform
REN .\_BuildOutput\WebApp\Xslt\Web.config Web.config.transform
+ECHO.
ECHO Packing the NuGet release files
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %version% -Symbols -Verbosity quiet
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.nuspec -Version %version% -Verbosity quiet
-
-IF ERRORLEVEL 1 GOTO :showerror
+IF ERRORLEVEL 1 GOTO :error
-ECHO No errors were detected but you still may see some in the output, then it's time to investigate.
-ECHO You might see some warnings but that is completely normal.
+:success
+ECHO.
+ECHO No errors were detected!
+ECHO There may still be some in the output, which you would need to investigate.
+ECHO Warnings are usually normal.
GOTO :EOF
-:showerror
-PAUSE
+:error
+
+ECHO.
+ECHO Errors were detected!
+
+REM don't pause if continuous integration else the build server waits forever
+REM before cancelling the build (and, there is noone to read the output anyways)
+IF isci NEQ 1 PAUSE
diff --git a/build/BuildBelle.bat b/build/BuildBelle.bat
index 6c11cc9fc5..8a07ee380a 100644
--- a/build/BuildBelle.bat
+++ b/build/BuildBelle.bat
@@ -23,6 +23,7 @@ ECHO Change directory to %CD%\..\src\Umbraco.Web.UI.Client\
CD %CD%\..\src\Umbraco.Web.UI.Client\
ECHO Do npm install and the grunt build of Belle
+call npm cache clean --quiet
call npm install --quiet
call npm install -g grunt-cli --quiet
call npm install -g bower --quiet
diff --git a/build/BuildDocs.bat b/build/BuildDocs.bat
new file mode 100644
index 0000000000..9d0a04e1cd
--- /dev/null
+++ b/build/BuildDocs.bat
@@ -0,0 +1,20 @@
+@ECHO OFF
+SETLOCAL
+
+SET release=%1
+ECHO Installing Npm NuGet Package
+
+SET nuGetFolder=%CD%\..\src\packages\
+ECHO Configured packages folder: %nuGetFolder%
+ECHO Current folder: %CD%
+
+%CD%\..\src\.nuget\NuGet.exe install Npm.js -OutputDirectory %nuGetFolder% -Verbosity quiet
+
+for /f "delims=" %%A in ('dir %nuGetFolder%node.js.* /b') do set "nodePath=%nuGetFolder%%%A\"
+for /f "delims=" %%A in ('dir %nuGetFolder%npm.js.* /b') do set "npmPath=%nuGetFolder%%%A\tools\"
+
+ECHO Adding Npm and Node to path
+REM SETLOCAL is on, so changes to the path not persist to the actual user's path
+PATH=%npmPath%;%nodePath%;%PATH%
+
+Powershell.exe -ExecutionPolicy Unrestricted -File .\BuildDocs.ps1
\ No newline at end of file
diff --git a/build/BuildDocs.ps1 b/build/BuildDocs.ps1
index 6f46a43fde..dcb3a85cc1 100644
--- a/build/BuildDocs.ps1
+++ b/build/BuildDocs.ps1
@@ -1,27 +1,100 @@
-##We cannot continue if sandcastle is not installed determined by env variable: SHFBROOT
+$PSScriptFilePath = (Get-Item $MyInvocation.MyCommand.Path);
+$RepoRoot = (get-item $PSScriptFilePath).Directory.Parent.FullName;
+$SolutionRoot = Join-Path -Path $RepoRoot "src";
+$ToolsRoot = Join-Path -Path $RepoRoot "tools";
+$DocFx = Join-Path -Path $ToolsRoot "docfx\docfx.exe"
+$DocFxFolder = (Join-Path -Path $ToolsRoot "docfx")
+$DocFxJson = Join-Path -Path $RepoRoot "apidocs\docfx.json"
+$7Zip = Join-Path -Path $ToolsRoot "7zip\7za.exe"
+$DocFxSiteOutput = Join-Path -Path $RepoRoot "apidocs\_site\*.*"
+$NgDocsSiteOutput = Join-Path -Path $RepoRoot "src\Umbraco.Web.UI.Client\docs\api\*.*"
+$ProgFiles86 = [Environment]::GetEnvironmentVariable("ProgramFiles(x86)");
+$MSBuild = "$ProgFiles86\MSBuild\14.0\Bin\MSBuild.exe"
-if (-not (Test-Path Env:\SHFBROOT))
-{
- throw "The docs cannot be build, install Sandcastle help file builder"
+
+################ Do the UI docs
+
+"Changing to Umbraco.Web.UI.Client folder"
+cd ..
+cd src\Umbraco.Web.UI.Client
+Write-Host $(Get-Location)
+
+"Creating build folder so MSBuild doesn't run the whole grunt build"
+if (-Not (Test-Path "build")) {
+ md "build"
}
-$PSScriptFilePath = (Get-Item $MyInvocation.MyCommand.Path).FullName
-$BuildRoot = Split-Path -Path $PSScriptFilePath -Parent
-$OutputPath = Join-Path -Path $BuildRoot -ChildPath "ApiDocs\Output"
-$ProjFile = Join-Path -Path $BuildRoot -ChildPath "ApiDocs\csharp-api-docs.shfbproj"
+"Installing node"
+# Check if Install-Product exists, should only exist on the build server
+if (Get-Command Install-Product -errorAction SilentlyContinue)
+{
+ Install-Product node ''
+}
-"Building docs with project file: $ProjFile"
+"Installing node modules"
+& npm install
-$MSBuild = "$Env:SYSTEMROOT\Microsoft.NET\Framework\v4.0.30319\msbuild.exe"
+"Installing grunt"
+& npm install -g grunt-cli
-# build it!
-& $MSBuild "$ProjFile"
+"Moving back to build folder"
+cd ..
+cd ..
+cd build
+Write-Host $(Get-Location)
-# remove files left over
-Remove-Item $BuildRoot\* -include csharp-api-docs.shfbproj_*
+ & grunt --gruntfile ../src/umbraco.web.ui.client/gruntfile.js docs
-# copy our custom styles in
-Copy-Item $BuildRoot\ApiDocs\TOC.css $OutputPath\TOC.css
+# change baseUrl
+$BaseUrl = "https://our.umbraco.org/apidocs/ui/"
+$IndexPath = "../src/umbraco.web.ui.client/docs/api/index.html"
+(Get-Content $IndexPath).replace('location.href.replace(rUrl, indexFile)', "`'" + $BaseUrl + "`'") | Set-Content $IndexPath
+# zip it
-""
-"Done!"
\ No newline at end of file
+& $7Zip a -tzip ui-docs.zip $NgDocsSiteOutput -r
+
+################ Do the c# docs
+
+# Build the solution in debug mode
+$SolutionPath = Join-Path -Path $SolutionRoot -ChildPath "umbraco.sln"
+& $MSBuild "$SolutionPath" /p:Configuration=Debug /maxcpucount /t:Clean
+if (-not $?)
+{
+ throw "The MSBuild process returned an error code."
+}
+& $MSBuild "$SolutionPath" /p:Configuration=Debug /maxcpucount
+if (-not $?)
+{
+ throw "The MSBuild process returned an error code."
+}
+
+# Go get docfx if we don't hae it
+$FileExists = Test-Path $DocFx
+If ($FileExists -eq $False) {
+
+ If(!(Test-Path $DocFxFolder))
+ {
+ New-Item $DocFxFolder -type directory
+ }
+
+ $DocFxZip = Join-Path -Path $ToolsRoot "docfx\docfx.zip"
+ $DocFxSource = "https://github.com/dotnet/docfx/releases/download/v1.9.4/docfx.zip"
+ Invoke-WebRequest $DocFxSource -OutFile $DocFxZip
+
+ #unzip it
+ & $7Zip e $DocFxZip "-o$DocFxFolder"
+}
+
+#clear site
+If(Test-Path(Join-Path -Path $RepoRoot "apidocs\_site"))
+{
+ Remove-Item $DocFxSiteOutput -recurse
+}
+
+# run it!
+& $DocFx metadata $DocFxJson
+& $DocFx build $DocFxJson
+
+# zip it
+
+& $7Zip a -tzip csharp-docs.zip $DocFxSiteOutput -r
diff --git a/build/InstallGit.cmd b/build/InstallGit.cmd
index b6ba71df9b..e009e2594e 100644
--- a/build/InstallGit.cmd
+++ b/build/InstallGit.cmd
@@ -1,23 +1,33 @@
@ECHO OFF
SETLOCAL
-REM SETLOCAL is on, so changes to the path not persist to the actual user's path
+ :: SETLOCAL is on, so changes to the path not persist to the actual user's path
-git.exe 2> NUL
-if %ERRORLEVEL%==9009 GOTO :trydefaultpath
+git.exe --version
+IF %ERRORLEVEL%==9009 GOTO :trydefaultpath
GOTO :EOF
+ :: Git is installed, no need to to anything else
:trydefaultpath
-path=C:\Program Files (x86)\Git\cmd;C:\Program Files\Git\cmd;%PATH%
-git.exe 2> NUL
-if %ERRORLEVEL%==9009 GOTO :showerror
+PATH=C:\Program Files (x86)\Git\cmd;C:\Program Files\Git\cmd;%PATH%
+git.exe --version
+IF %ERRORLEVEL%==9009 GOTO :showerror
GOTO :EOF
+ :: Git is installed, no need to to anything else
:showerror
ECHO Git is not in your path and could not be found in C:\Program Files (x86)\Git\cmd nor in C:\Program Files\Git\cmd
-set /p install=" Do you want to install Git through Chocolatey [y/n]? " %=%
-if %install%==y (
+SET /p install=" Do you want to install Git through Chocolatey [y/n]? " %=%
+IF %install%==y (
+ :: Create a temporary batch file to execute either after elevating to admin or as-is when the user is already admin
+ ECHO @ECHO OFF > "%temp%\ChocoInstallGit.cmd"
+ ECHO SETLOCAL >> "%temp%\ChocoInstallGit.cmd"
+ ECHO ECHO Installing Chocolatey first >> "%temp%\ChocoInstallGit.cmd"
+ ECHO @powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" >> "%temp%\ChocoInstallGit.cmd"
+ ECHO SET PATH=%%PATH%%;%%ALLUSERSPROFILE%%\chocolatey\bin >> "%temp%\ChocoInstallGit.cmd"
+ ECHO choco install git -y >> "%temp%\ChocoInstallGit.cmd"
+
GOTO :installgit
-) else (
+) ELSE (
GOTO :cantcontinue
)
@@ -26,7 +36,28 @@ ECHO Can't complete the build without Git being in the path. Please add it to be
GOTO :EOF
:installgit
-ECHO Installing Chocolatey first
-@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
-ECHO Installing Git through Chocolatey
-choco install git
\ No newline at end of file
+pushd %~dp0
+ :: Running prompt elevated
+
+:: --> Check for permissions
+>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
+
+:: --> If error flag set, we do not have admin.
+IF '%errorlevel%' NEQ '0' (
+ GOTO UACPrompt
+) ELSE ( GOTO gotAdmin )
+
+:UACPrompt
+ ECHO You're not currently running this with admin privileges, we'll now try to execute the install of Git through Chocolatey after elevating to admin privileges
+ ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
+ ECHO UAC.ShellExecute "%temp%\ChocoInstallGit.cmd", "", "", "runas", 1 >> "%temp%\getadmin.vbs"
+
+ "%temp%\getadmin.vbs"
+ EXIT /B
+
+:gotAdmin
+ IF EXIST "%temp%\getadmin.vbs" ( DEL "%temp%\getadmin.vbs" )
+ pushd "%CD%"
+ CD /D "%~dp0"
+
+ CALL "%temp%\ChocoInstallGit.cmd"
\ No newline at end of file
diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec
index 72733c5800..dbc7be00e4 100644
--- a/build/NuSpecs/UmbracoCms.Core.nuspec
+++ b/build/NuSpecs/UmbracoCms.Core.nuspec
@@ -27,15 +27,17 @@
-
+
+
-
-
-
-
+
+
+
+
+
diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec
index 66e82ac488..6903c34d8d 100644
--- a/build/NuSpecs/UmbracoCms.nuspec
+++ b/build/NuSpecs/UmbracoCms.nuspec
@@ -17,7 +17,7 @@
-
+
@@ -32,6 +32,7 @@
+
diff --git a/build/NuSpecs/tools/Dashboard.config.install.xdt b/build/NuSpecs/tools/Dashboard.config.install.xdt
index a77632926c..8368870186 100644
--- a/build/NuSpecs/tools/Dashboard.config.install.xdt
+++ b/build/NuSpecs/tools/Dashboard.config.install.xdt
@@ -21,6 +21,12 @@
+
+
views/dashboard/developer/developerdashboardvideos.html
@@ -30,16 +36,21 @@
-
+
views/dashboard/developer/examinemanagement.html
-
-
+
+
- views/dashboard/developer/xmldataintegrityreport.html
+ views/dashboard/developer/healthcheck.html
-
+
+
+
+ views/dashboard/developer/redirecturls.html
+
+
-
-
-
-
- admin
-
-
- views/dashboard/default/startupdashboardintro.html
-
-
-
-
-
@@ -80,5 +78,6 @@
\ No newline at end of file
diff --git a/build/NuSpecs/tools/Web.config.install.xdt b/build/NuSpecs/tools/Web.config.install.xdt
index dfb9925840..987db6c3d6 100644
--- a/build/NuSpecs/tools/Web.config.install.xdt
+++ b/build/NuSpecs/tools/Web.config.install.xdt
@@ -292,6 +292,8 @@
+
+
diff --git a/build/NuSpecs/tools/install.ps1 b/build/NuSpecs/tools/install.ps1
index de7a6cc16e..0e62fb0749 100644
--- a/build/NuSpecs/tools/install.ps1
+++ b/build/NuSpecs/tools/install.ps1
@@ -77,8 +77,33 @@ if ($project) {
{
$packageWebConfigSource = Join-Path $installPath "UmbracoFiles\Web.config"
Copy-Item $packageWebConfigSource $destinationWebConfig -Force
- }
+ # Copy files that don't get automatically copied for Website projects
+ # We do this here, when copyWebconfig is true because we only want to do it for new installs
+ # If this is an upgrade then the files should already be there
+ $splashesSource = Join-Path $installPath "UmbracoFiles\Config\splashes\*.*"
+ $splashesDestination = Join-Path $projectPath "Config\splashes\"
+ New-Item $splashesDestination -Type directory
+ Copy-Item $splashesSource $splashesDestination -Force
+
+ $sqlCe64Source = Join-Path $installPath "UmbracoFiles\bin\amd64\*"
+ $sqlCe64Destination = Join-Path $projectPath "bin\amd64\"
+ Copy-Item $sqlCe64Source $sqlCe64Destination -Force
+
+ $sqlCex86Source = Join-Path $installPath "UmbracoFiles\bin\x86\*"
+ $sqlCex86Destination = Join-Path $projectPath "bin\x86\"
+ Copy-Item $sqlCex86source $sqlCex86Destination -Force
+
+ $umbracoUIXMLSource = Join-Path $installPath "UmbracoFiles\Umbraco\Config\Create\UI.xml"
+ $umbracoUIXMLDestination = Join-Path $projectPath "Umbraco\Config\Create\UI.xml"
+ Copy-Item $umbracoUIXMLSource $umbracoUIXMLDestination -Force
+ } else {
+ $upgradeViewSource = Join-Path $umbracoFolderSource "Views\install\*"
+ $upgradeView = Join-Path $umbracoFolder "Views\install\"
+ Write-Host "Copying2 ${upgradeViewSource} to ${upgradeView}"
+ Copy-Item $upgradeViewSource $upgradeView -Force
+ }
+
$installFolder = Join-Path $projectPath "Install"
if(Test-Path $installFolder) {
Remove-Item $installFolder -Force -Recurse -Confirm:$false
diff --git a/build/NuSpecs/tools/trees.config.install.xdt b/build/NuSpecs/tools/trees.config.install.xdt
index 580c619547..a9fbf07762 100644
--- a/build/NuSpecs/tools/trees.config.install.xdt
+++ b/build/NuSpecs/tools/trees.config.install.xdt
@@ -55,21 +55,29 @@
xdt:Transform="SetAttributes()" />
-
-
+ xdt:Transform="Remove" />
+
+
+
+
+
+
+
+
-
-
diff --git a/src/SQLCE4Umbraco/SqlCEHelper.cs b/src/SQLCE4Umbraco/SqlCEHelper.cs
index 26a781360e..ab6f686c21 100644
--- a/src/SQLCE4Umbraco/SqlCEHelper.cs
+++ b/src/SQLCE4Umbraco/SqlCEHelper.cs
@@ -40,15 +40,10 @@ namespace SqlCE4Umbraco
var localConnection = new SqlCeConnection(ConnectionString);
if (!System.IO.File.Exists(ReplaceDataDirectory(localConnection.Database)))
{
- var sqlCeEngine = new SqlCeEngine(ConnectionString);
- sqlCeEngine.CreateDatabase();
-
- // SD: Pretty sure this should be in a using clause but i don't want to cause unknown side-effects here
- // since it's been like this for quite some time
- //using (var sqlCeEngine = new SqlCeEngine(ConnectionString))
- //{
- // sqlCeEngine.CreateDatabase();
- //}
+ using (var sqlCeEngine = new SqlCeEngine(ConnectionString))
+ {
+ sqlCeEngine.CreateDatabase();
+ }
}
}
diff --git a/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs b/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs
index ca1f4e85a0..792b5982b1 100644
--- a/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/HttpRequestCacheProvider.cs
@@ -9,6 +9,9 @@ namespace Umbraco.Core.Cache
///
/// A cache provider that caches items in the HttpContext.Items
///
+ ///
+ /// If the Items collection is null, then this provider has no effect
+ ///
internal class HttpRequestCacheProvider : DictionaryCacheProviderBase
{
// context provider
@@ -34,6 +37,11 @@ namespace Umbraco.Core.Cache
get { return _context != null ? _context.Items : HttpContext.Current.Items; }
}
+ private bool HasContextItems
+ {
+ get { return (_context != null && _context.Items != null) || HttpContext.Current != null; }
+ }
+
// for unit tests
public HttpRequestCacheProvider(HttpContextBase context)
{
@@ -50,18 +58,23 @@ namespace Umbraco.Core.Cache
protected override IEnumerable GetDictionaryEntries()
{
const string prefix = CacheItemPrefix + "-";
+
+ if (HasContextItems == false) return Enumerable.Empty();
+
return ContextItems.Cast()
.Where(x => x.Key is string && ((string)x.Key).StartsWith(prefix));
}
protected override void RemoveEntry(string key)
{
+ if (HasContextItems == false) return;
+
ContextItems.Remove(key);
}
protected override object GetEntry(string key)
{
- return ContextItems[key];
+ return HasContextItems ? ContextItems[key] : null;
}
#region Lock
@@ -81,7 +94,9 @@ namespace Umbraco.Core.Cache
get
{
- return new MonitorLock(ContextItems.SyncRoot);
+ return HasContextItems
+ ? (IDisposable) new MonitorLock(ContextItems.SyncRoot)
+ : new NoopLocker();
}
}
@@ -91,6 +106,9 @@ namespace Umbraco.Core.Cache
public override object GetCacheItem(string cacheKey, Func getCacheItem)
{
+ //no place to cache so just return the callback result
+ if (HasContextItems == false) return getCacheItem();
+
cacheKey = GetCacheKey(cacheKey);
Lazy result;
@@ -128,5 +146,10 @@ namespace Umbraco.Core.Cache
#region Insert
#endregion
+ private class NoopLocker : DisposableObject
+ {
+ protected override void DisposeResources()
+ { }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/NullCacheProvider.cs b/src/Umbraco.Core/Cache/NullCacheProvider.cs
index f4e449499b..6b797307ac 100644
--- a/src/Umbraco.Core/Cache/NullCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/NullCacheProvider.cs
@@ -5,38 +5,31 @@ using System.Web.Caching;
namespace Umbraco.Core.Cache
{
- internal class NullCacheProvider : IRuntimeCacheProvider
+ ///
+ /// Represents a cache provider that does not cache anything.
+ ///
+ public class NullCacheProvider : IRuntimeCacheProvider
{
public virtual void ClearAllCache()
- {
- }
+ { }
public virtual void ClearCacheItem(string key)
- {
- }
+ { }
public virtual void ClearCacheObjectTypes(string typeName)
- {
- }
+ { }
public virtual void ClearCacheObjectTypes()
- {
- }
+ { }
public virtual void ClearCacheObjectTypes(Func predicate)
- {
- }
-
-
-
+ { }
public virtual void ClearCacheByKeySearch(string keyStartsWith)
- {
- }
+ { }
public virtual void ClearCacheByKeyExpression(string regexString)
- {
- }
+ { }
public virtual IEnumerable GetCacheItemsByKeySearch(string keyStartsWith)
{
@@ -64,8 +57,6 @@ namespace Umbraco.Core.Cache
}
public void InsertCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
- {
-
- }
+ { }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs
index 8afa5639f1..feccba03b4 100644
--- a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs
@@ -1,23 +1,23 @@
using System;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Linq;
-using System.Reflection;
using System.Runtime.Caching;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web.Caching;
-using Umbraco.Core.Logging;
using CacheItemPriority = System.Web.Caching.CacheItemPriority;
namespace Umbraco.Core.Cache
{
///
+ /// Represents a cache provider that caches item in a .
/// A cache provider that wraps the logic of a System.Runtime.Caching.ObjectCache
///
- internal class ObjectCacheRuntimeCacheProvider : IRuntimeCacheProvider
+ /// The is created with name "in-memory". That name is
+ /// used to retrieve configuration options. It does not identify the memory cache, i.e.
+ /// each instance of this class has its own, independent, memory cache.
+ public class ObjectCacheRuntimeCacheProvider : IRuntimeCacheProvider
{
-
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
internal ObjectCache MemoryCache;
diff --git a/src/Umbraco.Core/Cache/StaticCacheProvider.cs b/src/Umbraco.Core/Cache/StaticCacheProvider.cs
index 9c448efa6a..c7fd00d39a 100644
--- a/src/Umbraco.Core/Cache/StaticCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/StaticCacheProvider.cs
@@ -3,14 +3,13 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
-using System.Web.Caching;
namespace Umbraco.Core.Cache
{
///
- /// A cache provider that statically caches everything in an in memory dictionary
+ /// Represents a cache provider that statically caches item in a concurrent dictionary.
///
- internal class StaticCacheProvider : ICacheProvider
+ public class StaticCacheProvider : ICacheProvider
{
internal readonly ConcurrentDictionary StaticCache = new ConcurrentDictionary();
@@ -75,7 +74,6 @@ namespace Umbraco.Core.Cache
public virtual object GetCacheItem(string cacheKey, Func getCacheItem)
{
return StaticCache.GetOrAdd(cacheKey, key => getCacheItem());
- }
-
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
index 1b1404a897..d743daca6a 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
@@ -291,7 +291,19 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
true);
}
}
-
+
+ [ConfigurationProperty("EnableInheritedMediaTypes")]
+ internal InnerTextConfigurationElement EnableInheritedMediaTypes
+ {
+ get
+ {
+ return new OptionalInnerTextConfigurationElement(
+ (InnerTextConfigurationElement)this["EnableInheritedMediaTypes"],
+ //set the default
+ true);
+ }
+ }
+
string IContentSection.NotificationEmailAddress
{
get { return Notifications.NotificationEmailAddress; }
@@ -431,5 +443,10 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
{
get { return EnableInheritedDocumentTypes; }
}
+
+ bool IContentSection.EnableInheritedMediaTypes
+ {
+ get { return EnableInheritedMediaTypes; }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
index ebdd9ae637..3d5e4435b6 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
@@ -61,5 +61,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
string DefaultDocumentTypeProperty { get; }
bool EnableInheritedDocumentTypes { get; }
+
+ bool EnableInheritedMediaTypes { get; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs
index 2998fc2f78..9eb6d02aa7 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSection.cs
@@ -9,6 +9,8 @@
bool DisableAlternativeTemplates { get; }
bool DisableFindContentByIdPath { get; }
+
+ bool DisableRedirectUrlTracking { get; }
string UrlProviderMode { get; }
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/WebRoutingElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/WebRoutingElement.cs
index 1ed9bc034c..82f5d46b28 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/WebRoutingElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/WebRoutingElement.cs
@@ -27,6 +27,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return (bool) base["disableFindContentByIdPath"]; }
}
+ [ConfigurationProperty("disableRedirectUrlTracking", DefaultValue = "false")]
+ public bool DisableRedirectUrlTracking
+ {
+ get { return (bool) base["disableRedirectUrlTracking"]; }
+ }
+
[ConfigurationProperty("urlProviderMode", DefaultValue = "AutoLegacy")]
public string UrlProviderMode
{
diff --git a/src/Umbraco.Core/Constants-Applications.cs b/src/Umbraco.Core/Constants-Applications.cs
index 12f7076fc4..fb1fb42044 100644
--- a/src/Umbraco.Core/Constants-Applications.cs
+++ b/src/Umbraco.Core/Constants-Applications.cs
@@ -73,6 +73,11 @@
///
public const string DataTypes = "dataTypes";
+ ///
+ /// alias for the packages tree
+ ///
+ public const string Packages = "packager";
+
///
/// alias for the dictionary tree.
///
diff --git a/src/Umbraco.Core/Constants-Examine.cs b/src/Umbraco.Core/Constants-Examine.cs
index 4ff6115749..9b1de812f7 100644
--- a/src/Umbraco.Core/Constants-Examine.cs
+++ b/src/Umbraco.Core/Constants-Examine.cs
@@ -1,15 +1,23 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Umbraco.Core
+namespace Umbraco.Core
{
public static partial class Constants
{
public static class Examine
{
+ ///
+ /// The alias of the internal member indexer
+ ///
+ public const string InternalMemberIndexer = "InternalMemberIndexer";
+
+ ///
+ /// The alias of the internal content indexer
+ ///
+ public const string InternalIndexer = "InternalIndexer";
+
+ ///
+ /// The alias of the external content indexer
+ ///
+ public const string ExternalIndexer = "ExternalIndexer";
///
/// The alias of the internal member searcher
///
@@ -19,6 +27,11 @@ namespace Umbraco.Core
/// The alias of the internal content searcher
///
public const string InternalSearcher = "InternalSearcher";
+
+ ///
+ /// The alias of the external content searcher
+ ///
+ public const string ExternalSearcher = "ExternalSearcher";
}
}
}
diff --git a/src/Umbraco.Core/Constants-ObjectTypes.cs b/src/Umbraco.Core/Constants-ObjectTypes.cs
index 560cd4b306..7ec45db7be 100644
--- a/src/Umbraco.Core/Constants-ObjectTypes.cs
+++ b/src/Umbraco.Core/Constants-ObjectTypes.cs
@@ -143,7 +143,10 @@ namespace Umbraco.Core
///
public const string LockObject = "87A9F1FF-B1E4-4A25-BABB-465A4A47EC41";
-
+ ///
+ /// Guid for a Lock object.
+ ///
+ public static readonly Guid LockObjectGuid = new Guid(LockObject);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs
index 2f7d247b36..80f118b58e 100644
--- a/src/Umbraco.Core/Constants-PropertyEditors.cs
+++ b/src/Umbraco.Core/Constants-PropertyEditors.cs
@@ -11,7 +11,7 @@ namespace Umbraco.Core
{
///
/// Used to prefix generic properties that are internal content properties
- ///
+ ///
public const string InternalGenericPropertiesPrefix = "_umb_";
///
@@ -74,7 +74,7 @@ namespace Umbraco.Core
///
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string DictionaryPicker = "17B70066-F764-407D-AB05-3717F1E1C513";
-
+
///
/// Guid for the Dropdown list datatype.
///
@@ -352,7 +352,7 @@ namespace Umbraco.Core
///
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string UltimatePicker = "CDBF0B5D-5CB2-445F-BC12-FCAAEC07CF2C";
-
+
///
/// Guid for the UltraSimpleEditor datatype.
///
@@ -369,7 +369,7 @@ namespace Umbraco.Core
///
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string UmbracoUserControlWrapper = "D15E1281-E456-4B24-AA86-1DDA3E4299D5";
-
+
///
/// Guid for the Upload field datatype.
///
@@ -419,6 +419,15 @@ namespace Umbraco.Core
/// Alias for the email address property editor
///
public const string EmailAddressAlias = "Umbraco.EmailAddress";
+
+ public static class PreValueKeys
+ {
+ ///
+ /// Pre-value name used to indicate a field that can be used to override the database field to which data for the associated
+ /// property is saved
+ ///
+ public const string DataValueType = "umbracoDataValueType";
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs
index 82e3a1ff3f..4a30db9cd8 100644
--- a/src/Umbraco.Core/Constants-System.cs
+++ b/src/Umbraco.Core/Constants-System.cs
@@ -1,33 +1,40 @@
namespace Umbraco.Core
{
- public static partial class Constants
- {
- ///
- /// Defines the identifiers for Umbraco system nodes.
- ///
- public static class System
- {
- ///
- /// The integer identifier for global system root node.
- ///
- public const int Root = -1;
+ public static partial class Constants
+ {
+ ///
+ /// Defines the identifiers for Umbraco system nodes.
+ ///
+ public static class System
+ {
+ ///
+ /// The integer identifier for global system root node.
+ ///
+ public const int Root = -1;
- ///
- /// The integer identifier for content's recycle bin.
- ///
- public const int RecycleBinContent = -20;
+ ///
+ /// The integer identifier for content's recycle bin.
+ ///
+ public const int RecycleBinContent = -20;
- ///
- /// The integer identifier for media's recycle bin.
- ///
- public const int RecycleBinMedia = -21;
+ ///
+ /// The integer identifier for media's recycle bin.
+ ///
+ public const int RecycleBinMedia = -21;
- public const int DefaultContentListViewDataTypeId = -95;
+ public const int DefaultContentListViewDataTypeId = -95;
public const int DefaultMediaListViewDataTypeId = -96;
public const int DefaultMembersListViewDataTypeId = -97;
// identifiers for lock objects
- public const int ServersLock = -331;
- }
- }
+ public const int ServersLock = -331;
+ }
+
+ public static class DatabaseProviders
+ {
+ public const string SqlCe = "System.Data.SqlServerCe.4.0";
+ public const string SqlServer = "System.Data.SqlClient";
+ public const string MySql = "MySql.Data.MySqlClient";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs
index 7f8cbbf0f7..05aba6b97d 100644
--- a/src/Umbraco.Core/DatabaseContext.cs
+++ b/src/Umbraco.Core/DatabaseContext.cs
@@ -135,7 +135,7 @@ namespace Umbraco.Core
if (string.IsNullOrEmpty(_providerName) == false)
return _providerName;
- _providerName = "System.Data.SqlClient";
+ _providerName = Constants.DatabaseProviders.SqlServer;
if (ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName] != null)
{
if (string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName) == false)
@@ -212,10 +212,10 @@ namespace Umbraco.Core
{
var provider = DbConnectionExtensions.DetectProviderFromConnectionString(connectionString);
var databaseProvider = provider.ToString();
- var providerName = "System.Data.SqlClient";
+ var providerName = Constants.DatabaseProviders.SqlServer;
if (databaseProvider.ToLower().Contains("mysql"))
{
- providerName = "MySql.Data.MySqlClient";
+ providerName = Constants.DatabaseProviders.MySql;
}
SaveConnectionString(connectionString, providerName);
Initialize(string.Empty);
@@ -240,10 +240,10 @@ namespace Umbraco.Core
public string GetDatabaseConnectionString(string server, string databaseName, string user, string password, string databaseProvider, out string providerName)
{
- providerName = "System.Data.SqlClient";
+ providerName = Constants.DatabaseProviders.SqlServer;
if (databaseProvider.ToLower().Contains("mysql"))
{
- providerName = "MySql.Data.MySqlClient";
+ providerName = Constants.DatabaseProviders.MySql;
return string.Format("Server={0}; Database={1};Uid={2};Pwd={3}", server, databaseName, user, password);
}
if (databaseProvider.ToLower().Contains("azure"))
@@ -260,7 +260,7 @@ namespace Umbraco.Core
/// Name of the database
public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName)
{
- const string providerName = "System.Data.SqlClient";
+ const string providerName = Constants.DatabaseProviders.SqlServer;
var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName);
SaveConnectionString(connectionString, providerName);
Initialize(providerName);
@@ -373,7 +373,7 @@ namespace Umbraco.Core
var databaseSettings = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName];
if (databaseSettings != null && string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) == false && string.IsNullOrWhiteSpace(databaseSettings.ProviderName) == false)
{
- var providerName = "System.Data.SqlClient";
+ var providerName = Constants.DatabaseProviders.SqlServer;
string connString = null;
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName))
{
@@ -381,8 +381,7 @@ namespace Umbraco.Core
connString = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ConnectionString;
}
Initialize(providerName, connString);
-
- DetermineSqlServerVersion();
+
}
else if (ConfigurationManager.AppSettings.ContainsKey(GlobalSettings.UmbracoConnectionName) && string.IsNullOrEmpty(ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName]) == false)
{
@@ -395,8 +394,8 @@ namespace Umbraco.Core
else if (legacyConnString.ToLowerInvariant().Contains("tcp:"))
{
//Must be sql azure
- SaveConnectionString(legacyConnString, "System.Data.SqlClient");
- Initialize("System.Data.SqlClient");
+ SaveConnectionString(legacyConnString, Constants.DatabaseProviders.SqlServer);
+ Initialize(Constants.DatabaseProviders.SqlServer);
}
else if (legacyConnString.ToLowerInvariant().Contains("datalayer=mysql"))
{
@@ -407,20 +406,19 @@ namespace Umbraco.Core
foreach (var variable in legacyConnString.Split(';').Where(x => x.ToLowerInvariant().StartsWith("datalayer") == false))
connectionStringWithoutDatalayer = string.Format("{0}{1};", connectionStringWithoutDatalayer, variable);
- SaveConnectionString(connectionStringWithoutDatalayer, "MySql.Data.MySqlClient");
- Initialize("MySql.Data.MySqlClient");
+ SaveConnectionString(connectionStringWithoutDatalayer, Constants.DatabaseProviders.MySql);
+ Initialize(Constants.DatabaseProviders.MySql);
}
else
{
//Must be sql
- SaveConnectionString(legacyConnString, "System.Data.SqlClient");
- Initialize("System.Data.SqlClient");
+ SaveConnectionString(legacyConnString, Constants.DatabaseProviders.SqlServer);
+ Initialize(Constants.DatabaseProviders.SqlServer);
}
//Remove the legacy connection string, so we don't end up in a loop if something goes wrong.
GlobalSettings.RemoveSetting(GlobalSettings.UmbracoConnectionName);
-
- DetermineSqlServerVersion();
+
}
else
{
@@ -465,49 +463,6 @@ namespace Umbraco.Core
Initialize(providerName);
}
- ///
- /// Set the lazy resolution of determining the SQL server version if that is the db type we're using
- ///
- private void DetermineSqlServerVersion()
- {
-
- var sqlServerSyntax = SqlSyntax as SqlServerSyntaxProvider;
- if (sqlServerSyntax != null)
- {
- //this will not execute now, it is lazy so will only execute when we need to actually know
- // the sql server version.
- sqlServerSyntax.VersionName = new Lazy(() =>
- {
- try
- {
- var database = this._factory.CreateDatabase();
-
- var version = database.ExecuteScalar("SELECT SERVERPROPERTY('productversion')");
- var firstPart = version.Split('.')[0];
- switch (firstPart)
- {
- case "11":
- return SqlServerVersionName.V2012;
- case "10":
- return SqlServerVersionName.V2008;
- case "9":
- return SqlServerVersionName.V2005;
- case "8":
- return SqlServerVersionName.V2000;
- case "7":
- return SqlServerVersionName.V7;
- default:
- return SqlServerVersionName.Other;
- }
- }
- catch (Exception)
- {
- return SqlServerVersionName.Invalid;
- }
- });
- }
- }
-
internal DatabaseSchemaResult ValidateDatabaseSchema()
{
if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName)))
@@ -517,7 +472,7 @@ namespace Umbraco.Core
{
if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted
- && ProviderName == "MySql.Data.MySqlClient")
+ && ProviderName == Constants.DatabaseProviders.MySql)
{
throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration");
}
@@ -625,13 +580,8 @@ namespace Umbraco.Core
var installedSchemaVersion = new SemVersion(schemaResult.DetermineInstalledVersion());
- var installedMigrationVersion = new SemVersion(0);
- //we cannot check the migrations table if it doesn't exist, this will occur when upgrading to 7.3
- if (schemaResult.ValidTables.Any(x => x.InvariantEquals("umbracoMigration")))
- {
- installedMigrationVersion = schemaResult.DetermineInstalledVersionByMigrations(migrationEntryService);
- }
-
+ var installedMigrationVersion = schemaResult.DetermineInstalledVersionByMigrations(migrationEntryService);
+
var targetVersion = UmbracoVersion.Current;
//In some cases - like upgrading from 7.2.6 -> 7.3, there will be no migration information in the database and therefore it will
@@ -731,7 +681,7 @@ namespace Umbraco.Core
private Attempt CheckReadyForInstall()
{
if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted
- && ProviderName == "MySql.Data.MySqlClient")
+ && ProviderName == Constants.DatabaseProviders.MySql)
{
throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration");
}
@@ -780,7 +730,7 @@ namespace Umbraco.Core
{
var dbIsSqlCe = false;
if (databaseSettings != null && databaseSettings.ProviderName != null)
- dbIsSqlCe = databaseSettings.ProviderName == "System.Data.SqlServerCe.4.0";
+ dbIsSqlCe = databaseSettings.ProviderName == Constants.DatabaseProviders.SqlCe;
var sqlCeDatabaseExists = false;
if (dbIsSqlCe)
{
diff --git a/src/Umbraco.Core/DecimalExtensions.cs b/src/Umbraco.Core/DecimalExtensions.cs
new file mode 100644
index 0000000000..b4d74fdb2e
--- /dev/null
+++ b/src/Umbraco.Core/DecimalExtensions.cs
@@ -0,0 +1,23 @@
+namespace Umbraco.Core
+{
+ ///
+ /// Provides extension methods for System.Decimal.
+ ///
+ /// See System.Decimal on MSDN and also
+ /// http://stackoverflow.com/questions/4298719/parse-decimal-and-filter-extra-0-on-the-right/4298787#4298787.
+ ///
+ public static class DecimalExtensions
+ {
+ ///
+ /// Gets the normalized value.
+ ///
+ /// The value to normalize.
+ /// The normalized value.
+ /// Normalizing changes the scaling factor and removes trailing zeroes,
+ /// so 1.2500m comes out as 1.25m.
+ public static decimal Normalize(this decimal value)
+ {
+ return value / 1.000000000000000000000000000000000m;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs
index 98fdb01ff4..2dfad2d103 100644
--- a/src/Umbraco.Core/IO/SystemDirectories.cs
+++ b/src/Umbraco.Core/IO/SystemDirectories.cs
@@ -69,7 +69,16 @@ namespace Umbraco.Core.IO
}
}
- public static string AppPlugins
+ public static string AppCode
+ {
+ get
+ {
+ //NOTE: this is not configurable and shouldn't need to be
+ return "~/App_Code";
+ }
+ }
+
+ public static string AppPlugins
{
get
{
diff --git a/src/Umbraco.Core/Logging/AsyncForwardingAppenderBase.cs b/src/Umbraco.Core/Logging/AsyncForwardingAppenderBase.cs
index 74a1de81f4..fcb0f183ec 100644
--- a/src/Umbraco.Core/Logging/AsyncForwardingAppenderBase.cs
+++ b/src/Umbraco.Core/Logging/AsyncForwardingAppenderBase.cs
@@ -1,20 +1,21 @@
-using System;
using log4net.Appender;
using log4net.Core;
using log4net.Util;
+using System;
+using System.Runtime.Remoting.Messaging;
namespace Umbraco.Core.Logging
{
- ///
- /// Based on https://github.com/cjbhaines/Log4Net.Async
- ///
+ ///
+ /// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
+ ///
public abstract class AsyncForwardingAppenderBase : ForwardingAppender
{
#region Private Members
private const FixFlags DefaultFixFlags = FixFlags.Partial;
- private FixFlags _fixFlags = DefaultFixFlags;
- private LoggingEventHelper _loggingEventHelper;
+ private FixFlags fixFlags = DefaultFixFlags;
+ private LoggingEventHelper loggingEventHelper;
#endregion Private Members
@@ -22,10 +23,25 @@ namespace Umbraco.Core.Logging
public FixFlags Fix
{
- get { return _fixFlags; }
+ get { return fixFlags; }
set { SetFixFlags(value); }
}
+ ///
+ /// Returns HttpContext.Current
+ ///
+ protected internal object HttpContext
+ {
+ get
+ {
+ return CallContext.HostContext;
+ }
+ set
+ {
+ CallContext.HostContext = value;
+ }
+ }
+
///
/// The logger name that will be used for logging internal errors.
///
@@ -38,7 +54,7 @@ namespace Umbraco.Core.Logging
public override void ActivateOptions()
{
base.ActivateOptions();
- _loggingEventHelper = new LoggingEventHelper(InternalLoggerName, DefaultFixFlags);
+ loggingEventHelper = new LoggingEventHelper(InternalLoggerName, DefaultFixFlags);
InitializeAppenders();
}
@@ -52,10 +68,10 @@ namespace Umbraco.Core.Logging
private void SetFixFlags(FixFlags newFixFlags)
{
- if (newFixFlags != _fixFlags)
+ if (newFixFlags != fixFlags)
{
- _loggingEventHelper.Fix = newFixFlags;
- _fixFlags = newFixFlags;
+ loggingEventHelper.Fix = newFixFlags;
+ fixFlags = newFixFlags;
InitializeAppenders();
}
}
@@ -84,7 +100,7 @@ namespace Umbraco.Core.Logging
protected void ForwardInternalError(string message, Exception exception, Type thisType)
{
LogLog.Error(thisType, message, exception);
- var loggingEvent = _loggingEventHelper.CreateLoggingEvent(Level.Error, message, exception);
+ var loggingEvent = loggingEventHelper.CreateLoggingEvent(Level.Error, message, exception);
ForwardLoggingEvent(loggingEvent, thisType);
}
diff --git a/src/Umbraco.Core/Logging/AsynchronousRollingFileAppender.cs b/src/Umbraco.Core/Logging/AsynchronousRollingFileAppender.cs
index cb58ebbfaa..c226bd03c8 100644
--- a/src/Umbraco.Core/Logging/AsynchronousRollingFileAppender.cs
+++ b/src/Umbraco.Core/Logging/AsynchronousRollingFileAppender.cs
@@ -1,6 +1,7 @@
using log4net.Core;
using log4net.Util;
using System;
+using System.ComponentModel;
using System.Runtime.Remoting.Messaging;
using System.Security.Principal;
using System.Threading;
@@ -12,7 +13,11 @@ namespace Umbraco.Core.Logging
///
/// Based on https://github.com/cjbhaines/Log4Net.Async
/// which is based on code by Chris Haines http://cjbhaines.wordpress.com/2012/02/13/asynchronous-log4net-appenders/
+ /// This is an old/deprecated logger and has been superceded by ParallelForwardingAppender which is included in Umbraco and
+ /// also by AsyncForwardingAppender in the Log4Net.Async library.
///
+ [Obsolete("This is superceded by the ParallelForwardingAppender, this will be removed in v8")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
public class AsynchronousRollingFileAppender : RollingFileAppender
{
private RingBuffer pendingAppends;
@@ -198,79 +203,4 @@ namespace Umbraco.Core.Logging
}
}
- internal interface IQueue
- {
- void Enqueue(T item);
- bool TryDequeue(out T ret);
- }
-
- internal class RingBuffer : IQueue
- {
- private readonly object lockObject = new object();
- private readonly T[] buffer;
- private readonly int size;
- private int readIndex = 0;
- private int writeIndex = 0;
- private bool bufferFull = false;
-
- public int Size { get { return size; } }
-
- public event Action BufferOverflow;
-
- public RingBuffer(int size)
- {
- this.size = size;
- buffer = new T[size];
- }
-
- public void Enqueue(T item)
- {
- var bufferWasFull = false;
- lock (lockObject)
- {
- buffer[writeIndex] = item;
- writeIndex = (++writeIndex) % size;
- if (bufferFull)
- {
- bufferWasFull = true;
- readIndex = writeIndex;
- }
- else if (writeIndex == readIndex)
- {
- bufferFull = true;
- }
- }
-
- if (bufferWasFull)
- {
- if (BufferOverflow != null)
- {
- BufferOverflow(this, EventArgs.Empty);
- }
- }
- }
-
- public bool TryDequeue(out T ret)
- {
- if (readIndex == writeIndex && !bufferFull)
- {
- ret = default(T);
- return false;
- }
- lock (lockObject)
- {
- if (readIndex == writeIndex && !bufferFull)
- {
- ret = default(T);
- return false;
- }
-
- ret = buffer[readIndex];
- buffer[readIndex] = default(T);
- readIndex = (++readIndex) % size;
- bufferFull = false;
- return true;
- }
- }
- }
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Logging/IQueue.cs b/src/Umbraco.Core/Logging/IQueue.cs
new file mode 100644
index 0000000000..d063993ef6
--- /dev/null
+++ b/src/Umbraco.Core/Logging/IQueue.cs
@@ -0,0 +1,12 @@
+namespace Umbraco.Core.Logging
+{
+ ///
+ /// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
+ ///
+ ///
+ internal interface IQueue
+ {
+ void Enqueue(T item);
+ bool TryDequeue(out T ret);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Logging/ImageProcessorLogger.cs b/src/Umbraco.Core/Logging/ImageProcessorLogger.cs
new file mode 100644
index 0000000000..02ca9c2949
--- /dev/null
+++ b/src/Umbraco.Core/Logging/ImageProcessorLogger.cs
@@ -0,0 +1,46 @@
+namespace Umbraco.Core.Logging
+{
+ using System;
+ using System.Runtime.CompilerServices;
+
+ using ImageProcessor.Common.Exceptions;
+
+ ///
+ /// A logger for explicitly logging ImageProcessor exceptions.
+ ///
+ /// Creating this logger is enough for ImageProcessor to find and replace its in-built debug logger
+ /// without any additional configuration required. This class currently has to be public in order
+ /// to do so.
+ ///
+ ///
+ public sealed class ImageProcessorLogger : ImageProcessor.Common.Exceptions.ILogger
+ {
+ ///
+ /// Logs the specified message as an error.
+ ///
+ /// The type calling the logger.
+ /// The message to log.
+ /// The property or method name calling the log.
+ /// The line number where the method is called.
+ public void Log(string text, [CallerMemberName] string callerName = null, [CallerLineNumber] int lineNumber = 0)
+ {
+ // Using LogHelper since the ImageProcessor logger expects a parameterless constructor.
+ var message = string.Format("{0} {1} : {2}", callerName, lineNumber, text);
+ LogHelper.Error(string.Empty, new ImageProcessingException(message));
+ }
+
+ ///
+ /// Logs the specified message as an error.
+ ///
+ /// The type calling the logger.
+ /// The message to log.
+ /// The property or method name calling the log.
+ /// The line number where the method is called.
+ public void Log(Type type, string text, [CallerMemberName] string callerName = null, [CallerLineNumber] int lineNumber = 0)
+ {
+ // Using LogHelper since the ImageProcessor logger expects a parameterless constructor.
+ var message = string.Format("{0} {1} : {2}", callerName, lineNumber, text);
+ LogHelper.Error(type, string.Empty, new ImageProcessingException(message));
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Logging/LoggingEventContext.cs b/src/Umbraco.Core/Logging/LoggingEventContext.cs
index 159af4266b..88222e3c05 100644
--- a/src/Umbraco.Core/Logging/LoggingEventContext.cs
+++ b/src/Umbraco.Core/Logging/LoggingEventContext.cs
@@ -3,15 +3,18 @@ using log4net.Core;
namespace Umbraco.Core.Logging
{
///
- /// Based on https://github.com/cjbhaines/Log4Net.Async
+ /// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
///
- internal class LoggingEventContext
+ internal sealed class LoggingEventContext
{
- public LoggingEventContext(LoggingEvent loggingEvent)
+ public LoggingEventContext(LoggingEvent loggingEvent, object httpContext)
{
LoggingEvent = loggingEvent;
+ HttpContext = httpContext;
}
public LoggingEvent LoggingEvent { get; set; }
+
+ public object HttpContext { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Logging/LoggingEventHelper.cs b/src/Umbraco.Core/Logging/LoggingEventHelper.cs
index c788e115f2..129098279a 100644
--- a/src/Umbraco.Core/Logging/LoggingEventHelper.cs
+++ b/src/Umbraco.Core/Logging/LoggingEventHelper.cs
@@ -4,9 +4,9 @@ using log4net.Core;
namespace Umbraco.Core.Logging
{
///
- /// Based on https://github.com/cjbhaines/Log4Net.Async
+ /// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
///
- internal class LoggingEventHelper
+ internal sealed class LoggingEventHelper
{
// needs to be a seperate class so that location is determined correctly by log4net when required
@@ -23,8 +23,10 @@ namespace Umbraco.Core.Logging
public LoggingEvent CreateLoggingEvent(Level level, string message, Exception exception)
{
- var loggingEvent = new LoggingEvent(HelperType, null, loggerName, level, message, exception);
- loggingEvent.Fix = Fix;
+ var loggingEvent = new LoggingEvent(HelperType, null, loggerName, level, message, exception)
+ {
+ Fix = Fix
+ };
return loggingEvent;
}
}
diff --git a/src/Umbraco.Core/Logging/ParallelForwardingAppender.cs b/src/Umbraco.Core/Logging/ParallelForwardingAppender.cs
index cf7efdb4c4..48bb3ec710 100644
--- a/src/Umbraco.Core/Logging/ParallelForwardingAppender.cs
+++ b/src/Umbraco.Core/Logging/ParallelForwardingAppender.cs
@@ -1,9 +1,9 @@
+using log4net.Core;
+using log4net.Util;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
-using log4net.Core;
-using log4net.Util;
namespace Umbraco.Core.Logging
{
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Logging
/// An asynchronous appender based on
///
///
- /// Based on https://github.com/cjbhaines/Log4Net.Async
+ /// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
///
public class ParallelForwardingAppender : AsyncForwardingAppenderBase, IDisposable
{
@@ -22,11 +22,11 @@ namespace Umbraco.Core.Logging
private CancellationTokenSource _loggingCancelationTokenSource;
private CancellationToken _loggingCancelationToken;
private Task _loggingTask;
- private Double _shutdownFlushTimeout = 1;
- private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(1);
+ private Double _shutdownFlushTimeout = 2;
+ private TimeSpan _shutdownFlushTimespan = TimeSpan.FromSeconds(2);
private static readonly Type ThisType = typeof(ParallelForwardingAppender);
- private volatile bool _shutDownRequested;
- private int? _bufferSize = DefaultBufferSize;
+ private volatile bool shutDownRequested;
+ private int? bufferSize = DefaultBufferSize;
#endregion Private Members
@@ -37,8 +37,8 @@ namespace Umbraco.Core.Logging
///
public override int? BufferSize
{
- get { return _bufferSize; }
- set { _bufferSize = value; }
+ get { return bufferSize; }
+ set { bufferSize = value; }
}
public int BufferEntryCount
@@ -67,7 +67,12 @@ namespace Umbraco.Core.Logging
protected override string InternalLoggerName
{
- get { return "ParallelForwardingAppender"; }
+ get
+ {
+ {
+ return "ParallelForwardingAppender";
+ }
+ }
}
#endregion Properties
@@ -83,7 +88,7 @@ namespace Umbraco.Core.Logging
private void StartForwarding()
{
- if (_shutDownRequested)
+ if (shutDownRequested)
{
return;
}
@@ -111,7 +116,7 @@ namespace Umbraco.Core.Logging
private void CompleteSubscriberTask()
{
- _shutDownRequested = true;
+ shutDownRequested = true;
if (_loggingEvents == null || _loggingEvents.IsAddingCompleted)
{
return;
@@ -154,7 +159,7 @@ namespace Umbraco.Core.Logging
loggingEvent.Fix = Fix;
//In the case where blocking on a full collection, and the task is subsequently completed, the cancellation token
//will prevent the entry from attempting to add to the completed collection which would result in an exception.
- _loggingEvents.Add(new LoggingEventContext(loggingEvent), _loggingCancelationToken);
+ _loggingEvents.Add(new LoggingEventContext(loggingEvent, HttpContext), _loggingCancelationToken);
}
protected override void Append(LoggingEvent[] loggingEvents)
@@ -187,6 +192,7 @@ namespace Umbraco.Core.Logging
//This call blocks until an item is available or until adding is completed
foreach (var entry in _loggingEvents.GetConsumingEnumerable(_loggingCancelationToken))
{
+ HttpContext = entry.HttpContext;
ForwardLoggingEvent(entry.LoggingEvent, ThisType);
}
}
diff --git a/src/Umbraco.Core/Logging/RingBuffer.cs b/src/Umbraco.Core/Logging/RingBuffer.cs
new file mode 100644
index 0000000000..8dd78129b8
--- /dev/null
+++ b/src/Umbraco.Core/Logging/RingBuffer.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Umbraco.Core.Logging
+{
+ ///
+ /// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
+ ///
+ ///
+ internal sealed class RingBuffer : IQueue
+ {
+ private readonly object lockObject = new object();
+ private readonly T[] buffer;
+ private readonly int size;
+ private int readIndex = 0;
+ private int writeIndex = 0;
+ private bool bufferFull = false;
+
+ public int Size { get { return size; } }
+
+ public event Action BufferOverflow;
+
+ public RingBuffer(int size)
+ {
+ this.size = size;
+ buffer = new T[size];
+ }
+
+ public void Enqueue(T item)
+ {
+ var bufferWasFull = false;
+ lock (lockObject)
+ {
+ buffer[writeIndex] = item;
+ writeIndex = (++writeIndex) % size;
+ if (bufferFull)
+ {
+ bufferWasFull = true;
+ readIndex = writeIndex;
+ }
+ else if (writeIndex == readIndex)
+ {
+ bufferFull = true;
+ }
+ }
+
+ if (bufferWasFull)
+ {
+ if (BufferOverflow != null)
+ {
+ BufferOverflow(this, EventArgs.Empty);
+ }
+ }
+ }
+
+ public bool TryDequeue(out T ret)
+ {
+ if (readIndex == writeIndex && !bufferFull)
+ {
+ ret = default(T);
+ return false;
+ }
+ lock (lockObject)
+ {
+ if (readIndex == writeIndex && !bufferFull)
+ {
+ ret = default(T);
+ return false;
+ }
+
+ ret = buffer[readIndex];
+ buffer[readIndex] = default(T);
+ readIndex = (++readIndex) % size;
+ bufferFull = false;
+ return true;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs
index b8e96c2793..ec73e1ff5e 100644
--- a/src/Umbraco.Core/Models/Content.cs
+++ b/src/Umbraco.Core/Models/Content.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
@@ -75,14 +76,19 @@ namespace Umbraco.Core.Models
_contentType = contentType;
}
- private static readonly PropertyInfo TemplateSelector = ExpressionHelper.GetPropertyInfo(x => x.Template);
- private static readonly PropertyInfo PublishedSelector = ExpressionHelper.GetPropertyInfo(x => x.Published);
- private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language);
- private static readonly PropertyInfo ReleaseDateSelector = ExpressionHelper.GetPropertyInfo(x => x.ReleaseDate);
- private static readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo(x => x.ExpireDate);
- private static readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo(x => x.WriterId);
- private static readonly PropertyInfo NodeNameSelector = ExpressionHelper.GetPropertyInfo(x => x.NodeName);
- private static readonly PropertyInfo PermissionsChangedSelector = ExpressionHelper.GetPropertyInfo(x => x.PermissionsChanged);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo TemplateSelector = ExpressionHelper.GetPropertyInfo(x => x.Template);
+ public readonly PropertyInfo PublishedSelector = ExpressionHelper.GetPropertyInfo(x => x.Published);
+ public readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language);
+ public readonly PropertyInfo ReleaseDateSelector = ExpressionHelper.GetPropertyInfo(x => x.ReleaseDate);
+ public readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo(x => x.ExpireDate);
+ public readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo(x => x.WriterId);
+ public readonly PropertyInfo NodeNameSelector = ExpressionHelper.GetPropertyInfo(x => x.NodeName);
+ public readonly PropertyInfo PermissionsChangedSelector = ExpressionHelper.GetPropertyInfo(x => x.PermissionsChanged);
+ }
///
/// Gets or sets the template used by the Content.
@@ -96,14 +102,7 @@ namespace Umbraco.Core.Models
public virtual ITemplate Template
{
get { return _template; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _template = value;
- return _template;
- }, _template, TemplateSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _template, Ps.Value.TemplateSelector); }
}
///
@@ -141,31 +140,18 @@ namespace Umbraco.Core.Models
public bool Published
{
get { return _published; }
- internal set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _published = value;
- return _published;
- }, _published, PublishedSelector);
- }
+ internal set { SetPropertyValueAndDetectChanges(value, ref _published, Ps.Value.PublishedSelector); }
}
///
/// Language of the data contained within this Content object.
///
[Obsolete("This is not used and will be removed from the codebase in future versions")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
public string Language
{
get { return _language; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _language = value;
- return _language;
- }, _language, LanguageSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _language, Ps.Value.LanguageSelector); }
}
///
@@ -175,14 +161,7 @@ namespace Umbraco.Core.Models
public DateTime? ReleaseDate
{
get { return _releaseDate; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _releaseDate = value;
- return _releaseDate;
- }, _releaseDate, ReleaseDateSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _releaseDate, Ps.Value.ReleaseDateSelector); }
}
///
@@ -192,14 +171,7 @@ namespace Umbraco.Core.Models
public DateTime? ExpireDate
{
get { return _expireDate; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _expireDate = value;
- return _expireDate;
- }, _expireDate, ExpireDateSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _expireDate, Ps.Value.ExpireDateSelector); }
}
///
@@ -209,14 +181,7 @@ namespace Umbraco.Core.Models
public virtual int WriterId
{
get { return _writer; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _writer = value;
- return _writer;
- }, _writer, WriterSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _writer, Ps.Value.WriterSelector); }
}
///
@@ -229,14 +194,7 @@ namespace Umbraco.Core.Models
internal string NodeName
{
get { return _nodeName; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _nodeName = value;
- return _nodeName;
- }, _nodeName, NodeNameSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _nodeName, Ps.Value.NodeNameSelector); }
}
///
@@ -246,14 +204,7 @@ namespace Umbraco.Core.Models
internal bool PermissionsChanged
{
get { return _permissionsChanged; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _permissionsChanged = value;
- return _permissionsChanged;
- }, _permissionsChanged, PermissionsChangedSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _permissionsChanged, Ps.Value.PermissionsChangedSelector); }
}
///
diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs
index b3d0f693d9..0fc3bac044 100644
--- a/src/Umbraco.Core/Models/ContentBase.cs
+++ b/src/Umbraco.Core/Models/ContentBase.cs
@@ -81,19 +81,24 @@ namespace Umbraco.Core.Models
_additionalData = new Dictionary();
}
- private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
- private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
- private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder);
- private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo(x => x.Level);
- private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path);
- private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId);
- private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed);
- private static readonly PropertyInfo DefaultContentTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeId);
- private readonly static PropertyInfo PropertyCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.Properties);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
+ public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
+ public readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder);
+ public readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo(x => x.Level);
+ public readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path);
+ public readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId);
+ public readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed);
+ public readonly PropertyInfo DefaultContentTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ContentTypeId);
+ public readonly PropertyInfo PropertyCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.Properties);
+ }
protected void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
- OnPropertyChanged(PropertyCollectionSelector);
+ OnPropertyChanged(Ps.Value.PropertyCollectionSelector);
}
///
@@ -114,7 +119,7 @@ namespace Umbraco.Core.Models
set
{
_parentId = new Lazy(() => value);
- OnPropertyChanged(ParentIdSelector);
+ OnPropertyChanged(Ps.Value.ParentIdSelector);
}
}
@@ -125,14 +130,7 @@ namespace Umbraco.Core.Models
public virtual string Name
{
get { return _name; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _name = value;
- return _name;
- }, _name, NameSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
}
///
@@ -142,14 +140,7 @@ namespace Umbraco.Core.Models
public virtual int SortOrder
{
get { return _sortOrder; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _sortOrder = value;
- return _sortOrder;
- }, _sortOrder, SortOrderSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _sortOrder, Ps.Value.SortOrderSelector); }
}
///
@@ -159,14 +150,7 @@ namespace Umbraco.Core.Models
public virtual int Level
{
get { return _level; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _level = value;
- return _level;
- }, _level, LevelSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _level, Ps.Value.LevelSelector); }
}
///
@@ -176,14 +160,7 @@ namespace Umbraco.Core.Models
public virtual string Path //Setting this value should be handled by the class not the user
{
get { return _path; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _path = value;
- return _path;
- }, _path, PathSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _path, Ps.Value.PathSelector); }
}
///
@@ -193,14 +170,7 @@ namespace Umbraco.Core.Models
public virtual int CreatorId
{
get { return _creatorId; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _creatorId = value;
- return _creatorId;
- }, _creatorId, CreatorIdSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _creatorId, Ps.Value.CreatorIdSelector); }
}
///
@@ -212,14 +182,7 @@ namespace Umbraco.Core.Models
public virtual bool Trashed //Setting this value should be handled by the class not the user
{
get { return _trashed; }
- internal set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _trashed = value;
- return _trashed;
- }, _trashed, TrashedSelector);
- }
+ internal set { SetPropertyValueAndDetectChanges(value, ref _trashed, Ps.Value.TrashedSelector); }
}
///
@@ -244,14 +207,7 @@ namespace Umbraco.Core.Models
}
return _contentTypeId;
}
- protected set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _contentTypeId = value;
- return _contentTypeId;
- }, _contentTypeId, DefaultContentTypeIdSelector);
- }
+ protected set { SetPropertyValueAndDetectChanges(value, ref _contentTypeId, Ps.Value.DefaultContentTypeIdSelector); }
}
///
diff --git a/src/Umbraco.Core/Models/ContentType.cs b/src/Umbraco.Core/Models/ContentType.cs
index 0926e48e31..88c498a147 100644
--- a/src/Umbraco.Core/Models/ContentType.cs
+++ b/src/Umbraco.Core/Models/ContentType.cs
@@ -48,8 +48,13 @@ namespace Umbraco.Core.Models
_allowedTemplates = new List();
}
- private static readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo(x => x.DefaultTemplateId);
- private static readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedTemplates);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo(x => x.DefaultTemplateId);
+ public readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedTemplates);
+ }
///
/// Gets or sets the alias of the default Template.
@@ -70,14 +75,7 @@ namespace Umbraco.Core.Models
internal int DefaultTemplateId
{
get { return _defaultTemplate; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _defaultTemplate = value;
- return _defaultTemplate;
- }, _defaultTemplate, DefaultTemplateSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _defaultTemplate, Ps.Value.DefaultTemplateSelector); }
}
///
@@ -92,11 +90,7 @@ namespace Umbraco.Core.Models
get { return _allowedTemplates; }
set
{
- SetPropertyValueAndDetectChanges(o =>
- {
- _allowedTemplates = value;
- return _allowedTemplates;
- }, _allowedTemplates, AllowedTemplatesSelector,
+ SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer>(
(templates, enumerable) => templates.UnsortedSequenceEqual(enumerable),
diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs
index a0305d2cfb..2982713e5a 100644
--- a/src/Umbraco.Core/Models/ContentTypeBase.cs
+++ b/src/Umbraco.Core/Models/ContentTypeBase.cs
@@ -67,33 +67,38 @@ namespace Umbraco.Core.Models
_additionalData = new Dictionary();
}
- private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
- private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
- private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder);
- private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo(x => x.Level);
- private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path);
- private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias);
- private static readonly PropertyInfo DescriptionSelector = ExpressionHelper.GetPropertyInfo(x => x.Description);
- private static readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo(x => x.Icon);
- private static readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.Thumbnail);
- private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId);
- private static readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo(x => x.AllowedAsRoot);
- private static readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo(x => x.IsContainer);
- private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed);
- private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedContentTypes);
- private static readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups);
- private static readonly PropertyInfo PropertyTypeCollectionSelector = ExpressionHelper.GetPropertyInfo>(x => x.PropertyTypes);
- private static readonly PropertyInfo HasPropertyTypeBeenRemovedSelector = ExpressionHelper.GetPropertyInfo(x => x.HasPropertyTypeBeenRemoved);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
+ public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
+ public readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder);
+ public readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo(x => x.Level);
+ public readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path);
+ public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias);
+ public readonly PropertyInfo DescriptionSelector = ExpressionHelper.GetPropertyInfo(x => x.Description);
+ public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo(x => x.Icon);
+ public readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo(x => x.Thumbnail);
+ public readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId);
+ public readonly PropertyInfo AllowedAsRootSelector = ExpressionHelper.GetPropertyInfo(x => x.AllowedAsRoot);
+ public readonly PropertyInfo IsContainerSelector = ExpressionHelper.GetPropertyInfo(x => x.IsContainer);
+ public readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed);
+ public readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedContentTypes);
+ public readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups);
+ public readonly PropertyInfo PropertyTypeCollectionSelector = ExpressionHelper.GetPropertyInfo>(x => x.PropertyTypes);
+ public readonly PropertyInfo HasPropertyTypeBeenRemovedSelector = ExpressionHelper.GetPropertyInfo(x => x.HasPropertyTypeBeenRemoved);
+ }
protected void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
- OnPropertyChanged(PropertyGroupCollectionSelector);
+ OnPropertyChanged(Ps.Value.PropertyGroupCollectionSelector);
}
protected void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
- OnPropertyChanged(PropertyTypeCollectionSelector);
+ OnPropertyChanged(Ps.Value.PropertyTypeCollectionSelector);
}
///
@@ -115,7 +120,7 @@ namespace Umbraco.Core.Models
set
{
_parentId = new Lazy(() => value);
- OnPropertyChanged(ParentIdSelector);
+ OnPropertyChanged(Ps.Value.ParentIdSelector);
}
}
@@ -126,14 +131,7 @@ namespace Umbraco.Core.Models
public virtual string Name
{
get { return _name; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _name = value;
- return _name;
- }, _name, NameSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
}
///
@@ -143,14 +141,7 @@ namespace Umbraco.Core.Models
public virtual int Level //NOTE Is this relevant for a ContentType?
{
get { return _level; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _level = value;
- return _level;
- }, _level, LevelSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _level, Ps.Value.LevelSelector); }
}
///
@@ -160,14 +151,7 @@ namespace Umbraco.Core.Models
public virtual string Path //NOTE Is this relevant for a ContentType?
{
get { return _path; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _path = value;
- return _path;
- }, _path, PathSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _path, Ps.Value.PathSelector); }
}
///
@@ -179,12 +163,10 @@ namespace Umbraco.Core.Models
get { return _alias; }
set
{
- SetPropertyValueAndDetectChanges(o =>
- {
- //_alias = value.ToSafeAlias();
- _alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
- return _alias;
- }, _alias, AliasSelector);
+ SetPropertyValueAndDetectChanges(
+ value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase),
+ ref _alias,
+ Ps.Value.AliasSelector);
}
}
@@ -195,14 +177,7 @@ namespace Umbraco.Core.Models
public virtual string Description
{
get { return _description; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _description = value;
- return _description;
- }, _description, DescriptionSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _description, Ps.Value.DescriptionSelector); }
}
///
@@ -212,14 +187,7 @@ namespace Umbraco.Core.Models
public virtual int SortOrder
{
get { return _sortOrder; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _sortOrder = value;
- return _sortOrder;
- }, _sortOrder, SortOrderSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _sortOrder, Ps.Value.SortOrderSelector); }
}
///
@@ -229,14 +197,7 @@ namespace Umbraco.Core.Models
public virtual string Icon
{
get { return _icon; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _icon = value;
- return _icon;
- }, _icon, IconSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _icon, Ps.Value.IconSelector); }
}
///
@@ -246,14 +207,7 @@ namespace Umbraco.Core.Models
public virtual string Thumbnail
{
get { return _thumbnail; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _thumbnail = value;
- return _thumbnail;
- }, _thumbnail, ThumbnailSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _thumbnail, Ps.Value.ThumbnailSelector); }
}
///
@@ -263,14 +217,7 @@ namespace Umbraco.Core.Models
public virtual int CreatorId
{
get { return _creatorId; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _creatorId = value;
- return _creatorId;
- }, _creatorId, CreatorIdSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _creatorId, Ps.Value.CreatorIdSelector); }
}
///
@@ -280,14 +227,7 @@ namespace Umbraco.Core.Models
public virtual bool AllowedAsRoot
{
get { return _allowedAsRoot; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _allowedAsRoot = value;
- return _allowedAsRoot;
- }, _allowedAsRoot, AllowedAsRootSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _allowedAsRoot, Ps.Value.AllowedAsRootSelector); }
}
///
@@ -300,14 +240,7 @@ namespace Umbraco.Core.Models
public virtual bool IsContainer
{
get { return _isContainer; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _isContainer = value;
- return _isContainer;
- }, _isContainer, IsContainerSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _isContainer, Ps.Value.IsContainerSelector); }
}
///
@@ -318,14 +251,7 @@ namespace Umbraco.Core.Models
public virtual bool Trashed //NOTE Is this relevant for a ContentType?
{
get { return _trashed; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _trashed = value;
- return _trashed;
- }, _trashed, TrashedSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _trashed, Ps.Value.TrashedSelector); }
}
private IDictionary _additionalData;
@@ -347,15 +273,11 @@ namespace Umbraco.Core.Models
get { return _allowedContentTypes; }
set
{
- SetPropertyValueAndDetectChanges(o =>
- {
- _allowedContentTypes = value;
- return _allowedContentTypes;
- }, _allowedContentTypes, AllowedContentTypesSelector,
+ SetPropertyValueAndDetectChanges(value, ref _allowedContentTypes, Ps.Value.AllowedContentTypesSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer>(
(sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable),
- sorts => sorts.GetHashCode()));
+ sorts => sorts.GetHashCode()));
}
}
@@ -418,7 +340,7 @@ namespace Umbraco.Core.Models
private set
{
_hasPropertyTypeBeenRemoved = value;
- OnPropertyChanged(HasPropertyTypeBeenRemovedSelector);
+ OnPropertyChanged(Ps.Value.HasPropertyTypeBeenRemovedSelector);
}
}
@@ -543,7 +465,7 @@ namespace Umbraco.Core.Models
// actually remove the group
PropertyGroups.RemoveItem(propertyGroupName);
- OnPropertyChanged(PropertyGroupCollectionSelector);
+ OnPropertyChanged(Ps.Value.PropertyGroupCollectionSelector);
}
///
diff --git a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs
index 4cf4a08bf1..e53011cc51 100644
--- a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs
+++ b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs
@@ -32,9 +32,13 @@ namespace Umbraco.Core.Models
AddContentType(parent);
}
- private static readonly PropertyInfo ContentTypeCompositionSelector =
- ExpressionHelper.GetPropertyInfo>(
- x => x.ContentTypeComposition);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo ContentTypeCompositionSelector =
+ ExpressionHelper.GetPropertyInfo>(x => x.ContentTypeComposition);
+ }
///
/// Gets or sets the content types that compose this content type.
@@ -46,7 +50,7 @@ namespace Umbraco.Core.Models
set
{
_contentTypeComposition = value.ToList();
- OnPropertyChanged(ContentTypeCompositionSelector);
+ OnPropertyChanged(Ps.Value.ContentTypeCompositionSelector);
}
}
@@ -102,7 +106,7 @@ namespace Umbraco.Core.Models
throw new InvalidCompositionException(Alias, contentType.Alias, conflictingPropertyTypeAliases.ToArray());
_contentTypeComposition.Add(contentType);
- OnPropertyChanged(ContentTypeCompositionSelector);
+ OnPropertyChanged(Ps.Value.ContentTypeCompositionSelector);
return true;
}
return false;
@@ -128,7 +132,7 @@ namespace Umbraco.Core.Models
if (compositionIdsToRemove.Any())
RemovedContentTypeKeyTracker.AddRange(compositionIdsToRemove);
- OnPropertyChanged(ContentTypeCompositionSelector);
+ OnPropertyChanged(Ps.Value.ContentTypeCompositionSelector);
return _contentTypeComposition.Remove(contentTypeComposition);
}
return false;
diff --git a/src/Umbraco.Core/Models/DataTypeDatabaseType.cs b/src/Umbraco.Core/Models/DataTypeDatabaseType.cs
index 1db8ac65cb..2fccdc0645 100644
--- a/src/Umbraco.Core/Models/DataTypeDatabaseType.cs
+++ b/src/Umbraco.Core/Models/DataTypeDatabaseType.cs
@@ -6,10 +6,6 @@ namespace Umbraco.Core.Models
///
/// Enum of the various DbTypes for which the Property values are stored
///
- ///
- /// Object is added to support complex values from PropertyEditors,
- /// but will be saved under the Ntext column.
- ///
[Serializable]
[DataContract]
public enum DataTypeDatabaseType
diff --git a/src/Umbraco.Core/Models/DataTypeDefinition.cs b/src/Umbraco.Core/Models/DataTypeDefinition.cs
index 4c12d6fbef..3ba5125a90 100644
--- a/src/Umbraco.Core/Models/DataTypeDefinition.cs
+++ b/src/Umbraco.Core/Models/DataTypeDefinition.cs
@@ -65,15 +65,20 @@ namespace Umbraco.Core.Models
_additionalData = new Dictionary();
}
- private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
- private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
- private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder);
- private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo(x => x.Level);
- private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path);
- private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId);
- private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed);
- private static readonly PropertyInfo PropertyEditorAliasSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyEditorAlias);
- private static readonly PropertyInfo DatabaseTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.DatabaseType);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
+ public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
+ public readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder);
+ public readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo(x => x.Level);
+ public readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path);
+ public readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId);
+ public readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed);
+ public readonly PropertyInfo PropertyEditorAliasSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyEditorAlias);
+ public readonly PropertyInfo DatabaseTypeSelector = ExpressionHelper.GetPropertyInfo(x => x.DatabaseType);
+ }
///
/// Gets or sets the Id of the Parent entity
@@ -83,14 +88,7 @@ namespace Umbraco.Core.Models
public int ParentId
{
get { return _parentId; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _parentId = value;
- return _parentId;
- }, _parentId, ParentIdSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _parentId, Ps.Value.ParentIdSelector); }
}
///
@@ -100,14 +98,7 @@ namespace Umbraco.Core.Models
public string Name
{
get { return _name; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _name = value;
- return _name;
- }, _name, NameSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
}
///
@@ -117,14 +108,7 @@ namespace Umbraco.Core.Models
public int SortOrder
{
get { return _sortOrder; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _sortOrder = value;
- return _sortOrder;
- }, _sortOrder, SortOrderSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _sortOrder, Ps.Value.SortOrderSelector); }
}
///
@@ -134,14 +118,7 @@ namespace Umbraco.Core.Models
public int Level
{
get { return _level; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _level = value;
- return _level;
- }, _level, LevelSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _level, Ps.Value.LevelSelector); }
}
///
@@ -151,14 +128,7 @@ namespace Umbraco.Core.Models
public string Path //Setting this value should be handled by the class not the user
{
get { return _path; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _path = value;
- return _path;
- }, _path, PathSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _path, Ps.Value.PathSelector); }
}
///
@@ -168,14 +138,7 @@ namespace Umbraco.Core.Models
public int CreatorId
{
get { return _creatorId; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _creatorId = value;
- return _creatorId;
- }, _creatorId, UserIdSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _creatorId, Ps.Value.UserIdSelector); }
}
//NOTE: SD: Why do we have this ??
@@ -189,11 +152,7 @@ namespace Umbraco.Core.Models
get { return _trashed; }
internal set
{
- SetPropertyValueAndDetectChanges(o =>
- {
- _trashed = value;
- return _trashed;
- }, _trashed, TrashedSelector);
+ SetPropertyValueAndDetectChanges(value, ref _trashed, Ps.Value.TrashedSelector);
//This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
_additionalData["Trashed"] = value;
}
@@ -205,11 +164,7 @@ namespace Umbraco.Core.Models
get { return _propertyEditorAlias; }
set
{
- SetPropertyValueAndDetectChanges(o =>
- {
- _propertyEditorAlias = value;
- return _propertyEditorAlias;
- }, _propertyEditorAlias, PropertyEditorAliasSelector);
+ SetPropertyValueAndDetectChanges(value, ref _propertyEditorAlias, Ps.Value.PropertyEditorAliasSelector);
//This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
_additionalData["DatabaseType"] = value;
}
@@ -245,12 +200,7 @@ namespace Umbraco.Core.Models
get { return _databaseType; }
set
{
- SetPropertyValueAndDetectChanges(o =>
- {
- _databaseType = value;
- return _databaseType;
- }, _databaseType, DatabaseTypeSelector);
-
+ SetPropertyValueAndDetectChanges(value, ref _databaseType, Ps.Value.DatabaseTypeSelector);
//This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
_additionalData["DatabaseType"] = value;
}
diff --git a/src/Umbraco.Core/Models/DictionaryItem.cs b/src/Umbraco.Core/Models/DictionaryItem.cs
index 749c629d19..42b047e35b 100644
--- a/src/Umbraco.Core/Models/DictionaryItem.cs
+++ b/src/Umbraco.Core/Models/DictionaryItem.cs
@@ -30,9 +30,14 @@ namespace Umbraco.Core.Models
_translations = new List();
}
- private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
- private static readonly PropertyInfo ItemKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ItemKey);
- private static readonly PropertyInfo TranslationsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Translations);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId);
+ public readonly PropertyInfo ItemKeySelector = ExpressionHelper.GetPropertyInfo(x => x.ItemKey);
+ public readonly PropertyInfo TranslationsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Translations);
+ }
///
/// Gets or Sets the Parent Id of the Dictionary Item
@@ -41,14 +46,7 @@ namespace Umbraco.Core.Models
public Guid? ParentId
{
get { return _parentId; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _parentId = value;
- return _parentId;
- }, _parentId, ParentIdSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _parentId, Ps.Value.ParentIdSelector); }
}
///
@@ -58,14 +56,7 @@ namespace Umbraco.Core.Models
public string ItemKey
{
get { return _itemKey; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _itemKey = value;
- return _itemKey;
- }, _itemKey, ItemKeySelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _itemKey, Ps.Value.ItemKeySelector); }
}
///
@@ -77,25 +68,21 @@ namespace Umbraco.Core.Models
get { return _translations; }
set
{
- SetPropertyValueAndDetectChanges(o =>
+ var asArray = value.ToArray();
+ //ensure the language callback is set on each translation
+ if (GetLanguage != null)
{
- var asArray = value.ToArray();
- //ensure the language callback is set on each translation
- if (GetLanguage != null)
+ foreach (var translation in asArray.OfType())
{
- foreach (var translation in asArray.OfType())
- {
- translation.GetLanguage = GetLanguage;
- }
+ translation.GetLanguage = GetLanguage;
}
+ }
- _translations = asArray;
- return _translations;
- }, _translations, TranslationsSelector,
+ SetPropertyValueAndDetectChanges(asArray, ref _translations, Ps.Value.TranslationsSelector,
//Custom comparer for enumerable
new DelegateEqualityComparer>(
(enumerable, translations) => enumerable.UnsortedSequenceEqual(translations),
- enumerable => enumerable.GetHashCode()));
+ enumerable => enumerable.GetHashCode()));
}
}
}
diff --git a/src/Umbraco.Core/Models/DictionaryTranslation.cs b/src/Umbraco.Core/Models/DictionaryTranslation.cs
index 59f96dbe85..4e5b1c2437 100644
--- a/src/Umbraco.Core/Models/DictionaryTranslation.cs
+++ b/src/Umbraco.Core/Models/DictionaryTranslation.cs
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Models
private string _value;
//note: this will be memberwise cloned
private int _languageId;
-
+
public DictionaryTranslation(ILanguage language, string value)
{
if (language == null) throw new ArgumentNullException("language");
@@ -50,8 +50,13 @@ namespace Umbraco.Core.Models
Key = uniqueId;
}
- private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language);
- private static readonly PropertyInfo ValueSelector = ExpressionHelper.GetPropertyInfo(x => x.Value);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language);
+ public readonly PropertyInfo ValueSelector = ExpressionHelper.GetPropertyInfo(x => x.Value);
+ }
///
/// Gets or sets the for the translation
@@ -79,12 +84,8 @@ namespace Umbraco.Core.Models
}
set
{
- SetPropertyValueAndDetectChanges(o =>
- {
- _language = value;
- _languageId = _language == null ? -1 : _language.Id;
- return _language;
- }, _language, LanguageSelector);
+ SetPropertyValueAndDetectChanges(value, ref _language, Ps.Value.LanguageSelector);
+ _languageId = _language == null ? -1 : _language.Id;
}
}
@@ -100,14 +101,7 @@ namespace Umbraco.Core.Models
public string Value
{
get { return _value; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _value = value;
- return _value;
- }, _value, ValueSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _value, Ps.Value.ValueSelector); }
}
public override object DeepClone()
diff --git a/src/Umbraco.Core/Models/EntityBase/Entity.cs b/src/Umbraco.Core/Models/EntityBase/Entity.cs
index c4838dfd0a..637255a1c8 100644
--- a/src/Umbraco.Core/Models/EntityBase/Entity.cs
+++ b/src/Umbraco.Core/Models/EntityBase/Entity.cs
@@ -23,13 +23,17 @@ namespace Umbraco.Core.Models.EntityBase
private DateTime _updateDate;
private bool _wasCancelled;
- private static readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo(x => x.Id);
- private static readonly PropertyInfo KeySelector = ExpressionHelper.GetPropertyInfo(x => x.Key);
- private static readonly PropertyInfo CreateDateSelector = ExpressionHelper.GetPropertyInfo(x => x.CreateDate);
- private static readonly PropertyInfo UpdateDateSelector = ExpressionHelper.GetPropertyInfo(x => x.UpdateDate);
- private static readonly PropertyInfo HasIdentitySelector = ExpressionHelper.GetPropertyInfo(x => x.HasIdentity);
- private static readonly PropertyInfo WasCancelledSelector = ExpressionHelper.GetPropertyInfo(x => x.WasCancelled);
-
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo(x => x.Id);
+ public readonly PropertyInfo KeySelector = ExpressionHelper.GetPropertyInfo(x => x.Key);
+ public readonly PropertyInfo CreateDateSelector = ExpressionHelper.GetPropertyInfo(x => x.CreateDate);
+ public readonly PropertyInfo UpdateDateSelector = ExpressionHelper.GetPropertyInfo(x => x.UpdateDate);
+ public readonly PropertyInfo HasIdentitySelector = ExpressionHelper.GetPropertyInfo(x => x.HasIdentity);
+ public readonly PropertyInfo WasCancelledSelector = ExpressionHelper.GetPropertyInfo(x => x.WasCancelled);
+ }
///
/// Integer Id
@@ -37,18 +41,11 @@ namespace Umbraco.Core.Models.EntityBase
[DataMember]
public int Id
{
- get
- {
- return _id;
- }
+ get { return _id; }
set
{
- SetPropertyValueAndDetectChanges(o =>
- {
- _id = value;
- HasIdentity = true; //set the has Identity
- return _id;
- }, _id, IdSelector);
+ SetPropertyValueAndDetectChanges(value, ref _id, Ps.Value.IdSelector);
+ HasIdentity = true; //set the has Identity
}
}
@@ -67,14 +64,7 @@ namespace Umbraco.Core.Models.EntityBase
_key = Guid.NewGuid();
return _key;
}
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _key = value;
- return _key;
- }, _key, KeySelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _key, Ps.Value.KeySelector); }
}
///
@@ -84,14 +74,7 @@ namespace Umbraco.Core.Models.EntityBase
public DateTime CreateDate
{
get { return _createDate; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _createDate = value;
- return _createDate;
- }, _createDate, CreateDateSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _createDate, Ps.Value.CreateDateSelector); }
}
///
@@ -105,14 +88,7 @@ namespace Umbraco.Core.Models.EntityBase
internal bool WasCancelled
{
get { return _wasCancelled; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _wasCancelled = value;
- return _wasCancelled;
- }, _wasCancelled, WasCancelledSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _wasCancelled, Ps.Value.WasCancelledSelector); }
}
///
@@ -122,14 +98,7 @@ namespace Umbraco.Core.Models.EntityBase
public DateTime UpdateDate
{
get { return _updateDate; }
- set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _updateDate = value;
- return _updateDate;
- }, _updateDate, UpdateDateSelector);
- }
+ set { SetPropertyValueAndDetectChanges(value, ref _updateDate, Ps.Value.UpdateDateSelector); }
}
internal virtual void ResetIdentity()
@@ -166,14 +135,7 @@ namespace Umbraco.Core.Models.EntityBase
{
return _hasIdentity;
}
- protected set
- {
- SetPropertyValueAndDetectChanges(o =>
- {
- _hasIdentity = value;
- return _hasIdentity;
- }, _hasIdentity, HasIdentitySelector);
- }
+ protected set { SetPropertyValueAndDetectChanges(value, ref _hasIdentity, Ps.Value.HasIdentitySelector); }
}
//TODO: Make this NOT virtual or even exist really!
diff --git a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs
index 0d5378d253..407237ad60 100644
--- a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs
+++ b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs
@@ -18,7 +18,9 @@ namespace Umbraco.Core.Models.EntityBase
//TODO: This needs to go on to ICanBeDirty http://issues.umbraco.org/issue/U4-5662
public virtual IEnumerable GetDirtyProperties()
{
- return _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key);
+ return _propertyChangedInfo == null
+ ? Enumerable.Empty()
+ : _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key);
}
private bool _changeTrackingEnabled = true;
@@ -26,12 +28,12 @@ namespace Umbraco.Core.Models.EntityBase
///
/// Tracks the properties that have changed
///
- private IDictionary _propertyChangedInfo = new Dictionary();
+ private IDictionary _propertyChangedInfo;
///
/// Tracks the properties that we're changed before the last commit (or last call to ResetDirtyProperties)
///
- private IDictionary _lastPropertyChangedInfo = null;
+ private IDictionary _lastPropertyChangedInfo;
///
/// Property changed event
@@ -47,12 +49,13 @@ namespace Umbraco.Core.Models.EntityBase
//return if we're not tracking changes
if (_changeTrackingEnabled == false) return;
+ if (_propertyChangedInfo == null)
+ _propertyChangedInfo = new Dictionary();
+
_propertyChangedInfo[propertyInfo.Name] = true;
if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name));
- }
+ PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyInfo.Name));
}
///
@@ -62,7 +65,7 @@ namespace Umbraco.Core.Models.EntityBase
/// True if Property is dirty, otherwise False
public virtual bool IsPropertyDirty(string propertyName)
{
- return _propertyChangedInfo.Any(x => x.Key == propertyName);
+ return _propertyChangedInfo != null && _propertyChangedInfo.Any(x => x.Key == propertyName);
}
///
@@ -71,7 +74,7 @@ namespace Umbraco.Core.Models.EntityBase
/// True if entity is dirty, otherwise False
public virtual bool IsDirty()
{
- return _propertyChangedInfo.Any();
+ return _propertyChangedInfo != null && _propertyChangedInfo.Any();
}
///
@@ -90,7 +93,7 @@ namespace Umbraco.Core.Models.EntityBase
/// True if Property was changed, otherwise False. Returns false if the entity had not been previously changed.
public virtual bool WasPropertyDirty(string propertyName)
{
- return WasDirty() && _lastPropertyChangedInfo.Any(x => x.Key == propertyName);
+ return _lastPropertyChangedInfo != null && _lastPropertyChangedInfo.Any(x => x.Key == propertyName);
}
///
@@ -100,7 +103,7 @@ namespace Umbraco.Core.Models.EntityBase
{
//NOTE: We cannot .Clear() because when we memberwise clone this will be the SAME
// instance as the one on the clone, so we need to create a new instance.
- _lastPropertyChangedInfo = new Dictionary();
+ _lastPropertyChangedInfo = null;
}
///
@@ -130,26 +133,29 @@ namespace Umbraco.Core.Models.EntityBase
if (rememberPreviouslyChangedProperties)
{
//copy the changed properties to the last changed properties
- _lastPropertyChangedInfo = _propertyChangedInfo.ToDictionary(v => v.Key, v => v.Value);
+ if (_propertyChangedInfo != null)
+ {
+ _lastPropertyChangedInfo = _propertyChangedInfo.ToDictionary(v => v.Key, v => v.Value);
+ }
}
//NOTE: We cannot .Clear() because when we memberwise clone this will be the SAME
// instance as the one on the clone, so we need to create a new instance.
- _propertyChangedInfo = new Dictionary();
+ _propertyChangedInfo = null;
}
- protected void ResetChangeTrackingCollections()
+ public void ResetChangeTrackingCollections()
{
- _propertyChangedInfo = new Dictionary();
- _lastPropertyChangedInfo = new Dictionary();
+ _propertyChangedInfo = null;
+ _lastPropertyChangedInfo = null;
}
- protected void DisableChangeTracking()
+ public void DisableChangeTracking()
{
_changeTrackingEnabled = false;
}
- protected void EnableChangeTracking()
+ public void EnableChangeTracking()
{
_changeTrackingEnabled = true;
}
@@ -158,60 +164,61 @@ namespace Umbraco.Core.Models.EntityBase
/// 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.
///
- ///
- ///
+ ///
+ ///
///
/// returns true if the value changed
///
- /// 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
+ /// 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.
///
- internal bool SetPropertyValueAndDetectChanges(Func setValue, T value, PropertyInfo propertySelector)
+ internal void SetPropertyValueAndDetectChanges(T newVal, ref T origVal, PropertyInfo propertySelector)
{
if ((typeof(T) == typeof(string) == false) && TypeHelper.IsTypeAssignableFrom(typeof(T)))
{
throw new InvalidOperationException("This method does not support IEnumerable instances. For IEnumerable instances a manual custom equality check will be required");
}
- return SetPropertyValueAndDetectChanges(setValue, value, propertySelector,
- new DelegateEqualityComparer(
- //Standard Equals comparison
- (arg1, arg2) => Equals(arg1, arg2),
- arg => arg.GetHashCode()));
-
+ SetPropertyValueAndDetectChanges(newVal, ref origVal, propertySelector, EqualityComparer.Default);
}
///
/// 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.
///
- ///
- ///
+ ///
+ ///
///
/// The equality comparer to use
/// returns true if the value changed
///
- /// 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
+ /// 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.
///
- internal bool SetPropertyValueAndDetectChanges(Func setValue, T value, PropertyInfo propertySelector, IEqualityComparer comparer)
+ internal void SetPropertyValueAndDetectChanges(T newVal, ref T origVal, PropertyInfo propertySelector, IEqualityComparer comparer)
{
- var initVal = value;
- var newVal = setValue(value);
-
- //don't track changes, just set the value (above)
- if (_changeTrackingEnabled == false) return false;
-
- if (comparer.Equals(initVal, newVal) == false)
+ //don't track changes, just set the value
+ if (_changeTrackingEnabled == false)
{
- OnPropertyChanged(propertySelector);
- return true;
+ //set the original value
+ origVal = newVal;
+ }
+ else
+ {
+ //check changed
+ var changed = comparer.Equals(origVal, newVal) == false;
+
+ //set the original value
+ origVal = newVal;
+
+ //raise the event if it was changed
+ if (changed)
+ {
+ OnPropertyChanged(propertySelector);
+ }
}
- return false;
}
-
-
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/File.cs b/src/Umbraco.Core/Models/File.cs
index 8ead6da5f8..e271774b8d 100644
--- a/src/Umbraco.Core/Models/File.cs
+++ b/src/Umbraco.Core/Models/File.cs
@@ -33,8 +33,14 @@ namespace Umbraco.Core.Models
_content = getFileContent != null ? null : string.Empty;
}
- private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo(x => x.Content);
- private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo(x => x.Path);
+ private static readonly Lazy Ps = new Lazy();
+
+ private class PropertySelectors
+ {
+ public readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo(x => x.Content);
+ public readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo