-
Notifications
You must be signed in to change notification settings - Fork 78
Fix: Cannot create templates during sync when running in production mode (Umbraco 17.3+) #938
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
fa5e088
cb1c7ca
025f2de
218c060
a0107f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,17 +14,17 @@ | |
| using Umbraco.Extensions; | ||
|
|
||
| using uSync.Core.Models; | ||
| using uSync.Core.Templates; | ||
| using uSync.Core.Versions; | ||
|
|
||
| namespace uSync.Core.Serialization.Serializers; | ||
|
|
||
| [SyncSerializer("D0E0769D-CCAE-47B4-AD34-4182C587B08A", "Template Serializer", uSyncConstants.Serialization.Template)] | ||
| public class TemplateSerializer : SyncSerializerBase<ITemplate>, ISyncSerializer<ITemplate> | ||
| { | ||
| private readonly IShortStringHelper _shortStringHelper; | ||
| private readonly IFileSystem? _viewFileSystem; | ||
|
|
||
| private readonly ITemplateService _templateService; | ||
| private readonly ISyncTemplateService _templateService; | ||
| private readonly IUserIdKeyResolver _userIdKeyResolver; | ||
|
|
||
| private readonly uSyncCapabilityChecker _capabilityChecker; | ||
|
|
@@ -38,17 +38,15 @@ public TemplateSerializer( | |
| FileSystems fileSystems, | ||
| IConfiguration configuration, | ||
| uSyncCapabilityChecker capabilityChecker, | ||
| ITemplateService templateService, | ||
| IUserIdKeyResolver userIdKeyResolver) | ||
| IUserIdKeyResolver userIdKeyResolver, | ||
| ISyncTemplateService syncTemplateService) | ||
| : base(entityService, logger) | ||
| { | ||
| _shortStringHelper = shortStringHelper; | ||
|
|
||
| _viewFileSystem = fileSystems.MvcViewsFileSystem; | ||
| _configuration = configuration; | ||
| _capabilityChecker = capabilityChecker; | ||
| _templateService = templateService; | ||
| _userIdKeyResolver = userIdKeyResolver; | ||
| _templateService = syncTemplateService; | ||
| } | ||
|
|
||
| protected override async Task<SyncAttempt<ITemplate>> ProcessDeleteAsync(Guid key, string alias, SerializerFlags flags) | ||
|
|
@@ -103,7 +101,13 @@ protected override async Task<SyncAttempt<ITemplate>> DeserializeCoreAsync(XElem | |
| userKey, key); | ||
|
|
||
| if (attempt.Success is false) | ||
| return SyncAttempt<ITemplate>.Fail(name, ChangeType.Import, "Failed to create template"); | ||
| { | ||
| logger.LogWarning("Failed to create template {alias} {name} - {error} - {status}", | ||
| alias, name, attempt.Exception?.Message ?? "Unknown error", attempt.Status); | ||
|
|
||
| return SyncAttempt<ITemplate>.Fail(name, ChangeType.Import, | ||
| $"Failed to create template {alias} {name} - {attempt.Exception?.Message ?? "Unknown error"} - {attempt.Status}"); | ||
| } | ||
|
|
||
| item = attempt.Result; | ||
| details.AddNew(alias, alias, "Template"); | ||
|
|
@@ -118,8 +122,8 @@ protected override async Task<SyncAttempt<ITemplate>> DeserializeCoreAsync(XElem | |
| if (item is null) | ||
| { | ||
| // creating went wrong | ||
| logger.LogWarning("Failed to create template"); | ||
| return SyncAttempt<ITemplate>.Fail(name, ChangeType.Import, "Failed to create template"); | ||
| logger.LogWarning("Failed to create template - item is null after create process."); | ||
| return SyncAttempt<ITemplate>.Fail(name, ChangeType.Import, "Failed to create template - no new item created."); | ||
|
||
| } | ||
|
|
||
| if (item.Key != key) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| using Umbraco.Cms.Core; | ||
| using Umbraco.Cms.Core.Models; | ||
| using Umbraco.Cms.Core.Services.OperationStatus; | ||
|
|
||
| namespace uSync.Core.Templates; | ||
|
|
||
| public interface ISyncTemplateService | ||
| { | ||
| Task<Attempt<ITemplate, TemplateOperationStatus>> CreateAsync(string name, string alias, string? content, Guid userKey, Guid key); | ||
| Task DeleteAsync(string alias, Guid userKey); | ||
| Task<ITemplate?> GetAsync(string alias); | ||
| Task<ITemplate?> GetAsync(Guid key); | ||
| Task<ITemplate?> GetAsync(int id); | ||
| Task<IEnumerable<ITemplate>> GetChildrenAsync(int templateId); | ||
| Task<Attempt<ITemplate, TemplateOperationStatus>> UpdateAsync(ITemplate template, Guid userKey); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,104 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.Extensions.Configuration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Core; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Core.Models; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Core.Persistence.Repositories; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Core.Scoping; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Core.Services; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Core.Services.OperationStatus; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Umbraco.Cms.Core.Strings; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using uSync.Core.Versions; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace uSync.Core.Templates; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// does creating of templates, espeically if we are in production mode. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| internal class SyncTemplateService : ISyncTemplateService | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly ITemplateService _templateService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly IConfiguration _configuration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly ICoreScopeProvider _scopeProvider; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly ITemplateRepository _templateRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private readonly IShortStringHelper _shortStringHelper; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public SyncTemplateService(ITemplateService templateService, IConfiguration configuration, ICoreScopeProvider scopeProvider, ITemplateRepository templateRepository, IShortStringHelper shortStringHelper) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _templateService = templateService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _configuration = configuration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _scopeProvider = scopeProvider; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _templateRepository = templateRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _shortStringHelper = shortStringHelper; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// creates a template, but only if we are in production mode. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="name"></param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="alias"></param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <param name="description"></param> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <returns></returns> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
KevinJump marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public async Task<Attempt<ITemplate, TemplateOperationStatus>> CreateAsync(string name, string alias, string? content, Guid userKey, Guid key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TemplateOperationStatus lastKnownStatus = TemplateOperationStatus.Success; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (IsInProductionMode() is false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var attempt = await _templateService.CreateAsync(name, alias, content, userKey, key); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (attempt.Success) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return attempt; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // else - lets try the repository way (surely this is a hack?) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // https://github.com/umbraco/Umbraco-CMS/pull/21600#issuecomment-4205232583 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await CreateTemplateInternal(name, alias, content, userKey, key, lastKnownStatus); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private async Task<Attempt<ITemplate, TemplateOperationStatus>> CreateTemplateInternal(string name, string alias, string? content, Guid userKey, Guid key, TemplateOperationStatus lastKnownStatus) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var template = new Template(_shortStringHelper, name, alias) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Content = content, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Key = key, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using (var scope = _scopeProvider.CreateCoreScope(autoComplete: true)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _templateRepository.Save(template); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scope.Complete(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scope.Complete(); |
Copilot
AI
Apr 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CreateTemplateInternal is marked async but contains no await, which adds unnecessary state-machine overhead and can hide synchronous exceptions behind an async boundary. Either make it synchronous and return Task.FromResult(...)/Task directly, or introduce real async work (there currently isn’t any).
| private async Task<Attempt<ITemplate, TemplateOperationStatus>> CreateTemplateInternal(string name, string alias, string? content, Guid userKey, Guid key, TemplateOperationStatus lastKnownStatus) | |
| { | |
| var template = new Template(_shortStringHelper, name, alias) | |
| { | |
| Content = content, | |
| Key = key, | |
| }; | |
| try | |
| { | |
| using (var scope = _scopeProvider.CreateCoreScope(autoComplete: true)) | |
| { | |
| _templateRepository.Save(template); | |
| scope.Complete(); | |
| return Attempt.SucceedWithStatus<ITemplate, TemplateOperationStatus>(TemplateOperationStatus.Success, template); | |
| } | |
| } | |
| catch (Exception ex) | |
| { | |
| return Attempt.FailWithStatus<ITemplate, TemplateOperationStatus>(lastKnownStatus, template, ex); | |
| private Task<Attempt<ITemplate, TemplateOperationStatus>> CreateTemplateInternal(string name, string alias, string? content, Guid userKey, Guid key, TemplateOperationStatus lastKnownStatus) | |
| { | |
| ITemplate? template = null; | |
| try | |
| { | |
| template = new Template(_shortStringHelper, name, alias) | |
| { | |
| Content = content, | |
| Key = key, | |
| }; | |
| using (var scope = _scopeProvider.CreateCoreScope(autoComplete: true)) | |
| { | |
| _templateRepository.Save(template); | |
| scope.Complete(); | |
| return Task.FromResult(Attempt.SucceedWithStatus<ITemplate, TemplateOperationStatus>(TemplateOperationStatus.Success, template)); | |
| } | |
| } | |
| catch (Exception ex) | |
| { | |
| return Task.FromResult(Attempt.FailWithStatus<ITemplate, TemplateOperationStatus>(lastKnownStatus, template, ex)); |
Uh oh!
There was an error while loading. Please reload this page.