diff --git a/uSync.Core/Extensions/ObjectPropertyExtensions.cs b/uSync.Core/Extensions/ObjectPropertyExtensions.cs
new file mode 100644
index 00000000..e7bcc9a2
--- /dev/null
+++ b/uSync.Core/Extensions/ObjectPropertyExtensions.cs
@@ -0,0 +1,85 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+using Umbraco.Extensions;
+
+namespace uSync.Core.Extensions;
+
+///
+/// extension methods to get and set properties on objects, using reflection.
+///
+public static class ObjectPropertyExtensions
+{
+ ///
+ /// Determines whether the specified object contains a public property with the given name.
+ ///
+ /// This method uses reflection to examine the object's type at runtime. Frequent use may have
+ /// performance implications.
+ /// The object to inspect for the presence of the specified property. Cannot be null.
+ /// The name of the property to search for. The comparison is case-sensitive.
+ /// true if the object has a public property with the specified name; otherwise, false.
+ public static bool HasProperty(this object obj, string propertyName)
+ => obj.GetType().GetProperty(propertyName) != null;
+
+ ///
+ /// Retrieves the value of a specified property from the given object, or returns a default value if the property
+ /// does not exist or cannot be accessed.
+ ///
+ /// This method uses reflection to access the property. If the property is not found or cannot be
+ /// accessed, no exception is thrown and the default value is returned.
+ /// The type of the property value to retrieve.
+ /// The object from which to retrieve the property value. Cannot be null.
+ /// The name of the property whose value is to be retrieved. The search is case-sensitive.
+ /// The value to return if the specified property does not exist or cannot be accessed.
+ /// The value of the specified property if it exists and can be accessed; otherwise, the provided default value.
+ public static T GetPropertyValue(this object obj, string propertyName, T defaultValue)
+ {
+ var propertyInfo = obj.GetType().GetProperty(propertyName);
+ if (propertyInfo == null) return defaultValue;
+
+ return GetPropertyAs(propertyInfo, obj, defaultValue);
+ }
+
+ ///
+ /// Sets the value of the specified property on the given object.
+ ///
+ /// If the specified property does not exist on the object, the method returns the provided value
+ /// without making any changes.
+ /// The type of the value to assign to the property.
+ /// The object whose property value is to be set. This parameter cannot be null.
+ /// The name of the property to set. This must correspond to a public property on the object.
+ /// The value to assign to the specified property.
+ /// The value that was assigned to the property.
+ public static T SetPropertyValue(this object obj, string propertyName, T value)
+ {
+ var propertyInfo = obj.GetType().GetProperty(propertyName);
+ if (propertyInfo == null) return value;
+ propertyInfo.SetValue(obj, value);
+ return value;
+ }
+
+ ///
+ /// Retrieves the value of the specified property and attempts to convert it to the specified type.
+ ///
+ /// If the property is not found or the conversion fails, the method returns the default value
+ /// provided.
+ /// The type to which the property value is converted.
+ /// The PropertyInfo object representing the property to retrieve the value from.
+ /// The object instance from which to retrieve the property value.
+ /// The value to return if the property is null or cannot be converted to the specified type.
+ /// The converted value of the property if successful; otherwise, the specified default value.
+ private static TValue GetPropertyAs(PropertyInfo info, object property, TValue defaultValue)
+ {
+ if (info == null) return defaultValue;
+
+ var value = info.GetValue(property);
+ if (value == null) return defaultValue;
+
+ var result = value.TryConvertTo();
+ if (result.Success)
+ return result.Result ?? defaultValue;
+
+ return defaultValue;
+
+ }
+}
diff --git a/uSync.Core/Serialization/Serializers/ContentSerializer.cs b/uSync.Core/Serialization/Serializers/ContentSerializer.cs
index 53360238..8e269b7b 100644
--- a/uSync.Core/Serialization/Serializers/ContentSerializer.cs
+++ b/uSync.Core/Serialization/Serializers/ContentSerializer.cs
@@ -24,7 +24,21 @@ public class ContentSerializer : ContentSerializerBase, ISyncSerialize
protected readonly IUserService userService;
protected readonly ITemplateService _templateService;
- protected readonly ISyncDocumentUrlCleaner _urlCleaner;
+ protected readonly ISyncDocumentUrlCleaner? _urlCleaner;
+
+ [Obsolete("Use the constructor with urlCleaner, will be removed in v19")]
+ public ContentSerializer(
+ IEntityService entityService,
+ ILanguageService languageService,
+ IRelationService relationService,
+ IShortStringHelper shortStringHelper,
+ ILogger logger,
+ IContentService contentService,
+ SyncValueMapperCollection syncMappers,
+ IUserService userService,
+ ITemplateService templateService
+ ) : this(entityService, languageService, relationService, shortStringHelper, logger, contentService, syncMappers, userService, templateService, null)
+ { }
public ContentSerializer(
IEntityService entityService,
@@ -802,7 +816,7 @@ public override Task DeleteItemAsync(IContent item)
protected override Task OnKeyChange(IContent item, Guid oldKey, Guid newKey)
{
// key changes need to clean the DocumentUrl cache.
- _urlCleaner.CleanUrlsForDocument(oldKey);
+ _urlCleaner?.CleanUrlsForDocument(oldKey);
return Task.CompletedTask;
}
}
diff --git a/uSync.Extend/readme.md b/uSync.Extend/readme.md
index 4e7d84f7..bd325599 100644
--- a/uSync.Extend/readme.md
+++ b/uSync.Extend/readme.md
@@ -7,6 +7,8 @@ having to write the whole thing from scratch.
The extend package contains two base classes that simplfiy Handler and serializer creation for uSync.
+Look in the [./Example](./Example) folder for a working example of how to use these base classes to create your own handlers and serializers.
+
### SyncObjectHandler
In uSync a handler is the thing that controlls the Input/Output of data to and from the file system.
its the thing that is called when an item is saved or when uSync exports or imports anything.