diff --git a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs index 0a0dbe37dd..2ea6d79d43 100644 --- a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs @@ -682,14 +682,16 @@ namespace Umbraco.Core.Persistence.Repositories public RenderingEngine DetermineTemplateRenderingEngine(ITemplate template) { var engine = _templateConfig.DefaultRenderingEngine; - - if (template.Content.IsNullOrWhiteSpace() == false && MasterPageHelper.IsMasterPageSyntax(template.Content)) + var viewHelper = new ViewHelper(_viewsFileSystem); + if (!viewHelper.ViewExists(template)) { - //there is a design but its definitely a webforms design - return RenderingEngine.WebForms; + if (template.Content.IsNullOrWhiteSpace() == false && MasterPageHelper.IsMasterPageSyntax(template.Content)) + { + //there is a design but its definitely a webforms design and we haven't got a MVC view already for it + return RenderingEngine.WebForms; + } } - var viewHelper = new ViewHelper(_viewsFileSystem); var masterPageHelper = new MasterPageHelper(_masterpagesFileSystem); switch (engine) diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs index 1d60879f97..9541a1cac0 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs @@ -117,7 +117,7 @@ namespace Umbraco.Core.Persistence public override void OnException(Exception x) { - _logger.Info(x.StackTrace); + _logger.Error("Database exception occurred", x); base.OnException(x); } diff --git a/src/Umbraco.Core/ThreadExtensions.cs b/src/Umbraco.Core/ThreadExtensions.cs new file mode 100644 index 0000000000..68f6959e91 --- /dev/null +++ b/src/Umbraco.Core/ThreadExtensions.cs @@ -0,0 +1,51 @@ +using System.Globalization; +using System.Threading; + +namespace Umbraco.Core +{ + static class ThreadExtensions + { + public static void SanitizeThreadCulture(this Thread thread) + { + // get the current culture + var currentCulture = CultureInfo.CurrentCulture; + + // at the top of any culture should be the invariant culture - find it + // doing an .Equals comparison ensure that we *will* find it and not loop + // endlessly + var invariantCulture = currentCulture; + while (invariantCulture.Equals(CultureInfo.InvariantCulture) == false) + invariantCulture = invariantCulture.Parent; + + // now that invariant culture should be the same object as CultureInfo.InvariantCulture + // yet for some reasons, sometimes it is not - and this breaks anything that loops on + // culture.Parent until a reference equality to CultureInfo.InvariantCulture. See, for + // example, the following code in PerformanceCounterLib.IsCustomCategory: + // + // CultureInfo culture = CultureInfo.CurrentCulture; + // while (culture != CultureInfo.InvariantCulture) + // { + // library = GetPerformanceCounterLib(machine, culture); + // if (library.IsCustomCategory(category)) + // return true; + // culture = culture.Parent; + // } + // + // The reference comparisons never succeeds, hence the loop never ends, and the + // application hangs. + // + // granted, that comparison should probably be a .Equals comparison, but who knows + // how many times the framework assumes that it can do a reference comparison? So, + // better fix the cultures. + + if (ReferenceEquals(invariantCulture, CultureInfo.InvariantCulture)) + return; + + // if we do not have equality, fix cultures by replacing them with a culture with + // the same name, but obtained here and now, with a proper invariant top culture + + thread.CurrentCulture = CultureInfo.GetCultureInfo(thread.CurrentCulture.Name); + thread.CurrentUICulture = CultureInfo.GetCultureInfo(thread.CurrentUICulture.Name); + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d3d3cc7b51..3e053e841c 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1290,6 +1290,7 @@ + diff --git a/src/Umbraco.Core/UmbracoApplicationBase.cs b/src/Umbraco.Core/UmbracoApplicationBase.cs index 6aadbd269a..225493b57b 100644 --- a/src/Umbraco.Core/UmbracoApplicationBase.cs +++ b/src/Umbraco.Core/UmbracoApplicationBase.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using System.Threading; using System.Web; using System.Web.Hosting; using log4net; @@ -64,6 +65,7 @@ namespace Umbraco.Core /// protected void Application_Start(object sender, EventArgs e) { + Thread.CurrentThread.SanitizeThreadCulture(); StartApplication(sender, e); } diff --git a/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs b/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs new file mode 100644 index 0000000000..c385799411 --- /dev/null +++ b/src/Umbraco.Tests/Templates/TemplateRepositoryTests.cs @@ -0,0 +1,109 @@ +using Moq; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Persistence.UnitOfWork; + +namespace Umbraco.Tests.Templates +{ + [TestFixture] + public class TemplateRepositoryTests + { + private readonly Mock _unitOfWorkMock = new Mock(); + private readonly Mock _cacheMock = new Mock(); + private TemplateRepository _templateRepository; + private readonly Mock _viewFileSystemMock = new Mock(); + private readonly Mock _masterpageFileSystemMock = new Mock(); + private readonly Mock _templateConfigMock = new Mock(); + + [SetUp] + public void Setup() + { + var loggerMock = new Mock(); + var sqlSyntaxMock = new Mock(); + _templateRepository = new TemplateRepository(_unitOfWorkMock.Object, _cacheMock.Object, loggerMock.Object, sqlSyntaxMock.Object, _masterpageFileSystemMock.Object, _viewFileSystemMock.Object, _templateConfigMock.Object); + + } + + [Test] + public void DetermineTemplateRenderingEngine_Returns_MVC_When_ViewFile_Exists_And_Content_Has_Webform_Markup() + { + // Project in MVC mode + _templateConfigMock.Setup(x => x.DefaultRenderingEngine).Returns(RenderingEngine.Mvc); + + // Template has masterpage content + var templateMock = new Mock(); + templateMock.Setup(x => x.Alias).Returns("Something"); + templateMock.Setup(x => x.Content).Returns(""); + + // but MVC View already exists + _viewFileSystemMock.Setup(x => x.FileExists(It.IsAny())).Returns(true); + + var res = _templateRepository.DetermineTemplateRenderingEngine(templateMock.Object); + Assert.AreEqual(RenderingEngine.Mvc, res); + } + + [Test] + public void DetermineTemplateRenderingEngine_Returns_WebForms_When_ViewFile_Doesnt_Exist_And_Content_Has_Webform_Markup() + { + // Project in MVC mode + _templateConfigMock.Setup(x => x.DefaultRenderingEngine).Returns(RenderingEngine.Mvc); + + // Template has masterpage content + var templateMock = new Mock(); + templateMock.Setup(x => x.Alias).Returns("Something"); + templateMock.Setup(x => x.Content).Returns(""); + + // MVC View doesn't exist + _viewFileSystemMock.Setup(x => x.FileExists(It.IsAny())).Returns(false); + + var res = _templateRepository.DetermineTemplateRenderingEngine(templateMock.Object); + Assert.AreEqual(RenderingEngine.WebForms, res); + } + + [Test] + public void DetermineTemplateRenderingEngine_Returns_WebForms_When_MasterPage_Exists_And_In_Mvc_Mode() + { + // Project in MVC mode + _templateConfigMock.Setup(x => x.DefaultRenderingEngine).Returns(RenderingEngine.Mvc); + + var templateMock = new Mock(); + templateMock.Setup(x => x.Alias).Returns("Something"); + + // but masterpage already exists + _viewFileSystemMock.Setup(x => x.FileExists(It.IsAny())).Returns(false); + _masterpageFileSystemMock.Setup(x => x.FileExists(It.IsAny())).Returns(true); + + var res = _templateRepository.DetermineTemplateRenderingEngine(templateMock.Object); + Assert.AreEqual(RenderingEngine.WebForms, res); + } + + [Test] + public void DetermineTemplateRenderingEngine_Returns_Mvc_When_ViewPage_Exists_And_In_Webforms_Mode() + { + // Project in WebForms mode + _templateConfigMock.Setup(x => x.DefaultRenderingEngine).Returns(RenderingEngine.WebForms); + + var templateMock = new Mock(); + templateMock.Setup(x => x.Alias).Returns("Something"); + + // but MVC View already exists + _viewFileSystemMock.Setup(x => x.FileExists(It.IsAny())).Returns(true); + _masterpageFileSystemMock.Setup(x => x.FileExists(It.IsAny())).Returns(false); + + var res = _templateRepository.DetermineTemplateRenderingEngine(templateMock.Object); + Assert.AreEqual(RenderingEngine.Mvc, res); + } + + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 9674971d3d..ef142d0d52 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -362,6 +362,7 @@ + diff --git a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs index 37d7a190f7..3f0a9f2a97 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs @@ -70,7 +70,7 @@ namespace Umbraco.Web.Scheduling try { - var result = await wc.SendAsync(request, token); + var result = await wc.SendAsync(request, token).ConfigureAwait(false); // ConfigureAwait(false) is recommended? http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html return result.StatusCode == HttpStatusCode.OK; } catch (Exception ex) diff --git a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs index 862bdf99ba..d535bc4f8a 100644 --- a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs +++ b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs @@ -195,46 +195,7 @@ namespace Umbraco.Web.Security.Identity public static void SanitizeThreadCulture(this IAppBuilder app) { - // get the current culture - var currentCulture = CultureInfo.CurrentCulture; - - // at the top of any culture should be the invariant culture - find it - // doing an .Equals comparison ensure that we *will* find it and not loop - // endlessly - var invariantCulture = currentCulture; - while (invariantCulture.Equals(CultureInfo.InvariantCulture) == false) - invariantCulture = invariantCulture.Parent; - - // now that invariant culture should be the same object as CultureInfo.InvariantCulture - // yet for some reasons, sometimes it is not - and this breaks anything that loops on - // culture.Parent until a reference equality to CultureInfo.InvariantCulture. See, for - // example, the following code in PerformanceCounterLib.IsCustomCategory: - // - // CultureInfo culture = CultureInfo.CurrentCulture; - // while (culture != CultureInfo.InvariantCulture) - // { - // library = GetPerformanceCounterLib(machine, culture); - // if (library.IsCustomCategory(category)) - // return true; - // culture = culture.Parent; - // } - // - // The reference comparisons never succeeds, hence the loop never ends, and the - // application hangs. - // - // granted, that comparison should probably be a .Equals comparison, but who knows - // how many times the framework assumes that it can do a reference comparison? So, - // better fix the cultures. - - if (ReferenceEquals(invariantCulture, CultureInfo.InvariantCulture)) - return; - - // if we do not have equality, fix cultures by replacing them with a culture with - // the same name, but obtained here and now, with a proper invariant top culture - - var thread = Thread.CurrentThread; - thread.CurrentCulture = CultureInfo.GetCultureInfo(thread.CurrentCulture.Name); - thread.CurrentUICulture = CultureInfo.GetCultureInfo(thread.CurrentUICulture.Name); + Thread.CurrentThread.SanitizeThreadCulture(); } } } \ No newline at end of file