diff --git a/src/Umbraco.Core/Services/MasterPageHelper.cs b/src/Umbraco.Core/IO/MasterPageHelper.cs similarity index 99% rename from src/Umbraco.Core/Services/MasterPageHelper.cs rename to src/Umbraco.Core/IO/MasterPageHelper.cs index 652887d212..8ddb8491d4 100644 --- a/src/Umbraco.Core/Services/MasterPageHelper.cs +++ b/src/Umbraco.Core/IO/MasterPageHelper.cs @@ -1,14 +1,13 @@ using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; -using Umbraco.Core.IO; using Umbraco.Core.Models; +using Umbraco.Core.Services; -namespace Umbraco.Core.Services +namespace Umbraco.Core.IO { internal class MasterPageHelper { diff --git a/src/Umbraco.Core/Services/ViewHelper.cs b/src/Umbraco.Core/IO/ViewHelper.cs similarity index 98% rename from src/Umbraco.Core/Services/ViewHelper.cs rename to src/Umbraco.Core/IO/ViewHelper.cs index 879a6bd6c3..9592664e2d 100644 --- a/src/Umbraco.Core/Services/ViewHelper.cs +++ b/src/Umbraco.Core/IO/ViewHelper.cs @@ -1,10 +1,9 @@ using System; using System.IO; using System.Text; -using Umbraco.Core.IO; using Umbraco.Core.Models; -namespace Umbraco.Core.Services +namespace Umbraco.Core.IO { internal class ViewHelper { diff --git a/src/Umbraco.Core/Models/File.cs b/src/Umbraco.Core/Models/File.cs index d337b82bbe..bcc4a58adb 100644 --- a/src/Umbraco.Core/Models/File.cs +++ b/src/Umbraco.Core/Models/File.cs @@ -32,14 +32,7 @@ namespace Umbraco.Core.Models [DataMember] public virtual string Name { - get - { - if (_name == null) - { - _name = System.IO.Path.GetFileName(Path); - } - return _name; - } + get { return _name ?? (_name = System.IO.Path.GetFileName(Path)); } } /// diff --git a/src/Umbraco.Core/Models/Template.cs b/src/Umbraco.Core/Models/Template.cs index 9cfc9c2367..0a820b255d 100644 --- a/src/Umbraco.Core/Models/Template.cs +++ b/src/Umbraco.Core/Models/Template.cs @@ -25,6 +25,8 @@ namespace Umbraco.Core.Models private static readonly PropertyInfo MasterTemplateAliasSelector = ExpressionHelper.GetPropertyInfo(x => x.MasterTemplateAlias); private static readonly PropertyInfo MasterTemplateIdSelector = ExpressionHelper.GetPropertyInfo>(x => x.MasterTemplateId); + private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); + private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); public Template(string name, string alias) : base(string.Empty) @@ -79,28 +81,44 @@ namespace Umbraco.Core.Models } [DataMember] - string ITemplate.Name + public new string Name { get { return _name; } - set { _name = value; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _name = value; + return _name; + }, _name, NameSelector); + + } } [DataMember] - string ITemplate.Alias + public new string Alias { get { return _alias; } - set { _alias = value; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _alias = value.ToCleanString(CleanStringType.UnderscoreAlias); + return _alias; + }, _alias, AliasSelector); + + } } - public override string Alias - { - get { return ((ITemplate)this).Alias; } - } + //public override string Alias + //{ + // get { return ((ITemplate)this).Alias; } + //} - public override string Name - { - get { return ((ITemplate)this).Name; } - } + //public override string Name + //{ + // get { return ((ITemplate)this).Name; } + //} /// diff --git a/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs b/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs index 281c271fe8..7ad95f6879 100644 --- a/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Rdbms; @@ -10,15 +11,19 @@ namespace Umbraco.Core.Persistence.Factories { internal class TemplateFactory { + private readonly IFileSystem _viewFileSystem; private readonly int _primaryKey; private readonly Guid _nodeObjectTypeId; - public TemplateFactory() - {} + public TemplateFactory(IFileSystem viewFileSystem) + { + _viewFileSystem = viewFileSystem; + } - public TemplateFactory(Guid nodeObjectTypeId) + public TemplateFactory(Guid nodeObjectTypeId, IFileSystem viewFileSystem) { _nodeObjectTypeId = nodeObjectTypeId; + _viewFileSystem = viewFileSystem; } public TemplateFactory(int primaryKey, Guid nodeObjectTypeId) @@ -31,7 +36,7 @@ namespace Umbraco.Core.Persistence.Factories public Template BuildEntity(TemplateDto dto, IEnumerable childDefinitions) { - var template = new Template(string.Empty, dto.NodeDto.Text, dto.Alias) + var template = new Template(dto.NodeDto.Text, dto.Alias, _viewFileSystem) { CreateDate = dto.NodeDto.CreateDate, Id = dto.NodeId, diff --git a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs index 7189572c2e..55d6c9dbb2 100644 --- a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs @@ -4,6 +4,8 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; @@ -13,6 +15,8 @@ using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; using Umbraco.Core.Sync; namespace Umbraco.Core.Persistence.Repositories @@ -24,6 +28,7 @@ namespace Umbraco.Core.Persistence.Repositories { private IFileSystem _masterpagesFileSystem; private IFileSystem _viewsFileSystem; + private ITemplatesSection _templateConfig; public TemplateRepository(IDatabaseUnitOfWork work) : base(work) @@ -37,17 +42,19 @@ namespace Umbraco.Core.Persistence.Repositories EnsureDependencies(); } - internal TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem) + internal TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem, ITemplatesSection templateConfig) : base(work, cache) { _masterpagesFileSystem = masterpageFileSystem; _viewsFileSystem = viewFileSystem; + _templateConfig = templateConfig; } private void EnsureDependencies() { _masterpagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages); _viewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews); + _templateConfig = UmbracoConfig.For.UmbracoSettings().Templates; } #region Overrides of RepositoryBase @@ -169,15 +176,29 @@ namespace Umbraco.Core.Persistence.Repositories } } - //TODO ensure unique alias here (as is done in the legacy Template class)! - //TODO: The legacy one also checked for length, so do that too! - //TODO: Integrate the ViewHelper, MasterPageHelper stuff for when saving the template content + EnsureValidAlias(entity); + + + if (entity.Content.IsNullOrWhiteSpace()) + { + //set default content + switch (_templateConfig.DefaultRenderingEngine) + { + case RenderingEngine.Unknown: + case RenderingEngine.Mvc: + entity.Content = ViewHelper.GetDefaultFileContent(); + break; + case RenderingEngine.WebForms: + //TODO: Fill this in + break; + } + } //Save to db var template = (Template)entity; template.AddingEntity(); - var factory = new TemplateFactory(NodeObjectTypeId); + var factory = new TemplateFactory(NodeObjectTypeId, _viewsFileSystem); var dto = factory.BuildDto(template); //NOTE: There is no reason for sort order, path or level with templates, also the ParentId column is NOT used, need to fix: @@ -215,6 +236,8 @@ namespace Umbraco.Core.Persistence.Repositories protected override void PersistUpdatedItem(ITemplate entity) { + EnsureValidAlias(entity); + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(entity.Content))) { if (entity.GetTypeOfRenderingEngine() == RenderingEngine.Mvc) @@ -229,6 +252,22 @@ namespace Umbraco.Core.Persistence.Repositories } } + if (entity.IsPropertyDirty("Alias")) + { + //we need to check what it currently is before saving and remove that file + var current = Get(entity.Id); + if (current.GetTypeOfRenderingEngine() == RenderingEngine.Mvc) + { + string viewName = string.Concat(current.Alias, ".cshtml"); + _viewsFileSystem.DeleteFile(viewName); + } + else + { + string masterpageName = string.Concat(current.Alias, ".master"); + _masterpagesFileSystem.DeleteFile(masterpageName); + } + } + //NOTE: There is no reason for sort order, path or level with templates, also the ParentId column is NOT used, need to fix: // http://issues.umbraco.org/issue/U4-5846 ////Look up parent to get and set the correct Path if ParentId has changed @@ -247,7 +286,7 @@ namespace Umbraco.Core.Persistence.Repositories //Get TemplateDto from db to get the Primary key of the entity var templateDto = Database.SingleOrDefault("WHERE nodeId = @Id", new { Id = entity.Id }); //Save updated entity to db - var template = entity as Template; + var template = (Template)entity; template.UpdateDate = DateTime.Now; var factory = new TemplateFactory(templateDto.PrimaryKey, NodeObjectTypeId); var dto = factory.BuildDto(template); @@ -309,7 +348,7 @@ namespace Umbraco.Core.Persistence.Repositories string vbViewName = string.Concat(dto.Alias, ".vbhtml"); string masterpageName = string.Concat(dto.Alias, ".master"); - var factory = new TemplateFactory(); + var factory = new TemplateFactory(_viewsFileSystem); var template = factory.BuildEntity(dto, childDefinitions); if (dto.Master.HasValue) @@ -575,5 +614,39 @@ namespace Umbraco.Core.Persistence.Repositories } #endregion + + /// + /// Ensures that there are not duplicate aliases and if so, changes it to be a numbered version and also verifies the length + /// + /// + private void EnsureValidAlias(ITemplate template) + { + //ensure unique alias + template.Alias = template.Alias.ToCleanString(CleanStringType.UnderscoreAlias); + + if (template.Alias.Length > 100) + template.Alias = template.Alias.Substring(0, 95); + + if (AliasAlreadExists(template)) + { + template.Alias = EnsureUniqueAlias(template, 1); + } + } + + private bool AliasAlreadExists(ITemplate template) + { + var sql = GetBaseQuery(true).Where(x => x.Alias == template.Alias && x.NodeId != template.Id); + var count = Database.ExecuteScalar(sql); + return count > 0; + } + + private string EnsureUniqueAlias(ITemplate template, int attempts) + { + //TODO: This is ported from the old data layer... pretty crap way of doing this but it works for now. + if (AliasAlreadExists(template)) + return template.Alias + attempts; + attempts++; + return EnsureUniqueAlias(template, attempts); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 32b035d02a..0416c7e8f3 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1070,7 +1070,7 @@ - + @@ -1087,7 +1087,7 @@ - + diff --git a/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs index a7951bfc69..262fb93b0a 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/TemplateRepositoryTest.cs @@ -2,8 +2,10 @@ using System.IO; using System.Linq; using System.Text; +using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Persistence; @@ -57,7 +59,8 @@ namespace Umbraco.Tests.Persistence.Repositories var unitOfWork = provider.GetUnitOfWork(); // Act - using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) { // Assert @@ -72,7 +75,8 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(); var unitOfWork = provider.GetUnitOfWork(); - using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) { // Act var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" }; @@ -92,7 +96,8 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(); var unitOfWork = provider.GetUnitOfWork(); - using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) { // Act var template = new Template("test", "test") { Content = ViewHelper.GetDefaultFileContent() }; @@ -106,25 +111,59 @@ namespace Umbraco.Tests.Persistence.Repositories } - //[Test] - //public void Can_Perform_Add_Unique_Alias() - //{ - // // Arrange - // var provider = new PetaPocoUnitOfWorkProvider(); - // var unitOfWork = provider.GetUnitOfWork(); - // using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) - // { - // // Act - // var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" }; - // repository.AddOrUpdate(template); - // unitOfWork.Commit(); + [Test] + public void Can_Perform_Add_Unique_Alias() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) + { + // Act + var template = new Template("test", "test") { Content = ViewHelper.GetDefaultFileContent() }; + repository.AddOrUpdate(template); + unitOfWork.Commit(); - // //Assert - // Assert.That(repository.Get("test"), Is.Not.Null); - // Assert.That(_masterPageFileSystem.FileExists("test.master"), Is.True); - // } + var template2 = new Template("test", "test") { Content = ViewHelper.GetDefaultFileContent() }; + repository.AddOrUpdate(template2); + unitOfWork.Commit(); - //} + //Assert + Assert.AreEqual("test1", template2.Alias); + } + + } + + [Test] + public void Can_Perform_Update_Unique_Alias() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) + { + // Act + var template = new Template("test", "test") { Content = ViewHelper.GetDefaultFileContent() }; + repository.AddOrUpdate(template); + unitOfWork.Commit(); + + var template2 = new Template("test1", "test1") { Content = ViewHelper.GetDefaultFileContent() }; + repository.AddOrUpdate(template2); + unitOfWork.Commit(); + + template.Alias = "test1"; + repository.AddOrUpdate(template); + unitOfWork.Commit(); + + //Assert + Assert.AreEqual("test11", template.Alias); + Assert.That(_viewsFileSystem.FileExists("test11.cshtml"), Is.True); + Assert.That(_viewsFileSystem.FileExists("test.cshtml"), Is.False); + } + + } [Test] public void Can_Perform_Update_MasterPage() @@ -132,7 +171,8 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(); var unitOfWork = provider.GetUnitOfWork(); - using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) { // Act var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" }; @@ -154,12 +194,41 @@ namespace Umbraco.Tests.Persistence.Repositories } [Test] - public void Can_Perform_Delete() + public void Can_Perform_Update_View() { // Arrange var provider = new PetaPocoUnitOfWorkProvider(); var unitOfWork = provider.GetUnitOfWork(); - using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) + { + // Act + var template = new Template("test", "test") { Content = ViewHelper.GetDefaultFileContent() }; + repository.AddOrUpdate(template); + unitOfWork.Commit(); + + template.Content += ""; + repository.AddOrUpdate(template); + unitOfWork.Commit(); + + var updated = repository.Get("test"); + + // Assert + Assert.That(_viewsFileSystem.FileExists("test.cshtml"), Is.True); + Assert.That(updated.Content, Is.EqualTo(ViewHelper.GetDefaultFileContent() + "")); + } + + + } + + [Test] + public void Can_Perform_Delete_MasterPage() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) { var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" }; repository.AddOrUpdate(template); @@ -177,6 +246,33 @@ namespace Umbraco.Tests.Persistence.Repositories } + } + + [Test] + public void Can_Perform_Delete_View() + { + // Arrange + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) + { + var template = new Template("test", "test", _viewsFileSystem) { Content = ViewHelper.GetDefaultFileContent() }; + repository.AddOrUpdate(template); + unitOfWork.Commit(); + + // Act + var templates = repository.Get("test"); + Assert.That(_viewsFileSystem.FileExists("test.cshtml"), Is.True); + repository.Delete(templates); + unitOfWork.Commit(); + + // Assert + Assert.IsNull(repository.Get("test")); + Assert.That(_viewsFileSystem.FileExists("test.cshtml"), Is.False); + } + + } [Test] @@ -199,7 +295,8 @@ namespace Umbraco.Tests.Persistence.Repositories contentRepo.AddOrUpdate(textpage); unitOfWork.Commit(); - using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) { var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" }; repository.AddOrUpdate(template); @@ -227,7 +324,8 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(); var unitOfWork = provider.GetUnitOfWork(); - using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) { var parent = new Template("parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" }; var child = new Template("child", "child") { Content = @"<%@ Master Language=""C#"" %>" }; @@ -259,7 +357,8 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var provider = new PetaPocoUnitOfWorkProvider(); var unitOfWork = provider.GetUnitOfWork(); - using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem)) + using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem, + Mock.Of(t => t.DefaultRenderingEngine == RenderingEngine.Mvc))) { var parent = new Template("parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" }; diff --git a/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs b/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs index 292948713a..6da4fbc07e 100644 --- a/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs +++ b/src/Umbraco.Tests/Templates/MasterPageHelperTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using NUnit.Framework; using umbraco.cms.businesslogic.template; +using Umbraco.Core.IO; using Umbraco.Core.Services; namespace Umbraco.Tests.Templates diff --git a/src/umbraco.cms/businesslogic/template/Template.cs b/src/umbraco.cms/businesslogic/template/Template.cs index 5da266d39b..1999ba8989 100644 --- a/src/umbraco.cms/businesslogic/template/Template.cs +++ b/src/umbraco.cms/businesslogic/template/Template.cs @@ -561,7 +561,7 @@ namespace umbraco.cms.businesslogic.template public List contentPlaceholderIds() { - return Umbraco.Core.Services.MasterPageHelper.GetContentPlaceholderIds(TemplateEntity).ToList(); + return MasterPageHelper.GetContentPlaceholderIds(TemplateEntity).ToList(); }