From 5801ba4b8140aaae93ff3a69117a19a6409e2c6e Mon Sep 17 00:00:00 2001 From: Matthew Care Date: Thu, 7 Oct 2021 21:05:43 +0100 Subject: [PATCH 1/8] Add Default View Content Provider Add the ability to register your own content provider, so that you can change the content which is injeted into new templates Obsolete old static method Register new interfaces / classes (hopefully in the correct buidler) --- .../IO/DefaultViewContentProvider.cs | 62 +++++++++++++++ .../IO/IDefaultViewContentProvider.cs | 8 ++ src/Umbraco.Core/IO/IViewHelper.cs | 13 ++++ src/Umbraco.Core/IO/ViewHelper.cs | 76 ++++--------------- .../UmbracoBuilder.FileSystems.cs | 3 + .../Implement/TemplateRepository.cs | 6 +- .../Controllers/TemplateController.cs | 7 +- .../ModelsBuilderNotificationHandler.cs | 6 +- 8 files changed, 113 insertions(+), 68 deletions(-) create mode 100644 src/Umbraco.Core/IO/DefaultViewContentProvider.cs create mode 100644 src/Umbraco.Core/IO/IDefaultViewContentProvider.cs create mode 100644 src/Umbraco.Core/IO/IViewHelper.cs diff --git a/src/Umbraco.Core/IO/DefaultViewContentProvider.cs b/src/Umbraco.Core/IO/DefaultViewContentProvider.cs new file mode 100644 index 000000000000..7c4225597150 --- /dev/null +++ b/src/Umbraco.Core/IO/DefaultViewContentProvider.cs @@ -0,0 +1,62 @@ +using System.Text; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Core.IO +{ + public class DefaultViewContentProvider : IDefaultViewContentProvider + { + public string GetDefaultFileContent(string layoutPageAlias = null, string modelClassName = null, string modelNamespace = null, string modelNamespaceAlias = null) + { + var content = new StringBuilder(); + + if (string.IsNullOrWhiteSpace(modelNamespaceAlias)) + modelNamespaceAlias = "ContentModels"; + + // either + // @inherits Umbraco.Web.Mvc.UmbracoViewPage + // @inherits Umbraco.Web.Mvc.UmbracoViewPage + content.AppendLine("@using Umbraco.Cms.Web.Common.PublishedModels;"); + content.Append("@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage"); + if (modelClassName.IsNullOrWhiteSpace() == false) + { + content.Append("<"); + if (modelNamespace.IsNullOrWhiteSpace() == false) + { + content.Append(modelNamespaceAlias); + content.Append("."); + } + content.Append(modelClassName); + content.Append(">"); + } + content.Append("\r\n"); + + // if required, add + // @using ContentModels = ModelNamespace; + if (modelClassName.IsNullOrWhiteSpace() == false && modelNamespace.IsNullOrWhiteSpace() == false) + { + content.Append("@using "); + content.Append(modelNamespaceAlias); + content.Append(" = "); + content.Append(modelNamespace); + content.Append(";\r\n"); + } + + // either + // Layout = null; + // Layout = "layoutPage.cshtml"; + content.Append("@{\r\n\tLayout = "); + if (layoutPageAlias.IsNullOrWhiteSpace()) + { + content.Append("null"); + } + else + { + content.Append("\""); + content.Append(layoutPageAlias); + content.Append(".cshtml\""); + } + content.Append(";\r\n}"); + return content.ToString(); + } + } +} diff --git a/src/Umbraco.Core/IO/IDefaultViewContentProvider.cs b/src/Umbraco.Core/IO/IDefaultViewContentProvider.cs new file mode 100644 index 000000000000..8c1a775d7ce8 --- /dev/null +++ b/src/Umbraco.Core/IO/IDefaultViewContentProvider.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Core.IO +{ + public interface IDefaultViewContentProvider + { + string GetDefaultFileContent(string layoutPageAlias = null, string modelClassName = null, + string modelNamespace = null, string modelNamespaceAlias = null); + } +} diff --git a/src/Umbraco.Core/IO/IViewHelper.cs b/src/Umbraco.Core/IO/IViewHelper.cs new file mode 100644 index 000000000000..d53dcbf2b939 --- /dev/null +++ b/src/Umbraco.Core/IO/IViewHelper.cs @@ -0,0 +1,13 @@ +using Umbraco.Cms.Core.Models; + +namespace Umbraco.Cms.Core.IO +{ + public interface IViewHelper + { + bool ViewExists(ITemplate t); + string GetFileContents(ITemplate t); + string CreateView(ITemplate t, bool overWrite = false); + string UpdateViewFile(ITemplate t, string currentAlias = null); + string ViewPath(string alias); + } +} diff --git a/src/Umbraco.Core/IO/ViewHelper.cs b/src/Umbraco.Core/IO/ViewHelper.cs index 258c4a7f640d..11d40e486216 100644 --- a/src/Umbraco.Core/IO/ViewHelper.cs +++ b/src/Umbraco.Core/IO/ViewHelper.cs @@ -7,20 +7,19 @@ namespace Umbraco.Cms.Core.IO { - public class ViewHelper + public class ViewHelper : IViewHelper { private readonly IFileSystem _viewFileSystem; + private readonly IDefaultViewContentProvider _defaultViewContentProvider; - public ViewHelper(IFileSystem viewFileSystem) + public ViewHelper(FileSystems fileSystems, IDefaultViewContentProvider defaultViewContentProvider) { - if (viewFileSystem == null) throw new ArgumentNullException(nameof(viewFileSystem)); - _viewFileSystem = viewFileSystem; + _viewFileSystem = fileSystems.MvcViewsFileSystem ?? throw new ArgumentNullException(nameof(fileSystems)); + _defaultViewContentProvider = defaultViewContentProvider ?? throw new ArgumentNullException(nameof(defaultViewContentProvider)); } - internal bool ViewExists(ITemplate t) - { - return _viewFileSystem.FileExists(ViewPath(t.Alias)); - } + public bool ViewExists(ITemplate t) => _viewFileSystem.FileExists(ViewPath(t.Alias)); + public string GetFileContents(ITemplate t) { @@ -60,58 +59,13 @@ public string CreateView(ITemplate t, bool overWrite = false) return viewContent; } - public static string GetDefaultFileContent(string layoutPageAlias = null, string modelClassName = null, string modelNamespace = null, string modelNamespaceAlias = null) + [Obsolete("Inject IDefaultViewContentProvider instead")] + public static string GetDefaultFileContent(string layoutPageAlias = null, string modelClassName = null, + string modelNamespace = null, string modelNamespaceAlias = null) { - var content = new StringBuilder(); - - if (string.IsNullOrWhiteSpace(modelNamespaceAlias)) - modelNamespaceAlias = "ContentModels"; - - // either - // @inherits Umbraco.Web.Mvc.UmbracoViewPage - // @inherits Umbraco.Web.Mvc.UmbracoViewPage - content.AppendLine("@using Umbraco.Cms.Web.Common.PublishedModels;"); - content.Append("@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage"); - if (modelClassName.IsNullOrWhiteSpace() == false) - { - content.Append("<"); - if (modelNamespace.IsNullOrWhiteSpace() == false) - { - content.Append(modelNamespaceAlias); - content.Append("."); - } - content.Append(modelClassName); - content.Append(">"); - } - content.Append("\r\n"); - - // if required, add - // @using ContentModels = ModelNamespace; - if (modelClassName.IsNullOrWhiteSpace() == false && modelNamespace.IsNullOrWhiteSpace() == false) - { - content.Append("@using "); - content.Append(modelNamespaceAlias); - content.Append(" = "); - content.Append(modelNamespace); - content.Append(";\r\n"); - } - - // either - // Layout = null; - // Layout = "layoutPage.cshtml"; - content.Append("@{\r\n\tLayout = "); - if (layoutPageAlias.IsNullOrWhiteSpace()) - { - content.Append("null"); - } - else - { - content.Append("\""); - content.Append(layoutPageAlias); - content.Append(".cshtml\""); - } - content.Append(";\r\n}"); - return content.ToString(); + var viewContentProvider = new DefaultViewContentProvider(); + return viewContentProvider.GetDefaultFileContent(layoutPageAlias, modelClassName, modelNamespace, + modelNamespaceAlias); } private string SaveTemplateToFile(ITemplate template) @@ -157,12 +111,12 @@ public string ViewPath(string alias) return _viewFileSystem.GetRelativePath(alias.Replace(" ", "") + ".cshtml"); } - private static string EnsureInheritedLayout(ITemplate template) + private string EnsureInheritedLayout(ITemplate template) { var design = template.Content; if (string.IsNullOrEmpty(design)) - design = GetDefaultFileContent(template.MasterTemplateAlias); + design = _defaultViewContentProvider.GetDefaultFileContent(template.MasterTemplateAlias); return design; } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs index edb8033f3dc4..6582cfb0c6e6 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.FileSystems.cs @@ -39,6 +39,9 @@ internal static IUmbracoBuilder AddFileSystems(this IUmbracoBuilder builder) // register the scheme for media paths builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.Services.AddUnique(); + builder.SetMediaFileSystem(factory => { IIOHelper ioHelper = factory.GetRequiredService(); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs index b0cabe53128d..52ecd1f7791e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs @@ -29,15 +29,15 @@ internal class TemplateRepository : EntityRepositoryBase, ITempl private readonly IIOHelper _ioHelper; private readonly IShortStringHelper _shortStringHelper; private readonly IFileSystem _viewsFileSystem; - private readonly ViewHelper _viewHelper; + private readonly IViewHelper _viewHelper; - public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, FileSystems fileSystems, IIOHelper ioHelper, IShortStringHelper shortStringHelper) + public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, FileSystems fileSystems, IIOHelper ioHelper, IShortStringHelper shortStringHelper, IViewHelper viewHelper) : base(scopeAccessor, cache, logger) { _ioHelper = ioHelper; _shortStringHelper = shortStringHelper; _viewsFileSystem = fileSystems.MvcViewsFileSystem; - _viewHelper = new ViewHelper(_viewsFileSystem); + _viewHelper = viewHelper; } protected override IRepositoryCachePolicy CreateCachePolicy() => diff --git a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs index 0a800693f80c..a5b33b5d042b 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs @@ -24,15 +24,18 @@ public class TemplateController : BackOfficeNotificationsController private readonly IFileService _fileService; private readonly IUmbracoMapper _umbracoMapper; private readonly IShortStringHelper _shortStringHelper; + private readonly IDefaultViewContentProvider _defaultViewContentProvider; public TemplateController( IFileService fileService, IUmbracoMapper umbracoMapper, - IShortStringHelper shortStringHelper) + IShortStringHelper shortStringHelper, + IDefaultViewContentProvider defaultViewContentProvider) { _fileService = fileService ?? throw new ArgumentNullException(nameof(fileService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); + _defaultViewContentProvider = defaultViewContentProvider ?? throw new ArgumentNullException(nameof(defaultViewContentProvider)); } /// @@ -136,7 +139,7 @@ public TemplateDisplay GetScaffold(int id) } } - var content = ViewHelper.GetDefaultFileContent( layoutPageAlias: dt.MasterTemplateAlias ); + var content = _defaultViewContentProvider.GetDefaultFileContent( layoutPageAlias: dt.MasterTemplateAlias ); var scaffold = _umbracoMapper.Map(dt); scaffold.Content = content + "\r\n\r\n@* the fun starts here *@\r\n\r\n"; diff --git a/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs b/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs index 90a48c401768..ea8408b21200 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs @@ -26,15 +26,17 @@ internal class ModelsBuilderNotificationHandler : private readonly ModelsBuilderSettings _config; private readonly IShortStringHelper _shortStringHelper; private readonly IModelsBuilderDashboardProvider _modelsBuilderDashboardProvider; + private readonly IDefaultViewContentProvider _defaultViewContentProvider; public ModelsBuilderNotificationHandler( IOptions config, IShortStringHelper shortStringHelper, - IModelsBuilderDashboardProvider modelsBuilderDashboardProvider) + IModelsBuilderDashboardProvider modelsBuilderDashboardProvider, IDefaultViewContentProvider defaultViewContentProvider) { _config = config.Value; _shortStringHelper = shortStringHelper; _modelsBuilderDashboardProvider = modelsBuilderDashboardProvider; + _defaultViewContentProvider = defaultViewContentProvider; } /// @@ -123,7 +125,7 @@ public void Handle(TemplateSavingNotification notification) // we do not support configuring this at the moment, so just let Umbraco use its default value // var modelNamespaceAlias = ...; - var markup = ViewHelper.GetDefaultFileContent( + var markup = _defaultViewContentProvider.GetDefaultFileContent( modelClassName: className, modelNamespace: modelNamespace/*, modelNamespaceAlias: modelNamespaceAlias*/); From dc536b011bec0caba05c2535690f5eae6c805261 Mon Sep 17 00:00:00 2001 From: Matthew Care Date: Thu, 7 Oct 2021 21:06:39 +0100 Subject: [PATCH 2/8] Add Umbraco Builder unique Follow the convention of having a method on IUmbracoBuilder which allows you to set a custom content provider --- .../DependencyInjection/UmbracoBuilder.Uniques.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs index b311b1f0dacc..e3839e152b9a 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Uniques.cs @@ -27,6 +27,19 @@ public static IUmbracoBuilder SetCultureDictionaryFactory(this IUmbracoBuilde return builder; } + /// + /// Sets the default view content provider + /// + /// The type of the provider. + /// The builder. + /// + public static IUmbracoBuilder SetDefaultViewContentProvider(this IUmbracoBuilder builder) + where T : class, IDefaultViewContentProvider + { + builder.Services.AddUnique(); + return builder; + } + /// /// Sets the culture dictionary factory. /// From 44c25cd016fffc1f8b42b438ec835f7f52ef4f1b Mon Sep 17 00:00:00 2001 From: Matthew Care Date: Thu, 7 Oct 2021 21:08:35 +0100 Subject: [PATCH 3/8] Update tests Fix all of the unit / integration tests Update integration tests to remove references to ViewHelper, to make the tests more focused on what they should be testing --- .../Repositories/ContentTypeRepositoryTest.cs | 3 ++- .../Repositories/DocumentRepositoryTest.cs | 2 +- .../Repositories/TemplateRepositoryTest.cs | 25 +++++++++---------- ....cs => DefaultViewContentProviderTests.cs} | 18 +++++++------ 4 files changed, 25 insertions(+), 23 deletions(-) rename src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/{ViewHelperTests.cs => DefaultViewContentProviderTests.cs} (71%) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs index dfe799e2b819..de1a5d3fb5c8 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; +using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.IO; @@ -73,7 +74,7 @@ public void Maps_Templates_Correctly() IScopeProvider provider = ScopeProvider; using (IScope scope = provider.CreateScope()) { - var templateRepo = new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper); + var templateRepo = new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper, Mock.Of()); ContentTypeRepository repository = ContentTypeRepository; Template[] templates = new[] { diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs index a7e164183935..7207718071fb 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs @@ -114,7 +114,7 @@ private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out Co appCaches ??= AppCaches; - templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper); + templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper, Mock.Of()); var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper); var languageRepository = new LanguageRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), globalSettings); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs index d137ef8d055b..80eb61d21f91 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs @@ -38,10 +38,11 @@ public class TemplateRepositoryTest : UmbracoIntegrationTest private IHostingEnvironment HostingEnvironment => GetRequiredService(); private FileSystems FileSystems => GetRequiredService(); + private IViewHelper ViewHelper => GetRequiredService(); private ITemplateRepository CreateRepository(IScopeProvider provider) => - new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper); - + new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper, ViewHelper); + [Test] public void Can_Instantiate_Repository() { @@ -90,16 +91,14 @@ public void Can_Perform_Add_View_With_Default_Content() // Act var template = new Template(ShortStringHelper, "test", "test") { - Content = ViewHelper.GetDefaultFileContent() + Content = "mock-content" }; repository.Save(template); // Assert Assert.That(repository.Get("test"), Is.Not.Null); Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); - Assert.AreEqual( - @"@usingUmbraco.Cms.Web.Common.PublishedModels;@inheritsUmbraco.Cms.Web.Common.Views.UmbracoViewPage@{Layout=null;}".StripWhitespace(), - template.Content.StripWhitespace()); + Assert.AreEqual("mock-content", template.Content.StripWhitespace()); } } @@ -144,13 +143,13 @@ public void Can_Perform_Add_Unique_Alias() // Act var template = new Template(ShortStringHelper, "test", "test") { - Content = ViewHelper.GetDefaultFileContent() + Content = "mock-content" }; repository.Save(template); var template2 = new Template(ShortStringHelper, "test", "test") { - Content = ViewHelper.GetDefaultFileContent() + Content = "mock-content" }; repository.Save(template2); @@ -172,13 +171,13 @@ public void Can_Perform_Update_Unique_Alias() // Act var template = new Template(ShortStringHelper, "test", "test") { - Content = ViewHelper.GetDefaultFileContent() + Content = "mock-content" }; repository.Save(template); var template2 = new Template(ShortStringHelper, "test1", "test1") { - Content = ViewHelper.GetDefaultFileContent() + Content = "mock-content" }; repository.Save(template2); @@ -205,7 +204,7 @@ public void Can_Perform_Update_View() // Act var template = new Template(ShortStringHelper, "test", "test") { - Content = ViewHelper.GetDefaultFileContent() + Content = "mock-content" }; repository.Save(template); @@ -216,7 +215,7 @@ public void Can_Perform_Update_View() // Assert Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); - Assert.That(updated.Content, Is.EqualTo(ViewHelper.GetDefaultFileContent() + "")); + Assert.That(updated.Content, Is.EqualTo("mock-content" + "")); } } @@ -232,7 +231,7 @@ public void Can_Perform_Delete_View() var template = new Template(ShortStringHelper, "test", "test") { - Content = ViewHelper.GetDefaultFileContent() + Content = "mock-content" }; repository.Save(template); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/DefaultViewContentProviderTests.cs similarity index 71% rename from src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/DefaultViewContentProviderTests.cs index 446659467b6a..d43d88f001ad 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/DefaultViewContentProviderTests.cs @@ -7,12 +7,14 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Templates { [TestFixture] - public class ViewHelperTests + public class DefaultViewContentProviderTests { + private IDefaultViewContentProvider DefaultViewContentProvider => new DefaultViewContentProvider(); + [Test] public void NoOptions() { - var view = ViewHelper.GetDefaultFileContent(); + var view = DefaultViewContentProvider.GetDefaultFileContent(); Assert.AreEqual( FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels; @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage @@ -24,7 +26,7 @@ @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage [Test] public void Layout() { - var view = ViewHelper.GetDefaultFileContent(layoutPageAlias: "Dharznoik"); + var view = DefaultViewContentProvider.GetDefaultFileContent(layoutPageAlias: "Dharznoik"); Assert.AreEqual( FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels; @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage @@ -36,7 +38,7 @@ @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage [Test] public void ClassName() { - var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName"); + var view = DefaultViewContentProvider.GetDefaultFileContent(modelClassName: "ClassName"); Assert.AreEqual( FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels; @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage @@ -48,7 +50,7 @@ @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage [Test] public void Namespace() { - var view = ViewHelper.GetDefaultFileContent(modelNamespace: "Models"); + var view = DefaultViewContentProvider.GetDefaultFileContent(modelNamespace: "Models"); Assert.AreEqual( FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels; @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage @@ -60,7 +62,7 @@ @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage [Test] public void ClassNameAndNamespace() { - var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models"); + var view = DefaultViewContentProvider.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models"); Assert.AreEqual( FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels; @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage @@ -73,7 +75,7 @@ @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage [Test] public void ClassNameAndNamespaceAndAlias() { - var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels"); + var view = DefaultViewContentProvider.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels"); Assert.AreEqual( FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels; @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage @@ -86,7 +88,7 @@ @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage [Test] public void Combined() { - var view = ViewHelper.GetDefaultFileContent(layoutPageAlias: "Dharznoik", modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels"); + var view = DefaultViewContentProvider.GetDefaultFileContent(layoutPageAlias: "Dharznoik", modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels"); Assert.AreEqual( FixView(@"@using Umbraco.Cms.Web.Common.PublishedModels; @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage From 8dfec54b2ae0f6d02d913ac54d36642cbb7f11d0 Mon Sep 17 00:00:00 2001 From: Matthew Care Date: Thu, 7 Oct 2021 21:09:14 +0100 Subject: [PATCH 4/8] Remove string Remove a string that gets appended to the default file content. --- src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs index a5b33b5d042b..46a770428e8d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs @@ -142,7 +142,7 @@ public TemplateDisplay GetScaffold(int id) var content = _defaultViewContentProvider.GetDefaultFileContent( layoutPageAlias: dt.MasterTemplateAlias ); var scaffold = _umbracoMapper.Map(dt); - scaffold.Content = content + "\r\n\r\n@* the fun starts here *@\r\n\r\n"; + scaffold.Content = content; return scaffold; } From 4456bf4a3bedcef0fe7a804d707c2a4df2ecece9 Mon Sep 17 00:00:00 2001 From: Matthew Care Date: Fri, 8 Oct 2021 11:33:39 +0100 Subject: [PATCH 5/8] Re-add original ctor Add original ctor in case someone was using it, else this would be a breaking change --- src/Umbraco.Core/IO/ViewHelper.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Umbraco.Core/IO/ViewHelper.cs b/src/Umbraco.Core/IO/ViewHelper.cs index 11d40e486216..80ff48a94343 100644 --- a/src/Umbraco.Core/IO/ViewHelper.cs +++ b/src/Umbraco.Core/IO/ViewHelper.cs @@ -12,6 +12,9 @@ public class ViewHelper : IViewHelper private readonly IFileSystem _viewFileSystem; private readonly IDefaultViewContentProvider _defaultViewContentProvider; + [Obsolete("Inject IViewHelper instead")] + public ViewHelper(IFileSystem viewFileSystem) => _viewFileSystem = viewFileSystem ?? throw new ArgumentNullException(nameof(viewFileSystem)); + public ViewHelper(FileSystems fileSystems, IDefaultViewContentProvider defaultViewContentProvider) { _viewFileSystem = fileSystems.MvcViewsFileSystem ?? throw new ArgumentNullException(nameof(fileSystems)); From 576bc1f60b7f03191b088e27fabe5a5e55652c94 Mon Sep 17 00:00:00 2001 From: Matthew Care Date: Mon, 25 Oct 2021 14:30:58 +0100 Subject: [PATCH 6/8] Make requested changes Prevent breaking change by creating a new ctor Update obsolete message --- src/Umbraco.Core/IO/ViewHelper.cs | 2 +- .../Controllers/TemplateController.cs | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/IO/ViewHelper.cs b/src/Umbraco.Core/IO/ViewHelper.cs index 80ff48a94343..16c880b3c1c1 100644 --- a/src/Umbraco.Core/IO/ViewHelper.cs +++ b/src/Umbraco.Core/IO/ViewHelper.cs @@ -12,7 +12,7 @@ public class ViewHelper : IViewHelper private readonly IFileSystem _viewFileSystem; private readonly IDefaultViewContentProvider _defaultViewContentProvider; - [Obsolete("Inject IViewHelper instead")] + [Obsolete("Use ctor with all params")] public ViewHelper(IFileSystem viewFileSystem) => _viewFileSystem = viewFileSystem ?? throw new ArgumentNullException(nameof(viewFileSystem)); public ViewHelper(FileSystems fileSystems, IDefaultViewContentProvider defaultViewContentProvider) diff --git a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs index 46a770428e8d..8cef90cb575a 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Mapping; @@ -12,6 +13,7 @@ using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; +using Umbraco.Cms.Web.Common.DependencyInjection; using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Cms.Web.BackOffice.Controllers @@ -38,6 +40,15 @@ public TemplateController( _defaultViewContentProvider = defaultViewContentProvider ?? throw new ArgumentNullException(nameof(defaultViewContentProvider)); } + [Obsolete("Use ctor will all params")] + public TemplateController( + IFileService fileService, + IUmbracoMapper umbracoMapper, + IShortStringHelper shortStringHelper) + : this(fileService, umbracoMapper, shortStringHelper, StaticServiceProvider.Instance.GetRequiredService()) + { + } + /// /// Gets data type by alias /// From cca526aa584bc8c0f01019e3f464692b8449ab0f Mon Sep 17 00:00:00 2001 From: Matthew Care Date: Tue, 26 Oct 2021 10:51:15 +0100 Subject: [PATCH 7/8] Use static service provider Use the static service provider in the obsolete ctor --- src/Umbraco.Core/IO/ViewHelper.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/IO/ViewHelper.cs b/src/Umbraco.Core/IO/ViewHelper.cs index 16c880b3c1c1..56a276080227 100644 --- a/src/Umbraco.Core/IO/ViewHelper.cs +++ b/src/Umbraco.Core/IO/ViewHelper.cs @@ -2,7 +2,9 @@ using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.IO @@ -13,7 +15,11 @@ public class ViewHelper : IViewHelper private readonly IDefaultViewContentProvider _defaultViewContentProvider; [Obsolete("Use ctor with all params")] - public ViewHelper(IFileSystem viewFileSystem) => _viewFileSystem = viewFileSystem ?? throw new ArgumentNullException(nameof(viewFileSystem)); + public ViewHelper(IFileSystem viewFileSystem) + { + _viewFileSystem = viewFileSystem ?? throw new ArgumentNullException(nameof(viewFileSystem)); + _defaultViewContentProvider = StaticServiceProvider.Instance.GetRequiredService(); + } public ViewHelper(FileSystems fileSystems, IDefaultViewContentProvider defaultViewContentProvider) { @@ -66,7 +72,7 @@ public string CreateView(ITemplate t, bool overWrite = false) public static string GetDefaultFileContent(string layoutPageAlias = null, string modelClassName = null, string modelNamespace = null, string modelNamespaceAlias = null) { - var viewContentProvider = new DefaultViewContentProvider(); + var viewContentProvider = StaticServiceProvider.Instance.GetRequiredService(); return viewContentProvider.GetDefaultFileContent(layoutPageAlias, modelClassName, modelNamespace, modelNamespaceAlias); } From ded1c0b79f12fafeaa726a148ecf794dae7d62d3 Mon Sep 17 00:00:00 2001 From: Matthew Care Date: Tue, 26 Oct 2021 13:57:53 +0100 Subject: [PATCH 8/8] Fix DI Integration tests failing due to multiple ctors. Marking correct one for DI usage --- src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs index 8cef90cb575a..23c955219aee 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TemplateController.cs @@ -28,6 +28,7 @@ public class TemplateController : BackOfficeNotificationsController private readonly IShortStringHelper _shortStringHelper; private readonly IDefaultViewContentProvider _defaultViewContentProvider; + [ActivatorUtilitiesConstructor] public TemplateController( IFileService fileService, IUmbracoMapper umbracoMapper,