Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jesse Andrews 191 posts 716 karma points c-trib
    Sep 12, 2023 @ 22:58
    Jesse Andrews
    0

    Running into issues with data being incorrectly overwritten with custom serializer

    I have a custom serializer that's working for the most part. I'm having some issues with existing data being overwritten when content is updated that shouldn't be. For example, I create a new item with the name "Test" and then delete it to create the entry.

    <Empty Key="6ceb35f6-b7b9-480c-9725-103885f8d018" Alias="Test" Change="Delete" />
    

    I then create another item with the same name. This creates a new entry as expected, but it also changes the previous config file to

    <Empty Key="{new id}" Alias="Test" Change="Rename" />
    

    even though the keys don't match. Is this an issue with usync or is the problem somewhere in my code (see below)?

    Handler

    [SyncHandler("WidgetHandler", "Widgets", "Widgets", 500,
        Icon = "icon-settings-alt usync-addon-icon", EntityType = "widget")]
    public class WidgetHandler : SyncHandlerRoot<IWidget, IWidget>, ISyncHandler, INotificationHandler<WidgetSavedNotification>, INotificationHandler<WidgetDeletedNotification> {
        private readonly SyncWidgetService _syncWidgetService;
        public override string Group => "Widgets";
    
        public WidgetHandler(SyncWidgetService syncWidgetService, ILogger<SyncHandlerRoot<IWidget, IWidget>> logger, AppCaches appCaches, IShortStringHelper shortStringHelper, SyncFileService syncFileService, uSyncEventService mutexService, uSyncConfigService uSyncConfig, ISyncItemFactory syncItemFactory) : base(logger, appCaches, shortStringHelper, syncFileService, mutexService, uSyncConfig, syncItemFactory) {
            _syncWidgetService = syncWidgetService;
        }
    
        protected override string GetItemName(IWidget item) => item.Name;
    
        public override IEnumerable<uSyncAction> ExportAll(string folder, HandlerSettings config, SyncUpdateCallback callback) {
            var items = _syncWidgetService.GetAll();
    
            var actions = new List<uSyncAction>();
            foreach (var item in items) {
                callback?.Invoke(GetItemName(item), 2, 4);
                actions.AddRange(Export(item, folder, config));
            }
    
            return actions;
        }
        protected override IEnumerable<IWidget> GetChildItems(IWidget parent) => Enumerable.Empty<IWidget>();
    
        protected override IEnumerable<IWidget> GetFolders(IWidget parent) => Enumerable.Empty<IWidget>();
    
        protected override IWidget GetFromService(IWidget item) => _syncWidgetService.Get(item.Key);
    
        protected override IEnumerable<uSyncAction> DeleteMissingItems(IWidget parent, IEnumerable<Guid> keysToKeep, bool reportOnly) {
            return Enumerable.Empty<uSyncAction>();
        }
        public void Handle(WidgetSavedNotification notification) {
            if (!ShouldProcessEvent()) {
                return;
            }
            var folder = Path.Combine(rootFolder, DefaultFolder);
            foreach (var widget in notification.SavedEntities) {
                var attempts = Export(widget, folder, DefaultConfig);
                foreach (var attempt in attempts.Where(x => x.Success)) {
                    CleanUp(widget, attempt.FileName, folder);
                }
            }
        }
    
        public void Handle(WidgetDeletedNotification notification) {
            if (!ShouldProcessEvent()) return;
            var folder = Path.Combine(rootFolder, DefaultFolder);
            foreach (var widget in notification.DeletedEntities) {
    
                var filename = GetPath(folder, widget, DefaultConfig.GuidNames, DefaultConfig.UseFlatStructure);
    
                var attempt = serializer.SerializeEmpty(widget, SyncActionType.Delete, string.Empty);
                if (attempt.Success) {
                    syncFileService.SaveXElement(attempt.Item, filename);
                    CleanUp(widget, filename, folder);
                }
            }
        }
    }
    

    Serializer

    [SyncSerializer("fde05407-9833-4713-9c6c-d13bf946707f", "Widget Serializer", "Widget")]
    public class WidgetSerializer : SyncSerializerRoot<IWidget>, ISyncSerializer<IWidget> {
        private readonly SyncWidgetService _syncWidgetService;
        private readonly IShortStringHelper _shortStringHelper;
        private readonly IContentTypeService _contentTypeService;
    
        public WidgetSerializer(SyncWidgetService syncWidgetService, IContentTypeService contentTypeService, IShortStringHelper shortStringHelper, ILogger<WidgetSerializer> logger) : base(logger) {
            _syncWidgetService = syncWidgetService;
            _shortStringHelper = shortStringHelper;
            _contentTypeService = contentTypeService;
        }
    
        public override void DeleteItem(IWidget item) {
            _syncWidgetService.Delete(item);
        }
    
        public override IWidget FindItem(int id) => _syncWidgetService.Get(id);
    
        public override IWidget FindItem(Guid key) => _syncWidgetService.Get(key);
    
        public override IWidget FindItem(string alias) => _syncWidgetService.Get(alias);
    
        public override string ItemAlias(IWidget item) => item.Name.ToSafeAlias(_shortStringHelper, true);
    
        public override Guid ItemKey(IWidget item) => item.Key;
    
        public override void SaveItem(IWidget item) {
            if (item.IsDirty()) {
                _syncWidgetService.Save(item);
            }
        }
    
        protected override SyncAttempt<IWidget> DeserializeCore(XElement node, SyncSerializerOptions options) {
            var key = node.GetKey();
            var item = FindItem(node.GetKey());
            var name = node.Element("Name").ValueOrDefault(string.Empty);
            var contentTypeKey = node.Element("ContentTypeKey").ValueOrDefault(Guid.Empty);
            var details = new List<uSyncChange>();
            var oldName = item?.Name ?? String.Empty;
            var oldKey = item?.ContentType.Key;
            var oldDescription = item?.Description ?? String.Empty;
            var description = node.Element("Description").ValueOrDefault(string.Empty);
            if (key != Guid.Empty) {
                item = _syncWidgetService.Get(key);
            }
            if (item == null || oldKey != contentTypeKey) {
                var contentType = _contentTypeService.Get(contentTypeKey);
                item = new Widget(name, contentType);
                item.Key = key;
            }
            if (oldName != name) {
                details.Add(uSyncChange.Update("Name", "Name", oldName, name));
                item.Name = name;
            }
            if (oldKey != contentTypeKey) {
                details.Add(uSyncChange.Update("ContentTypeKey", "ContentTypeKey", oldKey, contentTypeKey));
            }
            if (oldDescription != description) {
                details.Add(uSyncChange.Update("Description", "Description", oldDescription, description));
                item.Description = description;
            }
            //if (item.IsDirty()) {
            //    SaveItem(item);
            //}
            return SyncAttempt<IWidget>.Succeed(item.Name, item, ChangeType.Import, details);
        }
    
        protected override SyncAttempt<XElement> SerializeCore(IWidget item, SyncSerializerOptions options) {
            var node = InitializeBaseNode(item, item.Name);
            node.Add(new XElement("Name", item.Name));
            node.Add(new XElement("ContentTypeKey", item.ContentType.Key));
            node.Add(new XElement("Description", string.IsNullOrEmpty(item.Description) ? null : item.Description));
            return SyncAttempt<XElement>.Succeed(item.Name, node, typeof(IWidget), ChangeType.Export);
        }
    }
    

    The "Get" method of the syncWidgetService returns null if the id/key/alias isn't matched in the database. Not sure whether it should return something different in that case.

    Lastly, the site is running umbraco 11.4.2 with uSync 11.2.1.

Please Sign in or register to post replies

Write your reply to:

Draft