Compare commits

..

13 Commits

Author SHA1 Message Date
Warren 26c148dccc Merge remote-tracking branch 'origin/temp8-135-ChangeDocTypeDialog' into temp8-135-ChangeDocTypeDialog 2018-08-13 15:12:48 +01:00
Warren 8497056185 Fix up camelCasing stuff 2018-08-13 15:12:23 +01:00
Mads Rasmussen 5498e2c2bb Don't show property select if there are no allowed properties 2018-08-13 15:25:09 +02:00
Mads Rasmussen 602a8ce08c add property map + wire up save 2018-08-13 14:48:18 +02:00
Warren 7e82524c4e Camel case properties to make Mads not have a OCD issue with the server responses :) 2018-08-13 12:18:42 +01:00
Warren 783973b9da Fix up the Content Resource to send the correct params to the Controller endpoint 2018-08-13 11:53:14 +01:00
Mads Rasmussen 096cd1ef73 wip change doc type UI 2018-08-13 12:25:36 +02:00
Warren 07b01fa318 Updates resource with getAvailableProperties(fromAlias, toAlias) to call our new HTTP endpoint 2018-08-13 10:58:40 +01:00
Warren 0ba253c61d New Controller endpoint for Mads to get back a JSON object of allowed properties that he can use easier in the clientside for this dialog 2018-08-13 10:40:52 +01:00
Warren 5da7f034e9 WIP - Need some help with JS 2018-08-10 13:34:42 +01:00
Warren 8eebd4ccae WIP - UI needs finishing
* Adds in the GET & POST Controller methods along with new Models
* Adds new HTML view & Angular Controller
* Updates Angular Content Resource to call our new C# controller endpoints
2018-08-09 18:18:27 +01:00
Warren c47e254efe Remove the Legacy menu conversion on ChangeDocType action 2018-08-09 09:54:39 +01:00
Warren 3f35749619 * Remove actionNotify as notifications dialog already merged in
* Remove actionChangeDocType
2018-08-09 09:53:31 +01:00
1328 changed files with 41324 additions and 38400 deletions
+1 -7
View File
@@ -27,10 +27,4 @@ dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
# https://github.com/MicrosoftDocs/visualstudio-docs/blob/master/docs/ide/editorconfig-code-style-settings-reference.md
[*.cs]
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
dotnet_naming_style.prefix_underscore.required_prefix = _
-66
View File
@@ -1,66 +0,0 @@
---
name: 🐛 Bug Report
about: File a bug report, if you've discovered a problem in Umbraco.
---
A brief description of the issue goes here.
<!--
If you haven't yet done so, please read the "contributing guidelines"
thoroughly. Then, proceed by filling out the rest of the details in the issue
template below. The more details you can give us, the easier it will be for us
to determine the cause of a problem.
See: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md
-->
Reproduction
------------
If you're filing a bug, please describe how to reproduce it. Include as much
relevant information as possible, such as:
### Bug summary
<!--
* Write a short summary of the bug
* Try to pinpoint it as much as possible
* Try to state the _actual problem_, and not just what you _think_ the
solution might be.
-->
### Specifics
<!--
* Mention the URL where this bug occurs, if applicable
* What version of Umbraco are you using (down to the very last digit!)
* What browser and version you are using
* Please mention if you've checked it in other browsers as well
* Please include *full error messages* and *screenshots* if possible
-->
### Steps to reproduce
<!--
* Clearly mention the steps to reproduce the bug
-->
### Expected result
<!--
* What did you _expect_ that would happen on your Umbraco site?
* Describe the intended/desired outcome after you did the steps mentioned.
-->
### Actual result
<!--
* What is the actual result of the above steps?
* Describe the behaviour of the bug
* Please, please include **error messages** and screenshots. They might mean
nothing to you, but they are _very_ helpful to us.
-->
@@ -1,31 +0,0 @@
---
name: 📮 Feature Request
about: Open a feature request, if you want to propose a new feature.
---
A brief description of your feature request goes here.
<!--
If you want to discuss the feature you're imagining, please make sure to keep
those discussions on the forum at https://our.umbraco.com/ (choose the
category "Contributing to Umbraco", Umbraco HQ follows all new topics there).
Once you've come to a conclusion in the discussion, feel free to propose the
new feature here.
-->
How can you help?
-------------------------------
<!--
The resources (read: available time and effort) of Umbraco's core team are
limited.
If we can not work on your suggestion, please don't take it personally. Most
likely, it's either:
- We think your idea is valid, but we can't find the time to work on it.
- Your idea might be better suited as a package, if it's not suitable for
the majority of users.
-->
@@ -1,9 +0,0 @@
---
name: ⁉️ Support Question
about: Having trouble with Umbraco? -> https://our.umbraco.com
---
This issue tracker is NOT meant for support questions. If you have a question,
please join us on the forum at https://our.umbraco.com.
Thanks!
@@ -1,9 +0,0 @@
---
name: 📖 Documentation Issue
about: See https://github.com/umbraco/UmbracoDocs/issues for documentation issues
---
The Umbraco documentation has its own dedicated repository. Please open your
documentation-related issue at https://github.com/umbraco/UmbracoDocs/issues
Thanks!
@@ -1,31 +0,0 @@
---
name: 🔐 Security Issue
about: Discovered a Security Issue in Umbraco?
---
⚠️ PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, SEE BELOW.
If you have found a security issue in Umbraco, please send the details to
security@umbraco.com and don't disclose it publicly until we can provide a fix for
it. If you wish, we'll credit you for finding verified issues, when we release
the patched version.
❗ Please read more about how to report security issues on https://umbraco.com/security
A note on "Self XSS"
--------------------
Umbraco is a CMS, that allows users to edit content on a website. As such,
all _authenticated users_ can:
- Edit content, and (depending on the field types) insert HTML and CSS in that
content, with a variety of allowed attributes.
- Depending on the user level: Edit template files, and insert C#, HTML, CSS and
javascript in so on.
- Upload files to the site, which will become publicly available.
We see these functionalities as _features_, and not as security issues. Please
report the mentioned items only if they can be performed by non-authorized
users, or other exploitable vulnerabilities.
Thanks!
-11
View File
@@ -1,11 +0,0 @@
### Prerequisites
- [ ] I have [created an issue](https://github.com/umbraco/Umbraco-CMS/issues) for the proposed changes in this PR, the link is:
- [ ] I have added steps to test this contribution in the description below
### Description
<!-- A description of the changes proposed in the pull-request -->
<!-- Make sure to link to the related issue number so we can easily find it in the issue tracker -->
<!-- Thanks for contributing to Umbraco CMS! -->
+1 -1
View File
@@ -1,6 +1,6 @@
# The MIT License (MIT) #
Copyright (c) 2013-present Umbraco
Copyright (c) 2013 Umbraco
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+82 -51
View File
@@ -1,56 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<id>UmbracoCms.Core</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
<dependency id="LightInject" version="[5.1.2,5.999999)" />
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
<dependency id="LightInject.Web" version="[2.0.0,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Core" version="[2.2.2,2.999999)" />
<dependency id="Microsoft.AspNet.WebApi.Client" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.Owin" version="[4.0.0,4.999999)" />
<dependency id="MiniProfiler" version="[3.2.0.157,3.999999)" />
<dependency id="MySql.Data" version="[6.10.7,6.999999)" />
<dependency id="Newtonsoft.Json" version="[11.0.2,11.999999)" />
<dependency id="Semver" version="[2.0.4,2.999999)" />
<dependency id="Serilog" version="[2.7.1,2.999999)" />
<dependency id="Serilog.Enrichers.Process" version="[2.0.1,2.999999)" />
<dependency id="Serilog.Enrichers.Thread" version="[3.0.0,3.999999)" />
<dependency id="Serilog.Filters.Expressions" version="[2.0.0,2.999999)" />
<dependency id="Serilog.Formatting.Compact" version="[1.0.0,1.999999)" />
<dependency id="Serilog.Settings.AppSettings" version="[2.1.2,2.999999)" />
<dependency id="Serilog.Sinks.File" version="[4.0.0,4.999999)" />
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
<dependency id="NPoco" version="[3.9.4,3.999999)" />
</dependencies>
</metadata>
<files>
<!-- libs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
<metadata minClientVersion="3.4.4">
<id>UmbracoCms.Core</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
<dependency id="ClientDependency" version="[1.9.6,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.0.0-beta025,1.999999)" />
<dependency id="HtmlAgilityPack" version="[1.7.2,1.999999)" />
<dependency id="ImageProcessor" version="[2.6.1.19,2.999999)" />
<dependency id="ImageProcessor.Web" version="[4.9.2.19,4.999999)" />
<dependency id="ImageProcessor.Web.Config" version="[2.4.1.19,2.999999)" />
<dependency id="LightInject" version="[5.1.2,5.999999)" />
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
<dependency id="log4net" version="[2.0.8,2.999999)" />
<dependency id="Log4Net.Async" version="[2.0.4,2.999999)" />
<dependency id="Lucene.Net.Contrib" version="[3.0.3,3.999999)" />
<dependency id="Markdown" version="[2.2.1,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1,2.999999)" />
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3,2.999999)" />
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.CodeAnalysis.CSharp" version="[2.8.0,2.999999)" />
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[1.0.8,1.999999)" />
<dependency id="Microsoft.Net.Compilers" version="[2.8.0,2.999999)" />
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Owin.Security.Cookies" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Owin.Security.OAuth" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Web.Xdt" version="[2.1.2,2.999999)" />
<dependency id="MiniProfiler" version="[3.2.0.157,3.999999)" />
<dependency id="MySql.Data" version="[6.10.7,6.999999)" />
<dependency id="Newtonsoft.Json" version="[11.0.2,11.999999)" />
<dependency id="NPoco" version="[3.9.3,3.999999)" />
<dependency id="Semver" version="[2.0.4,2.999999)" />
<dependency id="System.Reflection.Primitives" version="[4.3.0,4.999999)" />
<dependency id="System.Runtime.Handles" version="[4.3.0,4.999999)" />
<dependency id="System.Security.Cryptography.X509Certificates" version="[4.3.2,4.999999)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.8.0,4.999999)" />
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
</dependencies>
</metadata>
<files>
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\Umbraco.Web.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\Umbraco.Examine.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Core\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
</files>
<file src="tools\install.core.ps1" target="tools\install.ps1" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Core\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Web\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="$BuildTmp$\bin\Umbraco.Web.UI.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Web.UI\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Examine\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Examine" />
</files>
</package>
-62
View File
@@ -1,62 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<id>UmbracoCms.Web</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the web assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="AutoMapper" version="[7.0.1,7.999999)" />
<dependency id="ClientDependency" version="[1.9.7,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.0.0-beta025,1.999999)" />
<dependency id="Lucene.Net.Contrib" version="[3.0.3,3.999999)" />
<dependency id="HtmlAgilityPack" version="[1.8.9,1.999999)" />
<dependency id="ImageProcessor" version="[2.6.2.25,2.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
<dependency id="Markdown" version="[2.2.1,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.2,2.999999)" />
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3,2.999999)" />
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.6,5.999999)" />
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Owin.Security.Cookies" version="[4.0.0,4.999999)" />
<dependency id="Microsoft.Owin.Security.OAuth" version="[4.0.0,4.999999)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.8.0,4.999999)" />
</dependencies>
</metadata>
<files>
<!-- libs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\Umbraco.Web.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\Umbraco.Examine.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Web\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Examine\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Examine" />
</files>
</package>
+53 -59
View File
@@ -1,65 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<id>UmbracoCms</id>
<version>8.0.0</version>
<title>Umbraco Cms</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Web" version="[$version$]" />
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3, 2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.24]" />
<dependency id="ImageProcessor.Web" version="[4.9.3.25,4.999999)" />
<dependency id="ImageProcessor.Web.Config" version="[2.4.1.19,2.999999)" />
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.0,2.999999)" />
<dependency id="Microsoft.Net.Compilers" version="[2.9.0,2.999999)" />
</dependencies>
</metadata>
<files>
<!-- files -->
<file src="$BuildTmp$\Configs\**" target="Content\Config" exclude="$BuildTmp$\Configs\Web.config.transform" />
<file src="$BuildTmp$\WebApp\Views\**" target="Content\Views" exclude="$BuildTmp$\WebApp\Views\Web.config" />
<file src="$BuildTmp$\WebApp\default.aspx" target="Content\default.aspx" />
<file src="$BuildTmp$\WebApp\Global.asax" target="Content\Global.asax" />
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
<metadata minClientVersion="3.4.4">
<id>UmbracoCms</id>
<version>8.0.0</version>
<title>Umbraco Cms</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.3, 2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.20]" />
</dependencies>
</metadata>
<files>
<file src="$BuildTmp$\Configs\**" target="Content\Config" exclude="$BuildTmp$\Configs\Web.config.transform" />
<file src="$BuildTmp$\WebApp\Views\**" target="Content\Views" exclude="$BuildTmp$\WebApp\Views\Web.config" />
<file src="$BuildTmp$\WebApp\default.aspx" target="Content\default.aspx" />
<file src="$BuildTmp$\WebApp\Global.asax" target="Content\Global.asax" />
<file src="$BuildTmp$\WebApp\Web.config" target="UmbracoFiles\Web.config" />
<file src="$BuildTmp$\WebApp\App_Browsers\**" target="UmbracoFiles\App_Browsers" />
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="$BuildTmp$\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
<!-- these files are copied by install.ps1 -->
<file src="$BuildTmp$\WebApp\Web.config" target="UmbracoFiles\Web.config" />
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.htm" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.htm" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.controller.js" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.controller.js" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\modelsbuilder.resource.js" target="Content\App_Plugins\ModelsBuilder\modelsbuilder.resource.js" />
<file src="$BuildTmp$\WebApp\App_Plugins\ModelsBuilder\package.manifest" target="Content\App_Plugins\ModelsBuilder\package.manifest" />
<!-- tools -->
<!-- beware! install.ps1 not supported by PackageReference -->
<file src="tools\install.ps1" target="tools\install.ps1" />
<file src="tools\Readme.txt" target="tools\Readme.txt" />
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
<file src="tools\install.ps1" target="tools\install.ps1" />
<file src="tools\Readme.txt" target="tools\Readme.txt" />
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
<file src="tools\applications.config.install.xdt" target="Content\config\applications.config.install.xdt" />
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
<!-- config transforms -->
<!-- beware! config transforms not supported by PackageReference -->
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
<file src="tools\applications.config.install.xdt" target="Content\config\applications.config.install.xdt" />
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
<file src="tools\Dashboard.config.install.xdt" target="Content\config\Dashboard.config.install.xdt" />
<file src="tools\trees.config.install.xdt" target="Content\config\trees.config.install.xdt" />
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" /> <!-- FIXME Content\ !! and then... transform?! -->
<!-- UmbracoCms props and targets -->
<file src="build\**" target="build" />
</files>
<file src="build\**" target="build" />
</files>
</package>
+3
View File
@@ -47,6 +47,9 @@
<CustomFilesToInclude Include=".\umbraco\**\*">
<Dir>umbraco</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\umbraco_client\**\*">
<Dir>umbraco_client</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\Global.asax">
<Dir>.</Dir>
</CustomFilesToInclude>
+11 -11
View File
@@ -1,26 +1,26 @@
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
| | | | \ / | |_) | |__) | / \ | | | | | |
| | | | |\/| | _ <| _ / / /\ \| | | | | |
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
----------------------------------------------------
Don't forget to build!
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, config\splashes and global.asax.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, umbraco_client, config\splashes and global.asax.
Please read the release notes on our.umbraco.com:
https://our.umbraco.com/download/releases
http://our.umbraco.com/contribute/releases
- Umbraco
- Umbraco
+20 -11
View File
@@ -1,30 +1,39 @@
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
_ _ __ __ ____ _____ _____ ____
| | | | \/ | _ \| __ \ /\ / ____/ __ \
| | | | \ / | |_) | |__) | / \ | | | | | |
| | | | |\/| | _ <| _ / / /\ \| | | | | |
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
----------------------------------------------------
*** IMPORTANT NOTICE FOR UPGRADES FROM VERSIONS BELOW 7.7.0 ***
Be sure to read the version specific upgrade information before proceeding:
https://our.umbraco.com/documentation/Getting-Started/Setup/Upgrading/version-specific#version-7-7-0
Depending on the version you are upgrading from, you may need to make some changes to your web.config
and you will need to be aware of the breaking changes listed there to see if these affect your installation.
Don't forget to build!
We've done our best to transform your configuration files but in case something is not quite right: remember we
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
We've overwritten all the files in the Umbraco folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
a package might have added. Only the existing files were overwritten. If you customized anything then make
We've overwritten all the files in the Umbraco and Umbraco_Client folder, these have been backed up in
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
a package might have added. Only the existing files were overwritten. If you customized anything then make
sure to do a compare and merge with the NuGetBackup folder.
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, config\splashes and global.asax.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, umbraco_client, config\splashes and global.asax.
Please read the release notes on our.umbraco.com:
http://our.umbraco.com/contribute/releases
- Umbraco
- Umbraco
@@ -150,6 +150,10 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
@@ -1,11 +1,11 @@
<?xml version="1.0"?>
<applications xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<add alias="content" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="media" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="settings" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="developer" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="users" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="member" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="forms" name="Forms" sortOrder="6" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing" />
<add alias="translation" sortOrder="7" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon,sortOrder)" />
</applications>
<add alias="content" icon="traycontent" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="media" icon="traymedia" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="settings" icon="traysettings" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="developer" icon="traydeveloper" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="users" icon="trayusers" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="member" icon="traymember" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="forms" name="Forms" icon="icon-umb-contour" sortOrder="6" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing" />
<add alias="translation" icon="traytranslation" sortOrder="7" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon,sortOrder)" />
</applications>
+1
View File
@@ -33,6 +33,7 @@ if ($project) {
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
# Delete files Umbraco ships with
if(Test-Path $umbracoBinFolder\log4net.dll) { Remove-Item $umbracoBinFolder\log4net.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll) { Remove-Item $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll -Force -Confirm:$false }
+18 -2
View File
@@ -44,6 +44,14 @@ if ($project) {
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
$umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
New-Item -ItemType Directory -Force -Path $umbracoClientFolder
$umbracoClientFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco_Client"
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
$copyWebconfig = $true
$destinationWebConfig = Join-Path $projectPath "Web.config"
@@ -77,7 +85,15 @@ if ($project) {
$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
@@ -143,4 +159,4 @@ if ($project) {
{
$DTE.ItemOperations.OpenFile($toolsPath + '\ReadmeUpgrade.txt')
}
}
}
+9 -16
View File
@@ -69,9 +69,6 @@
$global:node_nodepath = $this.ClearEnvVar("NODEPATH")
$global:node_npmcache = $this.ClearEnvVar("NPM_CONFIG_CACHE")
$global:node_npmprefix = $this.ClearEnvVar("NPM_CONFIG_PREFIX")
# https://github.com/gruntjs/grunt-contrib-connect/issues/235
$this.SetEnvVar("NODE_NO_HTTP2", "1")
})
$ubuild.DefineMethod("RestoreNode",
@@ -81,8 +78,6 @@
$this.SetEnvVar("NODEPATH", $node_nodepath)
$this.SetEnvVar("NPM_CONFIG_CACHE", $node_npmcache)
$this.SetEnvVar("NPM_CONFIG_PREFIX", $node_npmprefix)
$ignore = $this.ClearEnvVar("NODE_NO_HTTP2")
})
$ubuild.DefineMethod("CompileBelle",
@@ -119,13 +114,17 @@
&npm install >> $log 2>&1
Write-Output ">> $? $($error.Count)" >> $log 2>&1
Write-Output "### install bower" >> $log 2>&1
&npm install -g bower >> $log 2>&1
$error.Clear() # that one fails 'cos bower is deprecated - ignore
Write-Output "### install gulp" >> $log 2>&1
&npm install -g gulp >> $log 2>&1
$error.Clear() # that one fails 'cos deprecated stuff - ignore
Write-Output "### install gulp-cli" >> $log 2>&1
&npm install -g gulp-cli --quiet >> $log 2>&1
$error.Clear() # that one fails 'cos some files not being removed - ignore
if (-not $?) { throw "Failed to install gulp-cli" } # that one is expected to work
Write-Output "### gulp build for version $($this.Version.Release)" >> $log 2>&1
&gulp build --buildversion=$this.Version.Release >> $log 2>&1
@@ -400,15 +399,9 @@
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Core." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Web.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Web." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `
-Version $this.Version.Semver.ToString() `
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cms.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms." }
@@ -424,7 +417,7 @@
$ubuild.DefineMethod("VerifyNuGet",
{
$this.VerifyNuGetConsistency(
("UmbracoCms", "UmbracoCms.Core", "UmbracoCms.Web"),
("UmbracoCms", "UmbracoCms.Core"),
("Umbraco.Core", "Umbraco.Web", "Umbraco.Web.UI", "Umbraco.Examine"))
if ($this.OnError()) { return }
})
@@ -434,7 +427,7 @@
Write-Host "Prepare Azure Gallery"
$this.CopyFile("$($this.SolutionRoot)\build\Azure\azuregalleryrelease.ps1", $this.BuildOutput)
})
$ubuild.DefineMethod("Build",
{
$error.Clear()
@@ -464,7 +457,6 @@
if ($this.OnError()) { return }
$this.PrepareAzureGallery()
if ($this.OnError()) { return }
Write-Host "Done"
})
# ################################################################
@@ -480,4 +472,5 @@
$ubuild.Build()
if ($ubuild.OnError()) { return }
}
Write-Host "Done"
if ($get) { return $ubuild }
View File
View File
@@ -17,7 +17,7 @@ Assume positive intent and try to understand before being understood.
Treat others as you would like to be treated.
This also goes for treating the HQ with respect. For example: dont promote products on [our.umbraco.com](https://our.umbraco.com) that directly compete with our commercial offerings which enables us to work for a sustainable Umbraco.
This also goes for treating the HQ with respect. For example: dont promote products on [our.umbraco.org](https://our.umbraco.org) that directly compete with our commercial offerings which enables us to work for a sustainable Umbraco.
## Open
@@ -82,7 +82,7 @@ These wonderful volunteers will provide you with a first reply to your PR, revie
You can get in touch with [the PR team](#the-pr-team) in multiple ways, we love open conversations and we are a friendly bunch. No question you have is stupid. Any questions you have usually helps out multiple people with the same question. Ask away:
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.org/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
- We're also [active in the Gitter chatroom](https://gitter.im/umbraco/Umbraco-CMS)
## Code of Conduct
@@ -31,7 +31,7 @@ Before creating bug reports, please check [this list](#before-submitting-a-bug-r
##### Before Submitting A Bug Report
* Most importantly, check **if you can reproduce the problem** in the [latest version of Umbraco](https://our.umbraco.com/download/). We might have already fixed your particular problem.
* Most importantly, check **if you can reproduce the problem** in the [latest version of Umbraco](https://our.umbraco.org/download/). We might have already fixed your particular problem.
* It also helps tremendously to check if the issue you're experiencing is present in **a clean install** of the Umbraco version you're currently using. Custom code can have side-effects that don't occur in a clean install.
* **Use the Google**. Whatever you're experiencing, Google it plus "Umbraco" - usually you can get some pretty good hints from the search results, including open issues and further troubleshooting hints.
* If you do find and existing issue has **and the issue is still open**, add a comment to the existing issue if you have additional information. If you have the same problem and no new info to add, just "star" the issue.
@@ -65,11 +65,13 @@ Most of the suggestions in the [reporting bugs](#reporting-bugs) section also co
Some additional hints that may be helpful:
* **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part of Umbraco which the suggestion is related to.
* **Explain why this enhancement would be useful to most Umbraco users** and isn't something that can or should be implemented as a [community package](https://our.umbraco.com/projects/).
* **Explain why this enhancement would be useful to most Umbraco users** and isn't something that can or should be implemented as a [community package](https://our.umbraco.org/projects/).
### Your First Code Contribution
Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` and issues](https://issues.umbraco.org/issues?q=&project=U4&tagValue=upforgrabs&release=&issueType=&search=search) or on the [new issue tracker](https://github.com/umbraco/Umbraco-CMS/issues?q=is%3Aopen+is%3Aissue+label%3Acommunity%2Fup-for-grabs).
Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` and issues](http://issues.umbraco.org/issues/U4?q=%28project%3A+%7BU4%7D+Difficulty%3A+%7BVery+Easy%7D+%23Easy+%23Unresolved+Priority%3A+Normal+%23Major+%23Show-stopper+State%3A+-%7BIn+Progress%7D+sort+by%3A+votes+Affected+versions%3A+-6.*+Affected+versions%3A+-4.*%29+OR+%28tag%3A+%7BUp+For+Grabs%7D+%23Unresolved+%29).
The issue list is sorted by total number of upvotes. While not perfect, number of upvotes is a reasonable proxy for impact a given change will have.
### Pull Requests
@@ -78,7 +80,7 @@ The most successful pull requests usually look a like this:
* Fill in the required template
* Include screenshots and animated GIFs in your pull request whenever possible.
* Unit tests, while optional are awesome, thank you!
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.org/documentation/Reference/) is generated
Again, these are guidelines, not strict requirements.
@@ -114,8 +116,8 @@ There's two big areas that you should know about:
To find the general areas of something you're looking to fix or improve, have a look at the following two parts of the API documentation.
* [The AngularJS based backoffice files](https://our.umbraco.com/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
* [The rest](https://our.umbraco.com/apidocs/csharp/)
* [The AngularJS based backoffice files](https://our.umbraco.org/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
* [The rest](https://our.umbraco.org/apidocs/csharp/)
### What branch should I target for my contributions?
@@ -127,7 +129,7 @@ We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-fl
The easiest way to get started is to run `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 `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 (version 15.3 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 ([the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
![Gulp build in Visual Studio](img/gulpbuild.png)
@@ -154,4 +156,4 @@ git rebase upstream/dev-v7
In this command we're syncing with the `dev-v7` branch, but you can of course choose another one if needed.
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
+11
View File
@@ -0,0 +1,11 @@
### Prerequisites
- [ ] I have written a descriptive pull-request title
- [ ] I have linked this PR to an issue on the tracker at http://issues.umbraco.org
### Description
<!-- A description of the changes proposed in the pull-request -->
<!-- Thanks for contributing to Umbraco CMS! -->
+2 -12
View File
@@ -1,18 +1,9 @@
_You are browsing the Umbraco v8 branch. Umbraco 8 is currently under development._
_You are browsing the Umbraco v8 branch._
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS) to go to the v7 branch._
_Ready to try out Version 8? [See the quick start guide](V8_GETTING_STARTED.md)._
When is Umbraco 8 coming?
=========================
When it's ready. We're done with the major parts of the architecture work and are focusing on three seperate tracks to prepare Umbraco 8 for release:
1) Editor Track (_currently in progress_). Without editors, there's no market for Umbraco. So we want to make sure that Umbraco 8 is full of love for editors.
2) Partner Track. Without anyone implementing Umbraco, there's nothing for editors to update. So we want to make sure that Umbraco 8 is a joy to implement
3) Contributor Track. Without our fabulous ecosystem of both individual Umbracians and 3rd party ISVs, Umbraco wouldn't be as rich a platform as it is today. We want to make sure that it's easy, straight forward and as backwards-compatible as possible to create packages for Umbraco
Once a track is done, we start releasing previews where we ask people to test the features we believe are ready. While the testing is going on and we gather feedback, we move on to the next track. This doesn't mean that there hasn't already been work done in the area, but that a track focuses on finalizing, polishing and preparing the features for release.
Umbraco CMS
===========
The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 443,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
@@ -57,5 +48,4 @@ Umbraco is contribution focused and community driven. If you want to contribute
Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](CONTRIBUTING_DETAILED.md#reporting-bugs).
You can comment and report issues on the [github issue tracker](https://github.com/umbraco/Umbraco-CMS/issues).
Since [September 2018](https://umbraco.com/blog/a-second-take-on-umbraco-issue-tracker-hello-github-issues/) the old issue tracker is in read only mode, but can still be found at [http://issues.umbraco.org](http://issues.umbraco.org).
To view existing issues, please visit [http://issues.umbraco.org](http://issues.umbraco.org).
@@ -23,7 +23,7 @@ We recommend running the site with the Visual Studio since you'll be able to rem
### Making code changes
* _[The process for making code changes in v8 is the same as v7](https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md)_
* _[The process for making code changes in v8 is the same as v7](https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/docs/CONTRIBUTING.md)_
* Any .NET changes you make you just need to compile
* Any Angular/JS changes you make you will need to make sure you are running the Gulp build. Easiest way to do this is from within Visual Studio in the `Task Runner Explorer`. You can find this window by pressing `ctrl + q` and typing in `Task Runner Explorer`. In this window you'll see all Gulp tasks, double click on the `dev` task, this will compile the angular solution and start a file watcher, then any html/js changes you make are automatically built.
* When making js changes, you should have the chrome developer tools open to ensure that cache is disabled
@@ -33,5 +33,5 @@ We recommend running the site with the Visual Studio since you'll be able to rem
We are keeping track of [known issues and limitations here](http://issues.umbraco.org/issue/U4-11279). These line items will eventually be turned into actual tasks to be worked on. Feel free to help us keep this list updated if you find issues and even help fix some of these items. If there is a particular item you'd like to help fix please mention this on the task and we'll create a sub task for the item to continue discussion there.
There's [a list of tasks for v8 that haven't been completed](https://issues.umbraco.org/issues?q=&project=U4&tagValue=&release=8.0.0&issueType=&resolvedState=open&search=search). If you are interested in helping out with any of these please mention this on the task. This list will be constantly updated as we begin to document and design some of the other tasks that still need to get done.
There's [a list of tasks for v8 that haven't been completed](http://issues.umbraco.org/issues/U4?q=Due+in+version%3A+8.0.0+%23Unresolved+). If you are interested in helping out with any of these please mention this on the task. This list will be constantly updated as we begin to document and design some of the other tasks that still need to get done.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

@@ -8,7 +8,7 @@
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
<meta name="generator" content="docfx {{_docfxVersion}}">
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
<link rel="icon" type="image/png" href="https://our.umbraco.com/assets/images/app-icons/favicon.png">
<link rel="icon" type="image/png" href="https://our.umbraco.org/assets/images/app-icons/favicon.png">
<link rel="stylesheet" href="{{_rel}}styles/docfx.vendor.css">
<link rel="stylesheet" href="{{_rel}}styles/docfx.css">
<link rel="stylesheet" href="{{_rel}}styles/main.css">
+1 -1
View File
@@ -63,7 +63,7 @@ a:focus {
}
.navbar-header .navbar-brand {
background: url(https://our.umbraco.com/assets/images/logo.svg) left center no-repeat;
background: url(https://our.umbraco.org/assets/images/logo.svg) left center no-repeat;
background-size: 40px auto;
width:50px;
}
+2 -2
View File
@@ -2,7 +2,7 @@
using System.Resources;
[assembly: AssemblyCompany("Umbraco")]
[assembly: AssemblyCopyright("Copyright © Umbraco 2018")]
[assembly: AssemblyCopyright("Copyright © Umbraco 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -19,4 +19,4 @@ using System.Resources;
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.0.0")]
[assembly: AssemblyInformationalVersion("8.0.0-alpha.52")]
[assembly: AssemblyInformationalVersion("8.0.0-alpha.44")]
@@ -3,6 +3,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Web;
using Umbraco.Core.Components;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -10,7 +11,7 @@ using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Auditing
{
public sealed class AuditEventsComponent : UmbracoComponentBase, IUmbracoCoreComponent
{
@@ -52,6 +53,18 @@ namespace Umbraco.Core.Components
_userService = userService;
_entityService = entityService;
//BackOfficeUserManager.AccountLocked += ;
//BackOfficeUserManager.AccountUnlocked += ;
BackOfficeUserManager.ForgotPasswordRequested += OnForgotPasswordRequest;
BackOfficeUserManager.ForgotPasswordChangedSuccess += OnForgotPasswordChange;
BackOfficeUserManager.LoginFailed += OnLoginFailed;
//BackOfficeUserManager.LoginRequiresVerification += ;
BackOfficeUserManager.LoginSuccess += OnLoginSuccess;
BackOfficeUserManager.LogoutSuccess += OnLogoutSuccess;
BackOfficeUserManager.PasswordChanged += OnPasswordChanged;
BackOfficeUserManager.PasswordReset += OnPasswordReset;
//BackOfficeUserManager.ResetAccessFailedCount += ;
UserService.SavedUserGroup += OnSavedUserGroupWithUsers;
UserService.SavedUser += OnSavedUser;
@@ -242,6 +255,64 @@ namespace Umbraco.Core.Components
"umbraco/user/delete", "delete user");
}
private void OnLoginSuccess(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs)
{
var performingUser = GetPerformingUser(identityArgs.PerformingUser);
WriteAudit(performingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/sign-in/login", "login success");
}
}
private void OnLogoutSuccess(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs)
{
var performingUser = GetPerformingUser(identityArgs.PerformingUser);
WriteAudit(performingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/sign-in/logout", "logout success");
}
}
private void OnPasswordReset(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/reset", "password reset");
}
}
private void OnPasswordChanged(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/change", "password change");
}
}
private void OnLoginFailed(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, 0, identityArgs.IpAddress, "umbraco/user/sign-in/failed", "login failed", affectedDetails: "");
}
}
private void OnForgotPasswordChange(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/forgot/change", "password forgot/change");
}
}
private void OnForgotPasswordRequest(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/forgot/request", "password forgot/request");
}
}
private void WriteAudit(int performingId, int affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null)
{
var performingUser = _userService.GetUserById(performingId);
@@ -1,8 +1,10 @@
using System;
using System.ComponentModel;
using System.Threading;
using System.Web;
using Umbraco.Core.Security;
namespace Umbraco.Web.Security
namespace Umbraco.Core.Auditing
{
/// <summary>
/// This class is used by events raised from hthe BackofficeUserManager
+10 -1
View File
@@ -18,7 +18,10 @@ namespace Umbraco.Core
// this only gets called when an assembly can't be resolved
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private static readonly Regex Log4NetAssemblyPattern = new Regex("log4net, Version=([\\d\\.]+?), Culture=neutral, PublicKeyToken=\\w+$", RegexOptions.Compiled);
private const string Log4NetReplacement = "log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a";
/// <summary>
/// This is used to do an assembly binding redirect via code - normally required due to signature changes in assemblies
/// </summary>
@@ -27,6 +30,12 @@ namespace Umbraco.Core
/// <returns></returns>
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//log4net:
if (Log4NetAssemblyPattern.IsMatch(args.Name) && args.Name != Log4NetReplacement)
{
return Assembly.Load(Log4NetAssemblyPattern.Replace(args.Name, Log4NetReplacement));
}
//AutoMapper:
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
@@ -40,4 +40,4 @@ namespace Umbraco.Core.Collections
public static bool operator !=(CompositeIntStringKey key1, CompositeIntStringKey key2)
=> key1._key2 != key2._key2 || key1._key1 != key2._key1;
}
}
}
@@ -14,31 +14,30 @@ namespace Umbraco.Core.Collections
/// </remarks>
/// <typeparam name="TValue">The type of elements contained in the BindableCollection</typeparam>
/// <typeparam name="TKey">The type of the indexing key</typeparam>
public class ObservableDictionary<TKey, TValue> : ObservableCollection<TValue>, IReadOnlyDictionary<TKey, TValue>, IDictionary<TKey, TValue>
public class ObservableDictionary<TKey, TValue> : ObservableCollection<TValue>
{
protected Dictionary<TKey, int> Indecies { get; }
protected Func<TValue, TKey> KeySelector { get; }
protected Dictionary<TKey, int> Indecies = new Dictionary<TKey, int>();
protected Func<TValue, TKey> KeySelector;
/// <summary>
/// Create new ObservableDictionary
/// </summary>
/// <param name="keySelector">Selector function to create key from value</param>
/// <param name="equalityComparer">The equality comparer to use when comparing keys, or null to use the default comparer.</param>
public ObservableDictionary(Func<TValue, TKey> keySelector, IEqualityComparer<TKey> equalityComparer = null)
public ObservableDictionary(Func<TValue, TKey> keySelector)
: base()
{
KeySelector = keySelector ?? throw new ArgumentException("keySelector");
Indecies = new Dictionary<TKey, int>(equalityComparer);
if (keySelector == null) throw new ArgumentException("keySelector");
KeySelector = keySelector;
}
#region Protected Methods
protected override void InsertItem(int index, TValue item)
{
var key = KeySelector(item);
if (Indecies.ContainsKey(key))
throw new DuplicateKeyException(key.ToString());
if (index != Count)
if (index != this.Count)
{
foreach (var k in Indecies.Keys.Where(k => Indecies[k] >= index).ToList())
{
@@ -48,6 +47,7 @@ namespace Umbraco.Core.Collections
base.InsertItem(index, item);
Indecies[key] = index;
}
protected override void ClearItems()
@@ -56,6 +56,7 @@ namespace Umbraco.Core.Collections
Indecies.Clear();
}
protected override void RemoveItem(int index)
{
var item = this[index];
@@ -70,10 +71,9 @@ namespace Umbraco.Core.Collections
Indecies[k]--;
}
}
#endregion
public bool ContainsKey(TKey key)
public virtual bool ContainsKey(TKey key)
{
return Indecies.ContainsKey(key);
}
@@ -83,10 +83,10 @@ namespace Umbraco.Core.Collections
/// </summary>
/// <param name="key">Key of element to replace</param>
/// <returns></returns>
public TValue this[TKey key]
public virtual TValue this[TKey key]
{
get => this[Indecies[key]];
get { return this[Indecies[key]]; }
set
{
//confirm key matches
@@ -95,7 +95,7 @@ namespace Umbraco.Core.Collections
if (!Indecies.ContainsKey(key))
{
Add(value);
this.Add(value);
}
else
{
@@ -112,10 +112,9 @@ namespace Umbraco.Core.Collections
///
/// <exception cref="InvalidOperationException"></exception>
/// <returns>False if key not found</returns>
public bool Replace(TKey key, TValue value)
public virtual bool Replace(TKey key, TValue value)
{
if (!Indecies.ContainsKey(key)) return false;
//confirm key matches
if (!KeySelector(value).Equals(key))
throw new InvalidOperationException("Key of new value does not match");
@@ -125,11 +124,11 @@ namespace Umbraco.Core.Collections
}
public bool Remove(TKey key)
public virtual bool Remove(TKey key)
{
if (!Indecies.ContainsKey(key)) return false;
RemoveAt(Indecies[key]);
this.RemoveAt(Indecies[key]);
return true;
}
@@ -139,13 +138,12 @@ namespace Umbraco.Core.Collections
/// </summary>
/// <param name="currentKey"></param>
/// <param name="newKey"></param>
public void ChangeKey(TKey currentKey, TKey newKey)
public virtual void ChangeKey(TKey currentKey, TKey newKey)
{
if (!Indecies.ContainsKey(currentKey))
{
throw new InvalidOperationException("No item with the key " + currentKey + "was found in the collection");
}
if (ContainsKey(newKey))
{
throw new DuplicateKeyException(newKey.ToString());
@@ -157,81 +155,16 @@ namespace Umbraco.Core.Collections
Indecies.Add(newKey, currentIndex);
}
#region IDictionary and IReadOnlyDictionary implementation
public bool TryGetValue(TKey key, out TValue val)
{
if (Indecies.TryGetValue(key, out var index))
{
val = this[index];
return true;
}
val = default;
return false;
}
/// <summary>
/// Returns all keys
/// </summary>
public IEnumerable<TKey> Keys => Indecies.Keys;
/// <summary>
/// Returns all values
/// </summary>
public IEnumerable<TValue> Values => base.Items;
ICollection<TKey> IDictionary<TKey, TValue>.Keys => Indecies.Keys;
//this will never be used
ICollection<TValue> IDictionary<TKey, TValue>.Values => Values.ToList();
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
foreach (var i in Values)
{
var key = KeySelector(i);
yield return new KeyValuePair<TKey, TValue>(key, i);
}
}
void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
{
Add(value);
}
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Value);
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
return ContainsKey(item.Key);
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
return Remove(item.Key);
}
#endregion
internal class DuplicateKeyException : Exception
{
public string Key { get; private set; }
public DuplicateKeyException(string key)
: base("Attempted to insert duplicate key \"" + key + "\" in collection.")
: base("Attempted to insert duplicate key " + key + " in collection")
{
Key = key;
}
public string Key { get; }
}
}
}
+3 -3
View File
@@ -111,15 +111,15 @@ namespace Umbraco.Core.Components
catch (Exception e)
{
// in case of an error, force-dump everything to log
_logger.Info<BootLoader>("Component Report:\r\n{ComponentReport}", GetComponentsReport(requirements));
_logger.Error<BootLoader>(e, "Failed to sort compontents.");
_logger.Info<BootLoader>(() => GetComponentsReport(requirements));
_logger.Error<BootLoader>("Failed to sort components.", e);
throw;
}
// bit verbose but should help for troubleshooting
var text = "Ordered Components: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComponentTypes) + Environment.NewLine;
Console.WriteLine(text);
_logger.Debug<BootLoader>("Ordered Components: {SortedComponentTypes}", sortedComponentTypes);
_logger.Debug<BootLoader>(text);
return sortedComponentTypes;
}
@@ -63,6 +63,8 @@ namespace Umbraco.Core.Composing.CompositionRoots
container.RegisterSingleton<IRelationTypeRepository, RelationTypeRepository>();
container.RegisterSingleton<IServerRegistrationRepository, ServerRegistrationRepository>();
container.RegisterSingleton<ITagRepository, TagRepository>();
container.RegisterSingleton<ITaskRepository, TaskRepository>();
container.RegisterSingleton<ITaskTypeRepository, TaskTypeRepository>();
container.RegisterSingleton<ITemplateRepository, TemplateRepository>();
container.RegisterSingleton<IUserGroupRepository, UserGroupRepository>();
container.RegisterSingleton<IUserRepository, UserRepository>();
@@ -28,6 +28,7 @@ namespace Umbraco.Core.Composing.CompositionRoots
// register the services
container.RegisterSingleton<IKeyValueService, KeyValueService>();
container.RegisterSingleton<IPublicAccessService, PublicAccessService>();
container.RegisterSingleton<ITaskService, TaskService>();
container.RegisterSingleton<IDomainService, DomainService>();
container.RegisterSingleton<IAuditService, AuditService>();
container.RegisterSingleton<ITagService, TagService>();
-4
View File
@@ -58,7 +58,6 @@ namespace Umbraco.Core.Composing
// resets *everything* that is 'current'
internal static void Reset()
{
_container?.Dispose();
_container = null;
_shortStringHelper = null;
@@ -159,9 +158,6 @@ namespace Umbraco.Core.Composing
public static IPublishedValueFallback PublishedValueFallback
=> _publishedValueFallback ?? Container.GetInstance<IPublishedValueFallback>() ?? new NoopPublishedValueFallback();
public static IVariationContextAccessor VariationContextAccessor
=> Container.GetInstance<IVariationContextAccessor>();
#endregion
}
}
+5 -4
View File
@@ -148,7 +148,7 @@ namespace Umbraco.Core.Composing
catch (FileNotFoundException ex)
{
//this will occur if it cannot load the assembly
Current.Logger.Error(typeof(TypeFinder), ex, "Could not load assembly App_Code");
Current.Logger.Error(typeof(TypeFinder), "Could not load assembly App_Code", ex);
}
}
}
@@ -224,6 +224,7 @@ namespace Umbraco.Core.Composing
"Dynamic,",
"HtmlDiff,",
"Iesi.Collections,",
"log4net,",
"Microsoft.",
"Newtonsoft.",
"NHibernate.",
@@ -439,7 +440,7 @@ namespace Umbraco.Core.Composing
}
catch (TypeLoadException ex)
{
Current.Logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
Current.Logger.Error(typeof(TypeFinder), $"Could not query types on {assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", ex);
continue;
}
@@ -505,7 +506,7 @@ namespace Umbraco.Core.Composing
}
catch (TypeLoadException ex)
{
Current.Logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly);
Current.Logger.Error(typeof(TypeFinder), $"Could not query types on {assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", ex);
continue;
}
@@ -572,7 +573,7 @@ namespace Umbraco.Core.Composing
if (NotifiedLoadExceptionAssemblies.Contains(a.FullName) == false)
{
NotifiedLoadExceptionAssemblies.Add(a.FullName);
Current.Logger.Warn(typeof (TypeFinder), ex, "Could not load all types from {TypeName}.", a.GetName().Name);
Current.Logger.Warn(typeof (TypeFinder), ex, $"Could not load all types from {a.GetName().Name}.");
}
}
return rex.Types.WhereNotNull().ToArray();
+8 -8
View File
@@ -494,7 +494,7 @@ namespace Umbraco.Core.Composing
if (--attempts == 0)
throw;
_logger.Logger.Debug<TypeLoader>("Attempted to get filestream for file {Path} failed, {NumberOfAttempts} attempts left, pausing for {PauseMilliseconds} milliseconds", path, attempts, pauseMilliseconds);
_logger.Logger.Debug<TypeLoader>(() => $"Attempted to get filestream for file {path} failed, {attempts} attempts left, pausing for {pauseMilliseconds} milliseconds");
Thread.Sleep(pauseMilliseconds);
}
}
@@ -645,7 +645,7 @@ namespace Umbraco.Core.Composing
if (typeList != null)
{
// need to put some logging here to try to figure out why this is happening: http://issues.umbraco.org/issue/U4-3505
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: found a cached type list.", GetName(baseType, attributeType));
_logger.Logger.Debug<TypeLoader>(() => $"Getting {GetName(baseType, attributeType)}: found a cached type list.");
return typeList.Types;
}
@@ -676,7 +676,7 @@ namespace Umbraco.Core.Composing
// so in this instance there will never be a result.
if (cacheResult.Exception is CachedTypeNotFoundInFileException || cacheResult.Success == false)
{
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: failed to load from cache file, must scan assemblies.", GetName(baseType, attributeType));
_logger.Logger.Debug<TypeLoader>(() => $"Getting {GetName(baseType, attributeType)}: failed to load from cache file, must scan assemblies.");
scan = true;
}
else
@@ -695,7 +695,7 @@ namespace Umbraco.Core.Composing
catch (Exception ex)
{
// in case of any exception, we have to exit, and revert to scanning
_logger.Logger.Error<TypeLoader>(ex, "Getting {TypeName}: failed to load cache file type {CacheType}, reverting to scanning assemblies.", GetName(baseType, attributeType), type);
_logger.Logger.Error<TypeLoader>("Getting " + GetName(baseType, attributeType) + ": failed to load cache file type " + type + ", reverting to scanning assemblies.", ex);
scan = true;
break;
}
@@ -703,7 +703,7 @@ namespace Umbraco.Core.Composing
if (scan == false)
{
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: loaded types from cache file.", GetName(baseType, attributeType));
_logger.Logger.Debug<TypeLoader>(() => $"Getting {GetName(baseType, attributeType)}: loaded types from cache file.");
}
}
}
@@ -711,7 +711,7 @@ namespace Umbraco.Core.Composing
if (scan)
{
// either we had to scan, or we could not get the types from the cache file - scan now
_logger.Logger.Debug<TypeLoader>("Getting {TypeName}: scanning assemblies.", GetName(baseType, attributeType));
_logger.Logger.Debug<TypeLoader>(() => $"Getting {GetName(baseType, attributeType)}: scanning assemblies.");
foreach (var t in finder())
typeList.Add(t);
@@ -729,11 +729,11 @@ namespace Umbraco.Core.Composing
UpdateCache();
}
_logger.Logger.Debug<TypeLoader>("Got {TypeName}, caching ({CacheType}).", GetName(baseType, attributeType), added.ToString().ToLowerInvariant());
_logger.Logger.Debug<TypeLoader>(() => $"Got {GetName(baseType, attributeType)}, caching ({added.ToString().ToLowerInvariant()}).");
}
else
{
_logger.Logger.Debug<TypeLoader>("Got {TypeName}.", GetName(baseType, attributeType));
_logger.Logger.Debug<TypeLoader>(() => $"Got {GetName(baseType, attributeType)}.");
}
return typeList.Types;
@@ -12,7 +12,7 @@ using Semver;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Web.UI.JavaScript
namespace Umbraco.Core.Configuration
{
/// <summary>
/// A utility class for working with CDF config and cache files - use sparingly!
@@ -79,13 +79,47 @@ namespace Umbraco.Web.UI.JavaScript
versionAttribute.SetValue(newVersion);
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
_logger.Info<ClientDependencyConfiguration>("Updated version number from {OldVersion} to {NewVersion}", oldVersion, newVersion);
_logger.Info<ClientDependencyConfiguration>(() => $"Updated version number from {oldVersion} to {newVersion}");
return true;
}
}
catch (Exception ex)
{
_logger.Error<ClientDependencyConfiguration>(ex, "Couldn't update ClientDependency version number");
_logger.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
}
return false;
}
/// <summary>
/// Changes the version number in ClientDependency.config to a random value to avoid stale caches
/// </summary>
/// <seealso cref="UpdateVersionNumber(SemVersion, DateTime, string)" />
[Obsolete("Use the UpdateVersionNumber method specifying the version, date and dateFormat instead")]
public bool IncreaseVersionNumber()
{
try
{
var clientDependencyConfigXml = XDocument.Load(_fileName, LoadOptions.PreserveWhitespace);
if (clientDependencyConfigXml.Root != null)
{
var versionAttribute = clientDependencyConfigXml.Root.Attribute("version");
//Set the new version to the hashcode of now
var oldVersion = versionAttribute.Value;
var newVersion = Math.Abs(DateTime.UtcNow.GetHashCode());
versionAttribute.SetValue(newVersion);
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
_logger.Info<ClientDependencyConfiguration>(() => $"Updated version number from {oldVersion} to {newVersion}");
return true;
}
}
catch (Exception ex)
{
_logger.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
}
return false;
@@ -107,7 +141,7 @@ namespace Umbraco.Web.UI.JavaScript
try
{
var fullPath = currentHttpContext.Server.MapPath(XmlFileMapper.FileMapDefaultFolder);
var fullPath = currentHttpContext.Server.MapPath(XmlFileMapper.FileMapVirtualFolder);
if (fullPath != null)
{
cdfTempDirectories.Add(fullPath);
@@ -116,7 +150,7 @@ namespace Umbraco.Web.UI.JavaScript
catch (Exception ex)
{
//invalid path format or something... try/catch to be safe
_logger.Error<ClientDependencyConfiguration>(ex, "Could not get path from ClientDependency.config");
_logger.Error<ClientDependencyConfiguration>("Could not get path from ClientDependency.config", ex);
}
var success = true;
@@ -133,7 +167,7 @@ namespace Umbraco.Web.UI.JavaScript
catch (Exception ex)
{
// Something could be locking the directory or the was another error, making sure we don't break the upgrade installer
_logger.Error<ClientDependencyConfiguration>(ex, "Could not clear temp files");
_logger.Error<ClientDependencyConfiguration>("Could not clear temp files", ex);
success = false;
}
}
@@ -61,8 +61,7 @@ namespace Umbraco.Core.Configuration
var config = WebConfigurationManager.OpenWebConfiguration(appPath);
var settings = (MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings");
// note: "noreply@example.com" is/was the sample SMTP from email - we'll regard that as "not configured"
if (settings == null || settings.Smtp == null || "noreply@example.com".Equals(settings.Smtp.From, StringComparison.OrdinalIgnoreCase)) return false;
if (settings == null || settings.Smtp == null) return false;
if (settings.Smtp.SpecifiedPickupDirectory != null && string.IsNullOrEmpty(settings.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation) == false)
return true;
if (settings.Smtp.Network != null && string.IsNullOrEmpty(settings.Smtp.Network.Host) == false)
@@ -40,15 +40,13 @@ namespace Umbraco.Core.Configuration.Grid
var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js");
if (File.Exists(gridConfig))
{
var sourceString = File.ReadAllText(gridConfig);
try
{
editors.AddRange(parser.ParseGridEditors(sourceString));
editors.AddRange(parser.ParseGridEditors(File.ReadAllText(gridConfig)));
}
catch (Exception ex)
{
_logger.Error<GridEditorsConfig>(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString);
_logger.Error<GridEditorsConfig>("Could not parse the contents of grid.editors.config.js into a JSON array", ex);
}
}
@@ -88,7 +88,7 @@ namespace Umbraco.Core.Configuration
if (_healthChecks == null)
{
var ex = new ConfigurationErrorsException("Could not load the " + typeof(IHealthChecks) + " from config file, ensure the web.config and healthchecks.config files are formatted correctly");
Current.Logger.Error<UmbracoConfig>(ex, "Config error");
Current.Logger.Error<UmbracoConfig>("Config error", ex);
throw ex;
}
@@ -103,7 +103,7 @@ namespace Umbraco.Core.Configuration
if (_dashboardSection == null)
{
var ex = new ConfigurationErrorsException("Could not load the " + typeof(IDashboardSection) + " from config file, ensure the web.config and Dashboard.config files are formatted correctly");
Current.Logger.Error<UmbracoConfig>(ex, "Config error");
Current.Logger.Error<UmbracoConfig>("Config error", ex);
throw ex;
}
@@ -162,7 +162,7 @@ namespace Umbraco.Core.Configuration
if (_umbracoSettings == null)
{
var ex = new ConfigurationErrorsException("Could not load the " + typeof (IUmbracoSettingsSection) + " from config file, ensure the web.config and umbracoSettings.config files are formatted correctly");
Current.Logger.Error<UmbracoConfig>(ex, "Config error");
Current.Logger.Error<UmbracoConfig>("Config error", ex);
throw ex;
}
@@ -193,4 +193,4 @@ namespace Umbraco.Core.Configuration
//TODO: Add other configurations here !
}
}
}
@@ -136,7 +136,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
bool IContentSection.EnableInheritedMediaTypes => EnableInheritedMediaTypes;
string IContentSection.LoginBackgroundImage => LoginBackgroundImage;
}
}
@@ -1,24 +1,9 @@
using System;
using System.Linq;
using System.Linq;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public static class ContentSectionExtensions
{
/// <summary>
/// Gets a value indicating whether the file extension corresponds to an image.
/// </summary>
/// <param name="extension">The file extension.</param>
/// <param name="contentConfig"></param>
/// <returns>A value indicating whether the file extension corresponds to an image.</returns>
public static bool IsImageFile(this IContentSection contentConfig, string extension)
{
if (contentConfig == null) throw new ArgumentNullException(nameof(contentConfig));
if (extension == null) return false;
extension = extension.TrimStart('.');
return contentConfig.ImageFileTypes.InvariantContains(extension);
}
/// <summary>
/// Determines if file extension is allowed for upload based on (optional) white list and black list
/// held in settings.
@@ -30,17 +15,5 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
(contentSection.AllowedUploadFiles.Any() == false &&
contentSection.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false);
}
/// <summary>
/// Gets the auto-fill configuration for a specified property alias.
/// </summary>
/// <param name="contentSection"></param>
/// <param name="propertyTypeAlias">The property type alias.</param>
/// <returns>The auto-fill configuration for the specified property alias, or null.</returns>
public static IImagingAutoFillUploadField GetConfig(this IContentSection contentSection, string propertyTypeAlias)
{
var autoFillConfigs = contentSection.ImageAutoFillProperties;
return autoFillConfigs?.FirstOrDefault(x => x.Alias == propertyTypeAlias);
}
}
}
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
IEnumerable<string> ImageTagAllowedAttributes { get; }
IEnumerable<IImagingAutoFillUploadField> ImageAutoFillProperties { get; }
string ScriptFolderPath { get; }
IEnumerable<string> ScriptFileTypes { get; }
@@ -67,4 +67,4 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
string LoginBackgroundImage { get; }
}
}
}
@@ -8,8 +8,6 @@
bool DisableAlternativeTemplates { get; }
bool ValidateAlternativeTemplates { get; }
bool DisableFindContentByIdPath { get; }
bool DisableRedirectUrlTracking { get; }
@@ -18,4 +16,5 @@
string UmbracoApplicationUrl { get; }
}
}
@@ -5,27 +5,44 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
internal class WebRoutingElement : ConfigurationElement, IWebRoutingSection
{
[ConfigurationProperty("trySkipIisCustomErrors", DefaultValue = "false")]
public bool TrySkipIisCustomErrors => (bool) base["trySkipIisCustomErrors"];
public bool TrySkipIisCustomErrors
{
get { return (bool) base["trySkipIisCustomErrors"]; }
}
[ConfigurationProperty("internalRedirectPreservesTemplate", DefaultValue = "false")]
public bool InternalRedirectPreservesTemplate => (bool) base["internalRedirectPreservesTemplate"];
public bool InternalRedirectPreservesTemplate
{
get { return (bool) base["internalRedirectPreservesTemplate"]; }
}
[ConfigurationProperty("disableAlternativeTemplates", DefaultValue = "false")]
public bool DisableAlternativeTemplates => (bool) base["disableAlternativeTemplates"];
[ConfigurationProperty("validateAlternativeTemplates", DefaultValue = "false")]
public bool ValidateAlternativeTemplates => (bool) base["validateAlternativeTemplates"];
public bool DisableAlternativeTemplates
{
get { return (bool) base["disableAlternativeTemplates"]; }
}
[ConfigurationProperty("disableFindContentByIdPath", DefaultValue = "false")]
public bool DisableFindContentByIdPath => (bool) base["disableFindContentByIdPath"];
public bool DisableFindContentByIdPath
{
get { return (bool) base["disableFindContentByIdPath"]; }
}
[ConfigurationProperty("disableRedirectUrlTracking", DefaultValue = "false")]
public bool DisableRedirectUrlTracking => (bool) base["disableRedirectUrlTracking"];
public bool DisableRedirectUrlTracking
{
get { return (bool) base["disableRedirectUrlTracking"]; }
}
[ConfigurationProperty("urlProviderMode", DefaultValue = "AutoLegacy")]
public string UrlProviderMode => (string) base["urlProviderMode"];
public string UrlProviderMode
{
get { return (string) base["urlProviderMode"]; }
}
[ConfigurationProperty("umbracoApplicationUrl", DefaultValue = null)]
public string UmbracoApplicationUrl => (string)base["umbracoApplicationUrl"];
public string UmbracoApplicationUrl
{
get { return (string)base["umbracoApplicationUrl"]; }
}
}
}
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Configuration
/// <summary>
/// Gets the version comment of the executing code (eg "beta").
/// </summary>
public static string CurrentComment => "alpha.52";
public static string CurrentComment => "alpha.44";
/// <summary>
/// Gets the assembly version of Umbraco.Code.dll.
+2 -11
View File
@@ -13,9 +13,9 @@
public const string Content = "content";
/// <summary>
/// Application alias for the packages section.
/// Application alias for the developer section.
/// </summary>
public const string Packages = "packages";
public const string Developer = "developer";
/// <summary>
/// Application alias for the media section.
@@ -145,15 +145,6 @@
public const string PartialViewMacros = "partialViewMacros";
public static class Groups
{
public const string Settings = "settingsGroup";
public const string Templating = "templatingGroup";
public const string ThirdParty = "thirdPartyGroup";
}
//TODO: Fill in the rest!
}
}
+3 -5
View File
@@ -23,6 +23,9 @@ namespace Umbraco.Core
{
public const string MemberUsernameRuleType = "MemberUsername";
public const string MemberRoleRuleType = "MemberRole";
[Obsolete("No longer supported, this is here for backwards compatibility only")]
public const string MemberIdRuleType = "MemberId";
}
@@ -91,11 +94,6 @@ namespace Umbraco.Core
/// Property alias for the Media's file extension.
/// </summary>
public const string Extension = "umbracoExtension";
/// <summary>
/// The default height/width of an image file if the size can't be determined from the metadata
/// </summary>
public const int DefaultSize = 200;
}
/// <summary>
+1 -3
View File
@@ -13,9 +13,7 @@
public const int Textbox = -88;
public const int Boolean = -49;
public const int DateTime = -36;
public const int DropDownSingle = -39;
public const int DropDownMultiple = -42;
public const int Datetime = -36;
public const int DefaultContentListView = -95;
public const int DefaultMediaListView = -96;
@@ -71,6 +71,9 @@ namespace Umbraco.Core
[Obsolete("This no longer exists in the database")]
internal const string Stylesheet = "9F68DA4F-A3A8-44C2-8226-DCBD125E4840";
[Obsolete("This no longer exists in the database")]
internal const string StylesheetProperty = "5555da4f-a123-42b2-4488-dcdfb25e4111";
// ReSharper restore MemberHidesStaticFromOuterClass
}
-1
View File
@@ -58,7 +58,6 @@
/// </remarks>
public const string RecycleBinMediaPathPrefix = "-1,-21,";
public const int DefaultLabelDataTypeId = -92;
public const string UmbracoConnectionName = "umbracoDbDSN";
public const string UmbracoUpgradePlanName = "Umbraco.Core";
}
@@ -115,7 +115,7 @@ namespace Umbraco.Core
/// <summary>
/// Determines whether a variation varies by culture and segment.
/// </summary>
public static bool VariesByCultureAndSegment(this ContentVariation variation) => (variation & ContentVariation.CultureAndSegment) == ContentVariation.CultureAndSegment;
public static bool VariesByCultureAndSegment(this ContentVariation variation) => (variation & ContentVariation.CultureAndSegment) > 0;
/// <summary>
/// Validates that a combination of culture and segment is valid for the variation.
@@ -1,7 +1,8 @@
using System;
using System.Diagnostics;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Logging
namespace Umbraco.Core
{
/// <summary>
/// Starts the timer and invokes a callback upon disposal. Provides a simple way of timing an operation by wrapping it in a <code>using</code> (C#) statement.
@@ -9,7 +10,7 @@ namespace Umbraco.Core.Logging
public class DisposableTimer : DisposableObjectSlim
{
private readonly ILogger _logger;
private readonly LogLevel _level;
private readonly LogType? _logType;
private readonly Type _loggerType;
private readonly int _thresholdMilliseconds;
private readonly IDisposable _profilerStep;
@@ -17,33 +18,39 @@ namespace Umbraco.Core.Logging
private string _failMessage;
private Exception _failException;
private bool _failed;
private readonly string _timingId;
internal enum LogType
{
Debug, Info
}
// internal - created by profiling logger
internal DisposableTimer(ILogger logger, LogLevel level, IProfiler profiler, Type loggerType,
internal DisposableTimer(ILogger logger, LogType logType, IProfiler profiler, Type loggerType,
string startMessage, string endMessage, string failMessage = null,
int thresholdMilliseconds = 0)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_level = level;
_loggerType = loggerType ?? throw new ArgumentNullException(nameof(loggerType));
if (logger == null) throw new ArgumentNullException(nameof(logger));
if (loggerType == null) throw new ArgumentNullException(nameof(loggerType));
_logger = logger;
_logType = logType;
_loggerType = loggerType;
_endMessage = endMessage;
_failMessage = failMessage;
_thresholdMilliseconds = thresholdMilliseconds < 0 ? 0 : thresholdMilliseconds;
_timingId = Guid.NewGuid().ToString("N").Substring(0, 7); // keep it short-ish
if (thresholdMilliseconds == 0)
{
switch (_level)
switch (logType)
{
case LogLevel.Debug:
logger.Debug(loggerType, "{StartMessage} [Timing {TimingId}]", startMessage, _timingId);
case LogType.Debug:
logger.Debug(loggerType, startMessage);
break;
case LogLevel.Information:
logger.Info(loggerType, "{StartMessage} [Timing {TimingId}]", startMessage, _timingId);
case LogType.Info:
logger.Info(loggerType, startMessage);
break;
default:
throw new ArgumentOutOfRangeException(nameof(level));
throw new ArgumentOutOfRangeException(nameof(logType));
}
}
@@ -79,20 +86,20 @@ namespace Umbraco.Core.Logging
_profilerStep?.Dispose();
if ((Stopwatch.ElapsedMilliseconds >= _thresholdMilliseconds || _failed)
&& _loggerType != null && _logger != null
&& _logType.HasValue && _loggerType != null && _logger != null
&& (_endMessage.IsNullOrWhiteSpace() == false || _failed))
{
if (_failed)
{
_logger.Error(_loggerType, _failException, "{FailMessage} ({Duration}ms) [Timing {TimingId}]", _failMessage, Stopwatch.ElapsedMilliseconds, _timingId);
_logger.Error(_loggerType, $"{_failMessage} ({Stopwatch.ElapsedMilliseconds}ms)", _failException);
}
else switch (_level)
else switch (_logType)
{
case LogLevel.Debug:
_logger.Debug(_loggerType, "{EndMessage} ({Duration}ms) [Timing {TimingId}]", _endMessage, Stopwatch.ElapsedMilliseconds, _timingId);
case LogType.Debug:
_logger.Debug(_loggerType, () => $"{_endMessage} ({Stopwatch.ElapsedMilliseconds}ms)");
break;
case LogLevel.Information:
_logger.Info(_loggerType, "{EndMessage} ({Duration}ms) [Timing {TimingId}]", _endMessage, Stopwatch.ElapsedMilliseconds, _timingId);
case LogType.Info:
_logger.Info(_loggerType, () => $"{_endMessage} ({Stopwatch.ElapsedMilliseconds}ms)");
break;
// filtered in the ctor
//default:
+12 -1
View File
@@ -92,7 +92,18 @@ namespace Umbraco.Core
}
}
/// <summary>The flatten list.</summary>
/// <param name="e">The items.</param>
/// <param name="f">The select child.</param>
/// <typeparam name="T">Item type</typeparam>
/// <returns>list of TItem</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Do not use, use SelectRecursive instead which has far less potential of re-iterating an iterator which may cause significantly more SQL queries")]
public static IEnumerable<T> FlattenList<T>(this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
{
return e.SelectMany(c => f(c).FlattenList(f)).Concat(e);
}
/// <summary>
/// Returns true if all items in the other collection exist in this collection
/// </summary>
+4 -1
View File
@@ -14,7 +14,10 @@ namespace Umbraco.Core.Events
_msgs.Add(msg);
}
public int Count => _msgs.Count;
public int Count
{
get { return _msgs.Count; }
}
public IEnumerable<EventMessage> GetAll()
{
@@ -307,7 +307,7 @@ namespace Umbraco.Core.Events
// fixme see notes above
// delete event args does NOT superceedes 'unpublished' event
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition.EventName == "Unpublished")
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition.EventName == "UnPublished")
return false;
// found occurences, need to determine if this event args is superceded
+5 -13
View File
@@ -24,19 +24,11 @@ namespace Umbraco.Core
{
return "Unknown, httpContext is null";
}
HttpRequestBase request;
try
{
// is not null - throws
request = httpContext.Request;
}
catch
if (httpContext.Request == null)
{
return "Unknown, httpContext.Request is null";
}
if (request.ServerVariables == null)
if (httpContext.Request.ServerVariables == null)
{
return "Unknown, httpContext.Request.ServerVariables is null";
}
@@ -45,16 +37,16 @@ namespace Umbraco.Core
try
{
var ipAddress = request.ServerVariables["HTTP_X_FORWARDED_FOR"];
var ipAddress = httpContext.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ipAddress))
return request.UserHostAddress;
return httpContext.Request.UserHostAddress;
var addresses = ipAddress.Split(',');
if (addresses.Length != 0)
return addresses[0];
return request.UserHostAddress;
return httpContext.Request.UserHostAddress;
}
catch (System.Exception ex)
{
+118 -5
View File
@@ -1,15 +1,20 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using LightInject;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Composing;
using Umbraco.Core.Exceptions;
using Umbraco.Core.IO.MediaPathSchemes;
using Umbraco.Core.Logging;
using Umbraco.Core.Media;
using Umbraco.Core.Media.Exif;
using Umbraco.Core.Models;
namespace Umbraco.Core.IO
@@ -27,6 +32,8 @@ namespace Umbraco.Core.IO
// dependencies, so we have to rely on property injection for anything we might need
Current.Container.InjectProperties(this);
MediaPathScheme.Initialize(this);
UploadAutoFillProperties = new UploadAutoFillProperties(this, Logger, ContentConfig);
}
[Inject]
@@ -37,7 +44,9 @@ namespace Umbraco.Core.IO
[Inject]
internal ILogger Logger { get; set; }
internal UploadAutoFillProperties UploadAutoFillProperties { get; }
/// <summary>
/// Deletes all files passed in.
/// </summary>
@@ -102,7 +111,7 @@ namespace Umbraco.Core.IO
}
catch (Exception e)
{
Logger.Error<MediaFileSystem>(e, "Failed to delete attached file '{File}'", file);
Logger.Error<MediaFileSystem>("Failed to delete attached file \"" + file + "\".", e);
}
});
}
@@ -204,9 +213,113 @@ namespace Umbraco.Core.IO
return filepath;
}
// gets or creates a property for a content item.
private static Property GetProperty(IContentBase content, string propertyTypeAlias)
{
var property = content.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias));
if (property != null) return property;
var propertyType = content.GetContentType().CompositionPropertyTypes
.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias));
if (propertyType == null)
throw new Exception("No property type exists with alias " + propertyTypeAlias + ".");
property = new Property(propertyType);
content.Properties.Add(property);
return property;
}
// fixme - what's below belongs to the upload property editor, not the media filesystem!
public void SetUploadFile(IContentBase content, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null)
{
var property = GetProperty(content, propertyTypeAlias);
var oldpath = property.GetValue(culture, segment) is string svalue ? GetRelativePath(svalue) : null;
var filepath = StoreFile(content, property.PropertyType, filename, filestream, oldpath);
property.SetValue(GetUrl(filepath), culture, segment);
SetUploadFile(content, property, filepath, filestream, culture, segment);
}
public void SetUploadFile(IContentBase content, string propertyTypeAlias, string filepath, string culture = null, string segment = null)
{
var property = GetProperty(content, propertyTypeAlias);
// fixme delete?
var oldpath = property.GetValue(culture, segment) is string svalue ? GetRelativePath(svalue) : null;
if (string.IsNullOrWhiteSpace(oldpath) == false && oldpath != filepath)
DeleteFile(oldpath);
property.SetValue(GetUrl(filepath), culture, segment);
using (var filestream = OpenFile(filepath))
{
SetUploadFile(content, property, filepath, filestream, culture, segment);
}
}
// sets a file for the FileUpload property editor
// ie generates thumbnails and populates autofill properties
private void SetUploadFile(IContentBase content, Property property, string filepath, Stream filestream, string culture = null, string segment = null)
{
// will use filepath for extension, and filestream for length
UploadAutoFillProperties.Populate(content, property.Alias, filepath, filestream, culture, segment);
}
#endregion
#region Image
/// <summary>
/// Gets a value indicating whether the file extension corresponds to an image.
/// </summary>
/// <param name="extension">The file extension.</param>
/// <returns>A value indicating whether the file extension corresponds to an image.</returns>
public bool IsImageFile(string extension)
{
if (extension == null) return false;
extension = extension.TrimStart('.');
return ContentConfig.ImageFileTypes.InvariantContains(extension);
}
/// <summary>
/// Gets the dimensions of an image.
/// </summary>
/// <param name="stream">A stream containing the image bytes.</param>
/// <returns>The dimension of the image.</returns>
/// <remarks>First try with EXIF as it is faster and does not load the entire image
/// in memory. Fallback to GDI which means loading the image in memory and thus
/// use potentially large amounts of memory.</remarks>
public Size GetDimensions(Stream stream)
{
//Try to load with exif
try
{
var jpgInfo = ImageFile.FromStream(stream);
if (jpgInfo.Format != ImageFileFormat.Unknown
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelYDimension)
&& jpgInfo.Properties.ContainsKey(ExifTag.PixelXDimension))
{
var height = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelYDimension].Value);
var width = Convert.ToInt32(jpgInfo.Properties[ExifTag.PixelXDimension].Value);
if (height > 0 && width > 0)
{
return new Size(width, height);
}
}
}
catch (Exception)
{
//We will just swallow, just means we can't read exif data, we don't want to log an error either
}
//we have no choice but to try to read in via GDI
using (var image = Image.FromStream(stream))
{
var fileWidth = image.Width;
var fileHeight = image.Height;
return new Size(fileWidth, fileHeight);
}
}
#endregion
}
}
+6 -6
View File
@@ -73,11 +73,11 @@ namespace Umbraco.Core.IO
}
catch (UnauthorizedAccessException ex)
{
Current.Logger.Error<PhysicalFileSystem>(ex, "Not authorized to get directories for '{Path}'", fullPath);
Current.Logger.Error<PhysicalFileSystem>("Not authorized to get directories", ex);
}
catch (DirectoryNotFoundException ex)
{
Current.Logger.Error<PhysicalFileSystem>(ex, "Directory not found for '{Path}'", fullPath);
Current.Logger.Error<PhysicalFileSystem>("Directory not found", ex);
}
return Enumerable.Empty<string>();
@@ -109,7 +109,7 @@ namespace Umbraco.Core.IO
}
catch (DirectoryNotFoundException ex)
{
Current.Logger.Error<PhysicalFileSystem>(ex, "Directory not found for '{Path}'", fullPath);
Current.Logger.Error<PhysicalFileSystem>("Directory not found", ex);
}
}
@@ -189,11 +189,11 @@ namespace Umbraco.Core.IO
}
catch (UnauthorizedAccessException ex)
{
Current.Logger.Error<PhysicalFileSystem>(ex, "Not authorized to get directories for '{Path}'", fullPath);
Current.Logger.Error<PhysicalFileSystem>("Not authorized to get directories", ex);
}
catch (DirectoryNotFoundException ex)
{
Current.Logger.Error<PhysicalFileSystem>(ex, "Directory not found for '{FullPath}'", fullPath);
Current.Logger.Error<PhysicalFileSystem>("Directory not found", ex);
}
return Enumerable.Empty<string>();
@@ -226,7 +226,7 @@ namespace Umbraco.Core.IO
}
catch (FileNotFoundException ex)
{
Current.Logger.Error<PhysicalFileSystem>(ex.InnerException, "DeleteFile failed with FileNotFoundException for '{Path}'", fullPath);
Current.Logger.Info<PhysicalFileSystem>(() => $"DeleteFile failed with FileNotFoundException: {ex.InnerException}");
}
}
+2 -2
View File
@@ -54,7 +54,7 @@ namespace Umbraco.Core.IO
}
_logger = logger;
_logger.Debug<ShadowFileSystems>("Shadow '{ShadowId}'", id);
_logger.Debug<ShadowFileSystems>(() => "Shadow " + id + ".");
_id = id;
_wrappers = wrappers;
@@ -112,7 +112,7 @@ namespace Umbraco.Core.IO
{
lock (Locker)
{
_logger.Debug<ShadowFileSystems>("UnShadow '{ShadowId}' {Status}", _id, _completed ? "complete" : "abort");
_logger.Debug<ShadowFileSystems>(() => "UnShadow " + _id + " (" + (_completed ? "complete" : "abort") + ").");
var exceptions = new List<Exception>();
foreach (var wrapper in _wrappers)
+6 -3
View File
@@ -6,7 +6,10 @@ namespace Umbraco.Core.IO
//all paths has a starting but no trailing /
public class SystemDirectories
{
public static string Bin => "~/bin";
//TODO: Why on earth is this even configurable? You cannot change the /Bin folder in ASP.Net
public static string Bin => IOHelper.ReturnPath("umbracoBinDirectory", "~/bin");
public static string Base => IOHelper.ReturnPath("umbracoBaseDirectory", "~/base");
public static string Config => IOHelper.ReturnPath("umbracoConfigDirectory", "~/config");
@@ -16,7 +19,6 @@ namespace Umbraco.Core.IO
public static string Install => IOHelper.ReturnPath("umbracoInstallPath", "~/install");
//TODO: Consider removing this
public static string Masterpages => IOHelper.ReturnPath("umbracoMasterPagesPath", "~/masterpages");
//NOTE: this is not configurable and shouldn't need to be
@@ -38,7 +40,8 @@ namespace Umbraco.Core.IO
public static string Umbraco => IOHelper.ReturnPath("umbracoPath", "~/umbraco");
//TODO: Consider removing this
public static string UmbracoClient => IOHelper.ReturnPath("umbracoClientPath", "~/umbraco_client");
public static string UserControls => IOHelper.ReturnPath("umbracoUsercontrolsPath", "~/usercontrols");
public static string WebServices => IOHelper.ReturnPath("umbracoWebservicesPath", Umbraco.EnsureEndsWith("/") + "webservices");
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Allows for outputting a normalized appdomainappid token in a log format
/// </summary>
public sealed class AppDomainTokenConverter : log4net.Util.PatternConverter
{
protected override void Convert(TextWriter writer, object state)
{
writer.Write(HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty));
}
}
}
@@ -0,0 +1,121 @@
using log4net.Appender;
using log4net.Core;
using log4net.Util;
using System;
using System.Runtime.Remoting.Messaging;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </summary>
public abstract class AsyncForwardingAppenderBase : ForwardingAppender
{
#region Private Members
private const FixFlags DefaultFixFlags = FixFlags.Partial;
private FixFlags fixFlags = DefaultFixFlags;
private LoggingEventHelper loggingEventHelper;
#endregion Private Members
#region Properties
public FixFlags Fix
{
get { return fixFlags; }
set { SetFixFlags(value); }
}
/// <summary>
/// Returns HttpContext.Current
/// </summary>
protected internal object HttpContext
{
get
{
return CallContext.HostContext;
}
set
{
CallContext.HostContext = value;
}
}
/// <summary>
/// The logger name that will be used for logging internal errors.
/// </summary>
protected abstract string InternalLoggerName { get; }
public abstract int? BufferSize { get; set; }
#endregion Properties
public override void ActivateOptions()
{
base.ActivateOptions();
loggingEventHelper = new LoggingEventHelper(InternalLoggerName, DefaultFixFlags);
InitializeAppenders();
}
#region Appender Management
public override void AddAppender(IAppender newAppender)
{
base.AddAppender(newAppender);
SetAppenderFixFlags(newAppender);
}
private void SetFixFlags(FixFlags newFixFlags)
{
if (newFixFlags != fixFlags)
{
loggingEventHelper.Fix = newFixFlags;
fixFlags = newFixFlags;
InitializeAppenders();
}
}
private void InitializeAppenders()
{
foreach (var appender in Appenders)
{
SetAppenderFixFlags(appender);
}
}
private void SetAppenderFixFlags(IAppender appender)
{
var bufferingAppender = appender as BufferingAppenderSkeleton;
if (bufferingAppender != null)
{
bufferingAppender.Fix = Fix;
}
}
#endregion Appender Management
#region Forwarding
protected void ForwardInternalError(string message, Exception exception, Type thisType)
{
LogLog.Error(thisType, message, exception);
var loggingEvent = loggingEventHelper.CreateLoggingEvent(Level.Error, message, exception);
ForwardLoggingEvent(loggingEvent, thisType);
}
protected void ForwardLoggingEvent(LoggingEvent loggingEvent, Type thisType)
{
try
{
base.Append(loggingEvent);
}
catch (Exception exception)
{
LogLog.Error(thisType, "Unable to forward logging event", exception);
}
}
#endregion Forwarding
}
}
@@ -1,4 +1,5 @@
using System;
using System.Linq;
namespace Umbraco.Core.Logging
{
@@ -7,79 +8,34 @@ namespace Umbraco.Core.Logging
/// </summary>
public class DebugDiagnosticsLogger : ILogger
{
public bool IsEnabled(Type reporting, LogLevel level)
=> true;
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception, string message)
public void Error(Type reporting, string message, Exception exception = null)
{
System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception)
public void Warn(Type reporting, string format)
{
System.Diagnostics.Debug.WriteLine(Environment.NewLine + exception, reporting.FullName);
System.Diagnostics.Debug.WriteLine(format, reporting.FullName);
}
/// <inheritdoc/>
public void Fatal(Type reporting, string message)
public void Warn(Type reporting, Func<string> messageBuilder)
{
System.Diagnostics.Debug.WriteLine(message);
System.Diagnostics.Debug.WriteLine(messageBuilder(), reporting.FullName);
}
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
public void Warn(Type reporting, string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName);
System.Diagnostics.Debug.WriteLine(string.Format(format, args), reporting.FullName);
}
/// <inheritdoc/>
public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues)
public void Warn(Type reporting, string format, params Func<object>[] args)
{
System.Diagnostics.Debug.WriteLine(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string message)
{
System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception)
{
System.Diagnostics.Debug.WriteLine(Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Error(Type reporting, string message)
{
System.Diagnostics.Debug.WriteLine(message);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Error(Type reporting, string messageTemplate, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Warn(Type reporting, string message)
{
System.Diagnostics.Debug.WriteLine(message, reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, string message, params object[] propertyValues)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(message, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(string.Format(format, args.Select(x => x()).ToArray()), reporting.FullName);
}
/// <inheritdoc/>
@@ -89,9 +45,21 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string message, params object[] propertyValues)
public void Warn(Type reporting, Exception exception, Func<string> messageBuilder)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(message + Environment.NewLine + exception, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(messageBuilder() + Environment.NewLine + exception, reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format + Environment.NewLine + exception, args), reporting.FullName);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string format, params Func<object>[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format + Environment.NewLine + exception, args.Select(x => x()).ToArray()), reporting.FullName);
}
/// <inheritdoc/>
@@ -101,9 +69,21 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
public void Info(Type reporting, string messageTemplate, params object[] propertyValues)
public void Info(Type reporting, Func<string> messageBuilder)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(messageBuilder(), reporting.FullName);
}
/// <inheritdoc/>
public void Info(Type reporting, string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format, args), reporting.FullName);
}
/// <inheritdoc/>
public void Info(Type reporting, string format, params Func<object>[] args)
{
System.Diagnostics.Debug.WriteLine(string.Format(format, args.Select(x => x()).ToArray()), reporting.FullName);
}
/// <inheritdoc/>
@@ -113,21 +93,21 @@ namespace Umbraco.Core.Logging
}
/// <inheritdoc/>
public void Debug(Type reporting, string messageTemplate, params object[] propertyValues)
public void Debug(Type reporting, Func<string> messageBuilder)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(messageBuilder(), reporting.FullName);
}
/// <inheritdoc/>
public void Verbose(Type reporting, string message)
public void Debug(Type reporting, string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(message, reporting.FullName);
System.Diagnostics.Debug.WriteLine(string.Format(format, args), reporting.FullName);
}
/// <inheritdoc/>
public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues)
public void Debug(Type reporting, string format, params Func<object>[] args)
{
System.Diagnostics.Debug.WriteLine(MessageTemplates.Render(messageTemplate, propertyValues), reporting.FullName);
System.Diagnostics.Debug.WriteLine(string.Format(format, args.Select(x => x()).ToArray()), reporting.FullName);
}
}
}
+13 -115
View File
@@ -1,105 +1,22 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Defines the logging service.
/// </summary>
/// <remarks>
/// <para>Message templates in logging methods follow the Message Templates specification
/// available at https://messagetemplates.org/ in order to support structured logging.</para>
/// <para>Implementations must ensure that they support these templates. Note that the
/// specification includes support for traditional C# numeric placeholders.</para>
/// <para>For instance, "Processed {Input} in {Time}ms."</para>
/// </remarks>
public interface ILogger
{
/// <summary>
/// Determines if logging is enabled at a specified level, for a reporting type.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="level">The level.</param>
bool IsEnabled(Type reporting, LogLevel level);
/// <summary>
/// Logs a fatal message with an exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
void Fatal(Type reporting, Exception exception, string message);
/// <summary>
/// Logs a fatal exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <remarks>The message string is unspecified and is implementation-specific.</remarks>
void Fatal(Type reporting, Exception exception);
/// <summary>
/// Logs a fatal message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="message">A message.</param>
void Fatal(Type reporting, string message);
/// <summary>
/// Logs a fatal message with an exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs a fatal message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Fatal(Type reporting, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs an error message with an exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
void Error(Type reporting, Exception exception, string message);
/// <summary>
/// Logs an error exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <remarks>The message string is unspecified and is implementation-specific.</remarks>
void Error(Type reporting, Exception exception);
/// <summary>
/// Logs an error message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="message">A message.</param>
void Error(Type reporting, string message);
/// <summary>
/// Logs an error message with an exception.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues);
void Error(Type reporting, string message, Exception exception = null);
/// <summary>
/// Logs an error message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Error(Type reporting, string messageTemplate, params object[] propertyValues);
// note: should we have more overloads for Error too?
/// <summary>
/// Logs a warning message.
@@ -112,9 +29,8 @@ namespace Umbraco.Core.Logging
/// Logs a warning message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Warn(Type reporting, string messageTemplate, params object[] propertyValues);
/// <param name="messageBuilder">A message builder.</param>
void Warn(Type reporting, Func<string> messageBuilder);
/// <summary>
/// Logs a warning message with an exception.
@@ -129,9 +45,8 @@ namespace Umbraco.Core.Logging
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues);
/// <param name="messageBuilder">A message builder.</param>
void Warn(Type reporting, Exception exception, Func<string> messageBuilder);
/// <summary>
/// Logs an information message.
@@ -141,12 +56,11 @@ namespace Umbraco.Core.Logging
void Info(Type reporting, string message);
/// <summary>
/// Logs a info message.
/// Logs an information message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Info(Type reporting, string messageTemplate, params object[] propertyValues);
/// <param name="messageBuilder">A message builder.</param>
void Info(Type reporting, Func<string> messageBuilder);
/// <summary>
/// Logs a debugging message.
@@ -156,26 +70,10 @@ namespace Umbraco.Core.Logging
void Debug(Type reporting, string message);
/// <summary>
/// Logs a debug message.
/// Logs a debugging message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Debug(Type reporting, string messageTemplate, params object[] propertyValues);
/// <summary>
/// Logs a verbose message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="message">A message.</param>
void Verbose(Type reporting, string message);
/// <summary>
/// Logs a verbose message.
/// </summary>
/// <param name="reporting">The reporting type.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
void Verbose(Type reporting, string messageTemplate, params object[] propertyValues);
/// <param name="messageBuilder">A message builder.</param>
void Debug(Type reporting, Func<string> messageBuilder);
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace Umbraco.Core.Logging
{
/// <summary>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </summary>
/// <typeparam name="T"></typeparam>
internal interface IQueue<T>
{
void Enqueue(T item);
bool TryDequeue(out T ret);
}
}
@@ -2,9 +2,8 @@
using System.Runtime.CompilerServices;
using ImageProcessor.Common.Exceptions;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
namespace Umbraco.Web
namespace Umbraco.Core.Logging
{
/// <summary>
@@ -28,7 +27,7 @@ namespace Umbraco.Web
{
// Using LogHelper since the ImageProcessor logger expects a parameterless constructor.
var message = $"{callerName} {lineNumber} : {text}";
Current.Logger.Error<T>(new ImageProcessingException(message));
Current.Logger.Error<T>(string.Empty, new ImageProcessingException(message));
}
/// <summary>
@@ -42,7 +41,7 @@ namespace Umbraco.Web
{
// Using LogHelper since the ImageProcessor logger expects a parameterless constructor.
var message = $"{callerName} {lineNumber} : {text}";
Current.Logger.Error(type, new ImageProcessingException(message));
Current.Logger.Error(type, string.Empty, new ImageProcessingException(message));
}
}
}
@@ -1,32 +0,0 @@
using System;
using System.Web;
namespace Umbraco.Core.Logging
{
public static class LogHttpRequest
{
static readonly string RequestIdItemName = typeof(LogHttpRequest).Name + "+RequestId";
/// <summary>
/// Retrieve the id assigned to the currently-executing HTTP request, if any.
/// </summary>
/// <param name="requestId">The request id.</param>
/// <returns><c>true</c> if there is a request in progress; <c>false</c> otherwise.</returns>
public static bool TryGetCurrentHttpRequestId(out Guid requestId)
{
if (HttpContext.Current == null)
{
requestId = default(Guid);
return false;
}
var requestIdItem = HttpContext.Current.Items[RequestIdItemName];
if (requestIdItem == null)
HttpContext.Current.Items[RequestIdItemName] = requestId = Guid.NewGuid();
else
requestId = (Guid)requestIdItem;
return true;
}
}
}
-15
View File
@@ -1,15 +0,0 @@
namespace Umbraco.Core.Logging
{
/// <summary>
/// Specifies the level of a log event.
/// </summary>
public enum LogLevel
{
Verbose,
Debug,
Information,
Warning,
Error,
Fatal
}
}
+2 -2
View File
@@ -24,8 +24,8 @@ namespace Umbraco.Core.Logging
/// <inheritdoc/>
public IDisposable Step(string name)
{
_logger.Debug<LogProfiler>("Begin: {ProfileName}", name);
return new LightDisposableTimer(duration => _logger.Info<LogProfiler>("End {ProfileName} ({ProfileDuration}ms)", name, duration));
_logger.Debug<LogProfiler>(() => $"Begin: {name}.");
return new LightDisposableTimer(duration => _logger.Info<LogProfiler>(() => $"End {name}. ({duration}ms)"));
}
/// <inheritdoc/>
+244
View File
@@ -0,0 +1,244 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using log4net;
using log4net.Config;
using Umbraco.Core.Configuration;
using Umbraco.Core.Diagnostics;
using log4net.Util;
namespace Umbraco.Core.Logging
{
///<summary>
/// Implements <see cref="ILogger"/> on top of log4net.
///</summary>
public class Logger : ILogger
{
/// <summary>
/// Initialize a new instance of the <see cref="Logger"/> class with a log4net configuration file.
/// </summary>
/// <param name="log4NetConfigFile"></param>
public Logger(FileInfo log4NetConfigFile)
: this()
{
XmlConfigurator.Configure(log4NetConfigFile);
}
// private for CreateWithDefaultLog4NetConfiguration
private Logger()
{
// add custom global properties to the log4net context that we can use in our logging output
GlobalContext.Properties["processId"] = Process.GetCurrentProcess().Id;
GlobalContext.Properties["appDomainId"] = AppDomain.CurrentDomain.Id;
}
/// <summary>
/// Creates a logger with the default log4net configuration discovered (i.e. from the web.config).
/// </summary>
/// <remarks>Used by UmbracoApplicationBase to get its logger.</remarks>
public static Logger CreateWithDefaultLog4NetConfiguration()
{
return new Logger();
}
/// <inheritdoc/>
public void Error(Type reporting, string message, Exception exception = null)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null) return;
var dump = false;
if (IsTimeoutThreadAbortException(exception))
{
message += "\r\nThe thread has been aborted, because the request has timed out.";
// dump if configured, or if stacktrace contains Monitor.ReliableEnter
dump = UmbracoConfig.For.CoreDebug().DumpOnTimeoutThreadAbort || IsMonitorEnterThreadAbortException(exception);
// dump if it is ok to dump (might have a cap on number of dump...)
dump &= MiniDump.OkToDump();
}
if (dump)
{
try
{
var dumped = MiniDump.Dump(withException: true);
message += dumped
? "\r\nA minidump was created in App_Data/MiniDump"
: "\r\nFailed to create a minidump";
}
catch (Exception e)
{
message += string.Format("\r\nFailed to create a minidump ({0}: {1})", e.GetType().FullName, e.Message);
}
}
logger.Error(message, exception);
}
private static bool IsMonitorEnterThreadAbortException(Exception exception)
{
var abort = exception as ThreadAbortException;
if (abort == null) return false;
var stacktrace = abort.StackTrace;
return stacktrace.Contains("System.Threading.Monitor.ReliableEnter");
}
private static bool IsTimeoutThreadAbortException(Exception exception)
{
var abort = exception as ThreadAbortException;
if (abort == null) return false;
if (abort.ExceptionState == null) return false;
var stateType = abort.ExceptionState.GetType();
if (stateType.FullName != "System.Web.HttpApplication+CancelModuleException") return false;
var timeoutField = stateType.GetField("_timeout", BindingFlags.Instance | BindingFlags.NonPublic);
if (timeoutField == null) return false;
return (bool) timeoutField.GetValue(abort.ExceptionState);
}
/// <inheritdoc/>
public void Warn(Type reporting, string format)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.Warn(format);
}
/// <inheritdoc/>
public void Warn(Type reporting, Func<string> messageBuilder)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.Warn(messageBuilder());
}
/// <inheritdoc/>
public void Warn(Type reporting, string format, params object[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.WarnFormat(format, args);
}
/// <inheritdoc/>
public void Warn(Type reporting, string format, params Func<object>[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.WarnFormat(format, args.Select(x => x.Invoke()).ToArray());
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string message)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.Warn(message, exception);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, Func<string> messageBuilder)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
logger.Warn(messageBuilder(), exception);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string format, params object[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
// there is no WarnFormat overload that accepts an exception
// format the message the way log4net would do it (see source code LogImpl.cs)
var message = new SystemStringFormat(CultureInfo.InvariantCulture, format, args);
logger.Warn(message, exception);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string format, params Func<object>[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsWarnEnabled == false) return;
// there is no WarnFormat overload that accepts an exception
// format the message the way log4net would do it (see source code LogImpl.cs)
var message = new SystemStringFormat(CultureInfo.InvariantCulture, format, args.Select(x => x.Invoke()).ToArray());
logger.Warn(message, exception);
}
/// <inheritdoc/>
public void Info(Type reporting, string message)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsInfoEnabled == false) return;
logger.Info(message);
}
/// <inheritdoc/>
public void Info(Type reporting, Func<string> generateMessage)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsInfoEnabled == false) return;
logger.Info(generateMessage());
}
/// <inheritdoc/>
public void Info(Type reporting, string format, params object[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsInfoEnabled == false) return;
logger.InfoFormat(format, args);
}
/// <inheritdoc/>
public void Info(Type reporting, string format, params Func<object>[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsInfoEnabled == false) return;
logger.InfoFormat(format, args.Select(x => x.Invoke()).ToArray());
}
/// <inheritdoc/>
public void Debug(Type reporting, string message)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsDebugEnabled == false) return;
logger.Debug(message);
}
/// <inheritdoc/>
public void Debug(Type reporting, Func<string> messageBuilder)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsDebugEnabled == false) return;
logger.Debug(messageBuilder());
}
/// <inheritdoc/>
public void Debug(Type reporting, string format, params object[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsDebugEnabled == false) return;
logger.DebugFormat(format, args);
}
/// <inheritdoc/>
public void Debug(Type reporting, string format, params Func<object>[] args)
{
var logger = LogManager.GetLogger(reporting);
if (logger == null || logger.IsDebugEnabled == false) return;
logger.DebugFormat(format, args.Select(x => x.Invoke()).ToArray());
}
}
}
+48 -121
View File
@@ -1,4 +1,5 @@
using System;
using System.Linq;
namespace Umbraco.Core.Logging
{
@@ -7,63 +8,17 @@ namespace Umbraco.Core.Logging
/// </summary>
public static class LoggerExtensions
{
/// <summary>
/// Determines if logging is enabled at a specified level, for a reporting type.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="level">The level.</param>
public static bool IsEnabled<T>(this ILogger logger, LogLevel level)
=> logger.IsEnabled(typeof(T), level);
/// <summary>
/// Logs an error message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
/// <param name="exception">An exception.</param>
public static void Error<T>(this ILogger logger, Exception exception, string message)
=> logger.Error(typeof(T), exception, message);
/// <summary>
/// Logs an error message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Error<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
=> logger.Error(typeof(T), exception, messageTemplate, propertyValues);
/// <summary>
/// Logs an error exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
public static void Error<T>(this ILogger logger, Exception exception)
=> logger.Error(typeof(T), exception);
/// <summary>
/// Logs an error message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Error<T>(this ILogger logger, string message)
=> logger.Error(typeof(T), message);
/// <summary>
/// Logs an error message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Error<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
=> logger.Error(typeof(T), messageTemplate, propertyValues);
/// <param name="exception">An exception.</param>
public static void Error<T>(this ILogger logger, string message, Exception exception = null)
{
logger.Error(typeof(T), message, exception);
}
/// <summary>
/// Logs a warning message.
@@ -72,38 +27,44 @@ namespace Umbraco.Core.Logging
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Warn<T>(this ILogger logger, string message)
=> logger.Warn(typeof(T), message);
{
logger.Warn(typeof(T), message);
}
/// <summary>
/// Logs a warning message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Warn<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
=> logger.Warn(typeof(T), messageTemplate, propertyValues);
/// <param name="messageBuilder">A message builder.</param>
public static void Warn<T>(this ILogger logger, Func<string> messageBuilder)
{
logger.Warn(typeof(T), messageBuilder);
}
/// <summary>
/// Logs a warning message with an exception.
/// Logs a formatted warning message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageBuilder">A message builder.</param>
public static void Warn<T>(this ILogger logger, Exception exception, Func<string> messageBuilder)
{
logger.Warn(typeof(T), exception, messageBuilder);
}
/// <summary>
/// Logs a formatted warning message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
public static void Warn<T>(this ILogger logger, Exception exception, string message)
=> logger.Warn(typeof(T), exception, message);
/// <summary>
/// Logs a warning message with an exception.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Warn<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
=> logger.Warn(typeof(T), exception, messageTemplate, propertyValues);
{
logger.Warn(typeof(T), exception, message);
}
/// <summary>
/// Logs an information message.
@@ -112,17 +73,20 @@ namespace Umbraco.Core.Logging
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Info<T>(this ILogger logger, string message)
=> logger.Info(typeof(T), message);
{
logger.Info(typeof(T), message);
}
/// <summary>
/// Logs a information message.
/// Logs an information message.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Info<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
=> logger.Info(typeof(T), messageTemplate, propertyValues);
/// <param name="messageBuilder">A message builder.</param>
public static void Info<T>(this ILogger logger, Func<string> messageBuilder)
{
logger.Info(typeof(T), messageBuilder);
}
/// <summary>
/// Logs a debugging message.
@@ -131,56 +95,19 @@ namespace Umbraco.Core.Logging
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Debug<T>(this ILogger logger, string message)
=> logger.Debug(typeof(T), message);
{
logger.Debug(typeof(T), message);
}
/// <summary>
/// Logs a debugging message.
/// </summary>
/// <typeparam name="T">The reporting type</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Debug<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
=> logger.Debug(typeof(T), messageTemplate, propertyValues);
/// <summary>
/// Logs a verbose message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="message">A message.</param>
public static void Verbose<T>(this ILogger logger, string message)
=> logger.Verbose(typeof(T), message);
/// <summary>
/// Logs a verbose message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Verbose<T>(this ILogger logger, string messageTemplate, params object[] propertyValues)
=> logger.Verbose(typeof(T), messageTemplate, propertyValues);
/// <summary>
/// Logs a fatal message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="message">A message.</param>
public static void Fatal<T>(this ILogger logger, Exception exception, string message)
=> logger.Fatal(typeof(T), exception, message);
/// <summary>
/// Logs a fatal message.
/// </summary>
/// <typeparam name="T">The reporting type.</typeparam>
/// <param name="logger">The logger.</param>
/// <param name="exception">An exception.</param>
/// <param name="messageTemplate">A message template.</param>
/// <param name="propertyValues">Property values.</param>
public static void Fatal<T>(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues)
=> logger.Fatal(typeof(T), exception, messageTemplate, propertyValues);
/// <param name="messageBuilder">A message builder.</param>
public static void Debug<T>(this ILogger logger, Func<string> messageBuilder)
{
logger.Debug(typeof(T), messageBuilder);
}
}
}
@@ -0,0 +1,20 @@
using log4net.Core;
namespace Umbraco.Core.Logging
{
/// <remarks>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </remarks>
internal sealed class LoggingEventContext
{
public LoggingEventContext(LoggingEvent loggingEvent, object httpContext)
{
LoggingEvent = loggingEvent;
HttpContext = httpContext;
}
public LoggingEvent LoggingEvent { get; set; }
public object HttpContext { get; set; }
}
}
@@ -0,0 +1,33 @@
using System;
using log4net.Core;
namespace Umbraco.Core.Logging
{
/// <remarks>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </remarks>
internal sealed class LoggingEventHelper
{
// needs to be a seperate class so that location is determined correctly by log4net when required
private static readonly Type HelperType = typeof(LoggingEventHelper);
private readonly string loggerName;
public FixFlags Fix { get; set; }
public LoggingEventHelper(string loggerName, FixFlags fix)
{
this.loggerName = loggerName;
Fix = fix;
}
public LoggingEvent CreateLoggingEvent(Level level, string message, Exception exception)
{
var loggingEvent = new LoggingEvent(HelperType, null, loggerName, level, message, exception)
{
Fix = Fix
};
return loggingEvent;
}
}
}
@@ -1,35 +0,0 @@
using System;
using System.Linq;
using Serilog;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Provides tools to support message templates.
/// </summary>
public static class MessageTemplates
{
// Umbraco now uses Message Templates (https://messagetemplates.org/) for logging, which means
// we cannot plainly use string.Format() to format them. There is a work-in-progress C# lib,
// derived from Serilog, which should help (https://github.com/messagetemplates/messagetemplates-csharp)
// but it only has a pre-release NuGet package. So, we've got to use Serilog's code, which
// means we cannot get rid of Serilog entirely. We may want to revisit this at some point.
private static readonly Lazy<global::Serilog.ILogger> MinimalLogger = new Lazy<global::Serilog.ILogger>(() => new LoggerConfiguration().CreateLogger());
public static string Render(string messageTemplate, params object[] args)
{
// by default, unless initialized otherwise, Log.Logger is SilentLogger which cannot bind message
// templates. Log.Logger is set to a true Logger when initializing Umbraco's logger, but in case
// that has not been done already - use a temp minimal logger (eg for tests).
var logger = Log.Logger as global::Serilog.Core.Logger ?? MinimalLogger.Value;
var bound = logger.BindMessageTemplate(messageTemplate, args, out var parsedTemplate, out var boundProperties);
if (!bound)
throw new FormatException($"Could not format message \"{messageTemplate}\" with {args.Length} args.");
return parsedTemplate.Render(boundProperties.ToDictionary(x => x.Name, x => x.Value));
}
}
}
+10 -10
View File
@@ -26,34 +26,34 @@ namespace Umbraco.Core.Logging
switch (eventType)
{
case TraceEventType.Critical:
_logger.Fatal(_type.Value, exception, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Error(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state), exception ?? new Exception("Critical error"));
return true;
case TraceEventType.Error:
_logger.Error(_type.Value, exception, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Error(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state), exception ?? new Exception("Error"));
return true;
case TraceEventType.Warning:
_logger.Warn(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Warn(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
return true;
case TraceEventType.Information:
_logger.Info(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Info(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
return true;
case TraceEventType.Verbose:
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
return true;
case TraceEventType.Start:
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
return true;
case TraceEventType.Stop:
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
return true;
case TraceEventType.Suspend:
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
return true;
case TraceEventType.Resume:
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
return true;
case TraceEventType.Transfer:
_logger.Debug(_type.Value, "[{EventType}] Event Id: {EventId}, State: {State}", eventType, eventId, state);
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
return true;
default:
throw new ArgumentOutOfRangeException("eventType");
+9 -13
View File
@@ -13,8 +13,10 @@ namespace Umbraco.Core.Logging
public ProfilingLogger(ILogger logger, IProfiler profiler)
{
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
Profiler = profiler ?? throw new ArgumentNullException(nameof(profiler));
if (logger == null) throw new ArgumentNullException(nameof(logger));
if (profiler == null) throw new ArgumentNullException(nameof(profiler));
Logger = logger;
Profiler = profiler;
}
public DisposableTimer TraceDuration<T>(string startMessage)
@@ -24,33 +26,27 @@ namespace Umbraco.Core.Logging
public DisposableTimer TraceDuration<T>(string startMessage, string completeMessage, string failMessage = null)
{
return new DisposableTimer(Logger, LogLevel.Information, Profiler, typeof(T), startMessage, completeMessage, failMessage);
return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, typeof(T), startMessage, completeMessage, failMessage);
}
public DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage, string failMessage = null)
{
return new DisposableTimer(Logger, LogLevel.Information, Profiler, loggerType, startMessage, completeMessage, failMessage);
return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, loggerType, startMessage, completeMessage, failMessage);
}
public DisposableTimer DebugDuration<T>(string startMessage)
{
return Logger.IsEnabled<T>(LogLevel.Debug)
? DebugDuration<T>(startMessage, "Completed.")
: null;
return DebugDuration<T>(startMessage, "Completed.");
}
public DisposableTimer DebugDuration<T>(string startMessage, string completeMessage, string failMessage = null, int thresholdMilliseconds = 0)
{
return Logger.IsEnabled<T>(LogLevel.Debug)
? new DisposableTimer(Logger, LogLevel.Debug, Profiler, typeof(T), startMessage, completeMessage, failMessage, thresholdMilliseconds)
: null;
return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, typeof(T), startMessage, completeMessage, failMessage, thresholdMilliseconds);
}
public DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage, string failMessage = null, int thresholdMilliseconds = 0)
{
return Logger.IsEnabled(loggerType, LogLevel.Debug)
? new DisposableTimer(Logger, LogLevel.Debug, Profiler, loggerType, startMessage, completeMessage, failMessage, thresholdMilliseconds)
: null;
return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, loggerType, startMessage, completeMessage, failMessage, thresholdMilliseconds);
}
}
}
+78
View File
@@ -0,0 +1,78 @@
using System;
namespace Umbraco.Core.Logging
{
/// <summary>
/// Borrowed from https://github.com/cjbhaines/Log4Net.Async - will reference Nuget packages directly in v8
/// </summary>
/// <typeparam name="T"></typeparam>
internal sealed class RingBuffer<T> : IQueue<T>
{
private readonly object lockObject = new object();
private readonly T[] buffer;
private readonly int size;
private int readIndex = 0;
private int writeIndex = 0;
private bool bufferFull = false;
public int Size { get { return size; } }
public event Action<object, EventArgs> 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;
}
}
}
}
@@ -0,0 +1,95 @@
using System;
using System.IO;
using log4net.Appender;
using log4net.Util;
namespace Umbraco.Core.Logging
{
/// <summary>
/// This class will do the exact same thing as the RollingFileAppender that comes from log4net
/// With the extension, that it is able to do automatic cleanup of the logfiles in the directory where logging happens
///
/// By specifying the properties MaxLogFileDays and BaseFilePattern, the files will automaticly get deleted when
/// the logger is configured(typically when the app starts). To utilize this appender swap out the type of the rollingFile appender
/// that ships with Umbraco, to be Umbraco.Core.Logging.RollingFileCleanupAppender, and add the maxLogFileDays and baseFilePattern elements
/// to the configuration i.e.:
///
/// <example>
/// <appender name="rollingFile" type="Log4netAwesomeness.CustomRollingFileAppender, Log4netAwesomeness">
/// <file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
/// <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
/// <appendToFile value="true" />
/// <rollingStyle value="Date" />
/// <maximumFileSize value="5MB" />
/// <maxLogFileDays value="5"/>
/// <basefilePattern value="UmbracoTraceLog.*.txt.*"/>
/// <layout type="log4net.Layout.PatternLayout">
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
/// </layout>
/// <layout type="log4net.Layout.PatternLayout">
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
/// </layout>
/// <encoding value="utf-8" />
/// </appender>
/// </example>
/// </summary>
public class RollingFileCleanupAppender : RollingFileAppender
{
public int MaxLogFileDays { get; set; }
public string BaseFilePattern { get; set; }
/// <summary>
/// This override will delete logs older than the specified amount of days
/// </summary>
/// <param name="fileName"></param>
/// <param name="append"></param>
protected override void OpenFile(string fileName, bool append)
{
bool cleanup = true;
// Validate settings and input
if (MaxLogFileDays <= 0)
{
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'MaxLogFileDays' needs to be a positive integer, aborting cleanup");
cleanup = false;
}
if (string.IsNullOrWhiteSpace(BaseFilePattern))
{
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'BaseFilePattern' is empty, aborting cleanup");
cleanup = false;
}
// grab the directory we are logging to, as this is were we will search for older logfiles
var logFolder = Path.GetDirectoryName(fileName);
if (Directory.Exists(logFolder) == false)
{
LogLog.Warn(typeof(RollingFileCleanupAppender), string.Format("Directory '{0}' for logfiles does not exist, aborting cleanup", logFolder));
cleanup = false;
}
// If everything is validated, we can do the actual cleanup
if (cleanup)
{
Cleanup(logFolder);
}
base.OpenFile(fileName, append);
}
private void Cleanup(string directoryPath)
{
// only take files that matches the pattern we are using i.e. UmbracoTraceLog.*.txt.*
string[] logFiles = Directory.GetFiles(directoryPath, BaseFilePattern);
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Found {0} files that matches the baseFilePattern: '{1}'", logFiles.Length, BaseFilePattern));
foreach (var logFile in logFiles)
{
DateTime lastAccessTime = System.IO.File.GetLastWriteTimeUtc(logFile);
// take the value from the config file
if (lastAccessTime < DateTime.Now.AddDays(-MaxLogFileDays))
{
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Deleting file {0} as its lastAccessTime is older than {1} days speficied by MaxLogFileDays", logFile, MaxLogFileDays));
base.DeleteFile(logFile);
}
}
}
}
}
@@ -1,36 +0,0 @@
using System;
using Serilog.Core;
using Serilog.Events;
namespace Umbraco.Core.Logging.Serilog.Enrichers
{
/// <summary>
/// Enrich log events with a HttpRequestId GUID.
/// Original source - https://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/HttpRequestIdEnricher.cs
/// Nupkg: 'Serilog.Web.Classic' contains handlers & extra bits we do not want
/// </summary>
internal class HttpRequestIdEnricher : ILogEventEnricher
{
/// <summary>
/// The property name added to enriched log events.
/// </summary>
public const string HttpRequestIdPropertyName = "HttpRequestId";
/// <summary>
/// Enrich the log event with an id assigned to the currently-executing HTTP request, if any.
/// </summary>
/// <param name="logEvent">The log event to enrich.</param>
/// <param name="propertyFactory">Factory for creating new properties to add to the event.</param>
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
if (logEvent == null) throw new ArgumentNullException("logEvent");
Guid requestId;
if (!LogHttpRequest.TryGetCurrentHttpRequestId(out requestId))
return;
var requestIdProperty = new LogEventProperty(HttpRequestIdPropertyName, new ScalarValue(requestId));
logEvent.AddPropertyIfAbsent(requestIdProperty);
}
}
}
@@ -1,48 +0,0 @@
using System;
using System.Threading;
using System.Web;
using Serilog.Core;
using Serilog.Events;
namespace Umbraco.Core.Logging.Serilog.Enrichers
{
/// <summary>
/// Enrich log events with a HttpRequestNumber unique within the current
/// logging session.
/// Original source - https://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/HttpRequestNumberEnricher.cs
/// Nupkg: 'Serilog.Web.Classic' contains handlers & extra bits we do not want
/// </summary>
internal class HttpRequestNumberEnricher : ILogEventEnricher
{
/// <summary>
/// The property name added to enriched log events.
/// </summary>
public const string HttpRequestNumberPropertyName = "HttpRequestNumber";
static int _lastRequestNumber;
static readonly string RequestNumberItemName = typeof(HttpRequestNumberEnricher).Name + "+RequestNumber";
/// <summary>
/// Enrich the log event with the number assigned to the currently-executing HTTP request, if any.
/// </summary>
/// <param name="logEvent">The log event to enrich.</param>
/// <param name="propertyFactory">Factory for creating new properties to add to the event.</param>
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
if (logEvent == null) throw new ArgumentNullException("logEvent");
if (HttpContext.Current == null)
return;
int requestNumber;
var requestNumberItem = HttpContext.Current.Items[RequestNumberItemName];
if (requestNumberItem == null)
HttpContext.Current.Items[RequestNumberItemName] = requestNumber = Interlocked.Increment(ref _lastRequestNumber);
else
requestNumber = (int)requestNumberItem;
var requestNumberProperty = new LogEventProperty(HttpRequestNumberPropertyName, new ScalarValue(requestNumber));
logEvent.AddPropertyIfAbsent(requestNumberProperty);
}
}
}
@@ -1,39 +0,0 @@
using Serilog.Core;
using Serilog.Events;
using System;
using System.Web;
namespace Umbraco.Core.Logging.Serilog.Enrichers
{
/// <summary>
/// Enrich log events with the HttpSessionId property.
/// Original source - https://github.com/serilog-web/classic/blob/master/src/SerilogWeb.Classic/Classic/Enrichers/HttpSessionIdEnricher.cs
/// Nupkg: 'Serilog.Web.Classic' contains handlers & extra bits we do not want
/// </summary>
internal class HttpSessionIdEnricher : ILogEventEnricher
{
/// <summary>
/// The property name added to enriched log events.
/// </summary>
public const string HttpSessionIdPropertyName = "HttpSessionId";
/// <summary>
/// Enrich the log event with the current ASP.NET session id, if sessions are enabled.</summary>
/// <param name="logEvent">The log event to enrich.</param>
/// <param name="propertyFactory">Factory for creating new properties to add to the event.</param>
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
if (logEvent == null) throw new ArgumentNullException("logEvent");
if (HttpContext.Current == null)
return;
if (HttpContext.Current.Session == null)
return;
var sessionId = HttpContext.Current.Session.SessionID;
var sessionIdProperty = new LogEventProperty(HttpSessionIdPropertyName, new ScalarValue(sessionId));
logEvent.AddPropertyIfAbsent(sessionIdProperty);
}
}
}
@@ -1,49 +0,0 @@
using Serilog.Core;
using Serilog.Events;
namespace Umbraco.Core.Logging.Serilog.Enrichers
{
/// <summary>
/// This is used to create a new property in Logs called 'Log4NetLevel'
/// So that we can map Serilog levels to Log4Net levels - so log files stay consistent
/// </summary>
internal class Log4NetLevelMapperEnricher : ILogEventEnricher
{
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
var log4NetLevel = string.Empty;
switch (logEvent.Level)
{
case LogEventLevel.Debug:
log4NetLevel = "DEBUG";
break;
case LogEventLevel.Error:
log4NetLevel = "ERROR";
break;
case LogEventLevel.Fatal:
log4NetLevel = "FATAL";
break;
case LogEventLevel.Information:
log4NetLevel = "INFO";
break;
case LogEventLevel.Verbose:
log4NetLevel = "ALL";
break;
case LogEventLevel.Warning:
log4NetLevel = "WARN";
break;
}
//Pad string so that all log levels are 5 chars long (needed to keep the txt log file lined up nicely)
log4NetLevel = log4NetLevel.PadRight(5);
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("Log4NetLevel", log4NetLevel));
}
}
}
@@ -1,107 +0,0 @@
using System;
using System.Web;
using Serilog;
using Serilog.Events;
using Serilog.Formatting.Compact;
using Umbraco.Core.Logging.Serilog.Enrichers;
namespace Umbraco.Core.Logging.Serilog
{
public static class LoggerConfigExtensions
{
/// <summary>
/// This configures Serilog with some defaults
/// Such as adding ProcessID, Thread, AppDomain etc
/// It is highly recommended that you keep/use this default in your own logging config customizations
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
public static LoggerConfiguration MinimalConfiguration(this LoggerConfiguration logConfig)
{
global::Serilog.Debugging.SelfLog.Enable(msg => System.Diagnostics.Debug.WriteLine(msg));
//Set this environment variable - so that it can be used in external config file
//add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log.txt" />
Environment.SetEnvironmentVariable("BASEDIR", AppDomain.CurrentDomain.BaseDirectory, EnvironmentVariableTarget.Process);
logConfig.MinimumLevel.Verbose() //Set to highest level of logging (as any sinks may want to restrict it to Errors only)
.Enrich.WithProcessId()
.Enrich.WithProcessName()
.Enrich.WithThreadId()
.Enrich.WithProperty("AppDomainId", AppDomain.CurrentDomain.Id)
.Enrich.WithProperty("AppDomainAppId", HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty))
.Enrich.WithProperty("MachineName", Environment.MachineName)
.Enrich.With<Log4NetLevelMapperEnricher>()
.Enrich.With<HttpSessionIdEnricher>()
.Enrich.With<HttpRequestNumberEnricher>()
.Enrich.With<HttpRequestIdEnricher>();
return logConfig;
}
/// <summary>
/// Outputs a .txt format log at /App_Data/Logs/
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
/// <param name="minimumLevel">The log level you wish the JSON file to collect - default is Verbose (highest)</param>
/// <param name="retainedFileCount">The number of days to keep log files. Default is set to null which means all logs are kept</param>
public static LoggerConfiguration OutputDefaultTextFile(this LoggerConfiguration logConfig, LogEventLevel minimumLevel = LogEventLevel.Verbose, int? retainedFileCount = null)
{
//Main .txt logfile - in similar format to older Log4Net output
//Ends with ..txt as Date is inserted before file extension substring
logConfig.WriteTo.File($@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..txt",
shared: true,
rollingInterval: RollingInterval.Day,
restrictedToMinimumLevel: minimumLevel,
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}");
return logConfig;
}
/// <summary>
/// Outputs a CLEF format JSON log at /App_Data/Logs/
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
/// <param name="minimumLevel">The log level you wish the JSON file to collect - default is Verbose (highest)</param>
/// <param name="retainedFileCount">The number of days to keep log files. Default is set to null which means all logs are kept</param>
public static LoggerConfiguration OutputDefaultJsonFile(this LoggerConfiguration logConfig, LogEventLevel minimumLevel = LogEventLevel.Verbose, int? retainedFileCount = null)
{
//.clef format (Compact log event format, that can be imported into local SEQ & will make searching/filtering logs easier)
//Ends with ..txt as Date is inserted before file extension substring
logConfig.WriteTo.File(new CompactJsonFormatter(), $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..json",
shared: true,
rollingInterval: RollingInterval.Day, //Create a new JSON file every day
retainedFileCountLimit: retainedFileCount, //Setting to null means we keep all files - default is 31 days
restrictedToMinimumLevel: minimumLevel);
return logConfig;
}
/// <summary>
/// Reads settings from /config/serilog.config
/// That allows the main logging pipeline to be configured
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
public static LoggerConfiguration ReadFromConfigFile(this LoggerConfiguration logConfig)
{
//Read from main serilog.config file
logConfig.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + @"\config\serilog.config");
return logConfig;
}
/// <summary>
/// Reads settings from /config/serilog.user.config
/// That allows a seperate logging pipeline to be configured that wil not affect the main Umbraco log
/// </summary>
/// <param name="logConfig">A Serilog LoggerConfiguration</param>
public static LoggerConfiguration ReadFromUserConfigFile(this LoggerConfiguration logConfig)
{
//A nested logger - where any user configured sinks via config can not effect the main 'umbraco' logger above
logConfig.WriteTo.Logger(cfg =>
cfg.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + @"\config\serilog.user.config"));
return logConfig;
}
}
}
@@ -1,277 +0,0 @@
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using Serilog;
using Serilog.Events;
using Umbraco.Core.Configuration;
using Umbraco.Core.Diagnostics;
namespace Umbraco.Core.Logging.Serilog
{
///<summary>
/// Implements <see cref="ILogger"/> on top of Serilog.
///</summary>
public class SerilogLogger : ILogger
{
/// <summary>
/// Initialize a new instance of the <see cref="SerilogLogger"/> class with a configuration file.
/// </summary>
/// <param name="logConfigFile"></param>
public SerilogLogger(FileInfo logConfigFile)
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.AppSettings(filePath: AppDomain.CurrentDomain.BaseDirectory + logConfigFile)
.CreateLogger();
}
public SerilogLogger(LoggerConfiguration logConfig)
{
//Configure Serilog static global logger with config passed in
Log.Logger = logConfig.CreateLogger();
}
/// <summary>
/// Creates a logger with some pre-defined configuration and remainder from config file
/// </summary>
/// <remarks>Used by UmbracoApplicationBase to get its logger.</remarks>
public static SerilogLogger CreateWithDefaultConfiguration()
{
var loggerConfig = new LoggerConfiguration();
loggerConfig
.MinimalConfiguration()
.OutputDefaultTextFile(LogEventLevel.Debug)
.OutputDefaultJsonFile()
.ReadFromConfigFile()
.ReadFromUserConfigFile();
return new SerilogLogger(loggerConfig);
}
/// <summary>
/// Gets a contextualized logger.
/// </summary>
private global::Serilog.ILogger LoggerFor(Type reporting)
=> Log.Logger.ForContext(reporting);
/// <summary>
/// Maps Umbraco's log level to Serilog's.
/// </summary>
private LogEventLevel MapLevel(LogLevel level)
{
switch (level)
{
case LogLevel.Debug:
return LogEventLevel.Debug;
case LogLevel.Error:
return LogEventLevel.Error;
case LogLevel.Fatal:
return LogEventLevel.Fatal;
case LogLevel.Information:
return LogEventLevel.Information;
case LogLevel.Verbose:
return LogEventLevel.Verbose;
case LogLevel.Warning:
return LogEventLevel.Warning;
}
throw new NotSupportedException($"LogLevel \"{level}\" is not supported.");
}
/// <inheritdoc/>
public bool IsEnabled(Type reporting, LogLevel level)
=> LoggerFor(reporting).IsEnabled(MapLevel(level));
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception, string message)
{
var logger = LoggerFor(reporting);
DumpThreadAborts(logger, LogEventLevel.Fatal, exception, ref message);
logger.Fatal(exception, message);
}
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception)
{
var logger = LoggerFor(reporting);
var message = "Exception.";
DumpThreadAborts(logger, LogEventLevel.Fatal, exception, ref message);
logger.Fatal(exception, message);
}
/// <inheritdoc/>
public void Fatal(Type reporting, string message)
{
LoggerFor(reporting).Fatal(message);
}
/// <inheritdoc/>
public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues)
{
LoggerFor(reporting).Fatal(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
var logger = LoggerFor(reporting);
DumpThreadAborts(logger, LogEventLevel.Fatal, exception, ref messageTemplate);
logger.Fatal(exception, messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string message)
{
var logger = LoggerFor(reporting);
DumpThreadAborts(logger, LogEventLevel.Error, exception, ref message);
logger.Error(exception, message);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception)
{
var logger = LoggerFor(reporting);
var message = "Exception";
DumpThreadAborts(logger, LogEventLevel.Error, exception, ref message);
logger.Error(exception, message);
}
/// <inheritdoc/>
public void Error(Type reporting, string message)
{
LoggerFor(reporting).Error(message);
}
/// <inheritdoc/>
public void Error(Type reporting, string messageTemplate, params object[] propertyValues)
{
LoggerFor(reporting).Error(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
var logger = LoggerFor(reporting);
DumpThreadAborts(logger, LogEventLevel.Error, exception, ref messageTemplate);
logger.Error(exception, messageTemplate, propertyValues);
}
private static void DumpThreadAborts(global::Serilog.ILogger logger, LogEventLevel level, Exception exception, ref string messageTemplate)
{
var dump = false;
if (IsTimeoutThreadAbortException(exception))
{
messageTemplate += "\r\nThe thread has been aborted, because the request has timed out.";
// dump if configured, or if stacktrace contains Monitor.ReliableEnter
dump = UmbracoConfig.For.CoreDebug().DumpOnTimeoutThreadAbort || IsMonitorEnterThreadAbortException(exception);
// dump if it is ok to dump (might have a cap on number of dump...)
dump &= MiniDump.OkToDump();
}
if (dump)
{
try
{
var dumped = MiniDump.Dump(withException: true);
messageTemplate += dumped
? "\r\nA minidump was created in App_Data/MiniDump"
: "\r\nFailed to create a minidump";
}
catch (Exception ex)
{
messageTemplate += "\r\nFailed to create a minidump";
//Log a new entry (as opposed to appending to same log entry)
logger.Write(level, ex, "Failed to create a minidump ({ExType}: {ExMessage})",
new object[]{ ex.GetType().FullName, ex.Message });
}
}
}
private static bool IsMonitorEnterThreadAbortException(Exception exception)
{
if (!(exception is ThreadAbortException abort)) return false;
var stacktrace = abort.StackTrace;
return stacktrace.Contains("System.Threading.Monitor.ReliableEnter");
}
private static bool IsTimeoutThreadAbortException(Exception exception)
{
if (!(exception is ThreadAbortException abort)) return false;
if (abort.ExceptionState == null) return false;
var stateType = abort.ExceptionState.GetType();
if (stateType.FullName != "System.Web.HttpApplication+CancelModuleException") return false;
var timeoutField = stateType.GetField("_timeout", BindingFlags.Instance | BindingFlags.NonPublic);
if (timeoutField == null) return false;
return (bool) timeoutField.GetValue(abort.ExceptionState);
}
/// <inheritdoc/>
public void Warn(Type reporting, string message)
{
LoggerFor(reporting).Warning(message);
}
/// <inheritdoc/>
public void Warn(Type reporting, string message, params object[] propertyValues)
{
LoggerFor(reporting).Warning(message, propertyValues);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string message)
{
LoggerFor(reporting).Warning(exception, message);
}
/// <inheritdoc/>
public void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues)
{
LoggerFor(reporting).Warning(exception, messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Info(Type reporting, string message)
{
LoggerFor(reporting).Information(message);
}
/// <inheritdoc/>
public void Info(Type reporting, string messageTemplate, params object[] propertyValues)
{
LoggerFor(reporting).Information(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Debug(Type reporting, string message)
{
LoggerFor(reporting).Debug(message);
}
/// <inheritdoc/>
public void Debug(Type reporting, string messageTemplate, params object[] propertyValues)
{
LoggerFor(reporting).Debug(messageTemplate, propertyValues);
}
/// <inheritdoc/>
public void Verbose(Type reporting, string message)
{
LoggerFor(reporting).Verbose(message);
}
/// <inheritdoc/>
public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues)
{
LoggerFor(reporting).Verbose(messageTemplate, propertyValues);
}
}
}
@@ -5,7 +5,7 @@ using System.Text.RegularExpressions;
using HtmlAgilityPack;
using Umbraco.Core.Xml;
namespace Umbraco.Web.Macros
namespace Umbraco.Core.Macros
{
/// <summary>
/// Parses the macro syntax in a string and renders out it's contents
+5 -5
View File
@@ -117,7 +117,7 @@ namespace Umbraco.Core
lock (_locko)
{
_logger.Debug<MainDom>("Signaled {Signaled} ({SignalSource})", _signaled ? "(again)" : string.Empty, source);
_logger.Debug<MainDom>(() => "Signaled" + (_signaled ? " (again)" : "") + " (" + source + ").");
if (_signaled) return;
if (_isMainDom == false) return; // probably not needed
_signaled = true;
@@ -125,7 +125,7 @@ namespace Umbraco.Core
try
{
_logger.Info<MainDom>("Stopping ({SignalSource})", source);
_logger.Info<MainDom>("Stopping.");
foreach (var callback in _callbacks.OrderBy(x => x.Key).Select(x => x.Value))
{
try
@@ -134,19 +134,19 @@ namespace Umbraco.Core
}
catch (Exception e)
{
_logger.Error<MainDom>(e, "Error while running callback, remaining callbacks will not run.");
_logger.Error<MainDom>("Error while running callback, remaining callbacks will not run.", e);
throw;
}
}
_logger.Debug<MainDom>("Stopped ({SignalSource})", source);
_logger.Debug<MainDom>("Stopped.");
}
finally
{
// in any case...
_isMainDom = false;
_asyncLocker.Dispose();
_logger.Info<MainDom>("Released ({SignalSource})", source);
_logger.Info<MainDom>("Released.");
}
}

Some files were not shown because too many files have changed in this diff Show More