Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion uSync.BackOffice/Configuration/uSyncHandlerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public static TResult GetSetting<TResult>(this HandlerSettings settings, string
{
if (settings.Settings != null && settings.Settings.TryGetValue(key, out var value) && value is not null)
{
if (value.TryConvertPreChecked<TResult>(out var result) && result is not null)
if (value.TryGetValueAs<TResult>(out var result) && result is not null)
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion uSync.Core/Extensions/ConversionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ internal static class ConversionExtensions
public static TObject? GetValueAs<TObject>(this object value)
{
if (value == null) return default;
return value.TryConvertPreChecked<TObject>(out var result) ? result : default;
return value.TryGetValueAs<TObject>(out var result) ? result : default;
}

public static Guid ConvertToGuid(this int value)
Expand Down
58 changes: 41 additions & 17 deletions uSync.Core/Extensions/JsonTextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -390,38 +390,63 @@ public static bool TrySerializeJsonString(this object value, [MaybeNull] out str
public static string SerializeJsonString(this object value, bool indent = true)
=> value is null ? string.Empty : JsonSerializer.Serialize(value, indent ? _defaultOptions : _flatOptions);

private static bool TryGetValueAs<TObject>(this object value, [MaybeNullWhen(false)] out TObject result)
/// <summary>
/// Convert a value to the requested type.
/// </summary>
/// <remarks>
/// Pre-empts the first-chance InvalidCastException that Umbraco's TryConvertTo
/// throws when converting a JsonElement to a value type (see uSync.Complete
/// issue #304). Settings/config values often arrive as JsonElement (bound from
/// appsettings.json); doing that conversion with System.Text.Json first means the
/// common path never throws. String conversions (which TryConvertTo already
/// handles cleanly) and anything STJ can't handle still fall back to TryConvertTo.
/// </remarks>
public static bool TryGetValueAs<TObject>(this object? value, [MaybeNullWhen(false)] out TObject result)
{
result = default;
if (value == null) return false;
if (value is null) return false;

// Umbraco's TryConvertTo turns a JsonElement into a string cleanly, but throws
// (and swallows) an InvalidCastException for JsonElement -> value type. Do the
// value-type conversion with System.Text.Json first to avoid that noise; string
// and anything STJ can't handle fall through to TryConvertTo below.
if (value is JsonElement element && typeof(TObject) != typeof(string))
{
try
{
result = element.Deserialize<TObject>(_defaultOptions);
if (result is not null) return true;
}
catch
{
// not something STJ could convert directly - fall back to TryConvertTo below.
}
}

var attempt = value.TryConvertTo<TObject>();
if (attempt is false || attempt.Result is null) return attempt;
if (attempt.Success is false || attempt.Result is null) return false;

result = attempt.Result;
return true;
}

/// <summary>
/// Convert a value to the requested type, pre-empting the first-chance
/// InvalidCastException that Umbraco's TryConvertTo throws when converting
/// a JsonElement to a value type (see uSync.Complete issue #304).
/// Convert a value to the requested runtime type.
/// </summary>
/// <remarks>
/// Settings/config values often arrive as JsonElement (bound from appsettings.json).
/// Asking Umbraco's TryConvertTo to turn one into e.g. a bool throws (and swallows)
/// an InvalidCastException every call - harmless, but noisy and slow when a debugger
/// is attached. Doing the JsonElement conversion with System.Text.Json first means the
/// common path never throws; anything STJ can't handle still falls back to TryConvertTo.
/// Non-generic companion to the generic TryGetValueAs for callers that only
/// have a runtime Type. Same JsonElement pre-check.
/// </remarks>
public static bool TryConvertPreChecked<TObject>(this object? value, [MaybeNullWhen(false)] out TObject result)
public static bool TryGetValueAs(this object? value, Type targetType, [MaybeNullWhen(false)] out object result)
{
result = default;
if (value is null) return false;

if (value is JsonElement element)
if (value is JsonElement element && targetType != typeof(string))
{
try
{
result = element.Deserialize<TObject>(_defaultOptions);
result = element.Deserialize(targetType, _defaultOptions);
if (result is not null) return true;
}
catch
Expand All @@ -430,7 +455,7 @@ public static bool TryConvertPreChecked<TObject>(this object? value, [MaybeNullW
}
}

var attempt = value.TryConvertTo<TObject>();
var attempt = value.TryConvertTo(targetType);
if (attempt.Success is false || attempt.Result is null) return false;

result = attempt.Result;
Expand Down Expand Up @@ -498,8 +523,7 @@ public static TResult GetPropertyValueOrDefault<TResult>(this JsonObject obj, st
if (obj.TryGetPropertyValue(propertyName, out var value) is false || value is null)
return defaultValue;

var attempt = value.TryConvertTo<TResult>();
return attempt.ResultOr(defaultValue);
return value.TryGetValueAs<TResult>(out var result) ? result : defaultValue;
}

public static bool TryGetPropertyAsArray(this JsonObject jsonObject, string propertyName, [MaybeNullWhen(false)] out JsonArray result)
Expand Down
7 changes: 4 additions & 3 deletions uSync.Core/Extensions/ListExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Umbraco.Extensions;

using uSync.Core.Extensions;

namespace uSync.Core;

public static class ListExtensions
Expand Down Expand Up @@ -40,10 +42,9 @@ internal static IEnumerable<T> ConvertItems<T>(this IList<string> items)
foreach (var item in items)
{
if (string.IsNullOrWhiteSpace(item)) continue;
var attempt = item.TryConvertTo<T>();
if (attempt.Success && attempt.Result is not null)
if (item.TryGetValueAs<T>(out var result))
{
yield return attempt.Result;
yield return result;
}
}
}
Expand Down
7 changes: 1 addition & 6 deletions uSync.Core/Extensions/ObjectPropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,6 @@ private static TValue GetPropertyAs<TValue>(PropertyInfo info, object property,
var value = info.GetValue(property);
if (value == null) return defaultValue;

var result = value.TryConvertTo<TValue>();
if (result.Success)
return result.Result ?? defaultValue;

return defaultValue;

return value.TryGetValueAs<TValue>(out var result) ? result : defaultValue;
}
}
19 changes: 6 additions & 13 deletions uSync.Core/Extensions/XElementExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

using Umbraco.Extensions;

using uSync.Core.Extensions;

namespace uSync.Core;

public static class XElementExtensions
Expand Down Expand Up @@ -138,11 +140,7 @@ public static TObject ValueOrDefault<TObject>([AllowNull] this XElement? node, T
var value = node.ValueOrDefault(string.Empty);
if (value == string.Empty) return defaultValue;

var attempt = value.TryConvertTo<TObject>();
if (attempt)
return attempt.Result ?? defaultValue;

return defaultValue;
return value.TryGetValueAs<TObject>(out var result) ? result : defaultValue;
}


Expand Down Expand Up @@ -209,8 +207,7 @@ public static void CreateOrSetElement<TObject>(this XElement node, string name,
{
if (node is null) return;

var attempt = value.TryConvertTo<string>();
if (attempt.Success)
if (value.TryGetValueAs<string>(out var stringValue))
{
var element = node.Element(name);
if (element is null)
Expand All @@ -219,7 +216,7 @@ public static void CreateOrSetElement<TObject>(this XElement node, string name,
node.Add(element);
}

element.Value = attempt.Result ?? string.Empty;
element.Value = stringValue ?? string.Empty;
}
}

Expand Down Expand Up @@ -289,11 +286,7 @@ public static TObject ValueOrDefault<TObject>([AllowNull] this XAttribute attrib
var value = attribute.ValueOrDefault(string.Empty);
if (value == string.Empty) return defaultValue;

var attempt = value.TryConvertTo<TObject>();
if (attempt)
return attempt.Result ?? defaultValue;

return defaultValue;
return value.TryGetValueAs<TObject>(out var result) ? result : defaultValue;
}
#endregion

Expand Down
5 changes: 2 additions & 3 deletions uSync.Core/Mapping/Mappers/MediaPicker3Mapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,8 @@ private static Guid GetGuidValue(JsonObject obj, string key)
{
if (obj != null && obj.ContainsKey(key))
{
var attempt = obj[key]?.ToString().TryConvertTo<Guid>();
if (attempt?.Success is true)
return attempt?.Result ?? Guid.Empty;
if (obj[key]?.ToString().TryGetValueAs<Guid>(out var guid) is true)
return guid;
}

return Guid.Empty;
Expand Down
11 changes: 5 additions & 6 deletions uSync.Core/Mapping/Mappers/MemberGroupPickerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Umbraco.Extensions;

using uSync.Core.Dependency;
using uSync.Core.Extensions;
using uSync.Core.Serialization;

using static Umbraco.Cms.Core.Constants;
Expand Down Expand Up @@ -30,11 +31,10 @@ public MemberGroupPickerMapper(
/// </summary>
public override async Task<string?> GetExportValueAsync(object value, string editorAlias)
{
var attempt = value.TryConvertTo<string>();
if (attempt.Success is false || attempt.Result is null)
if (value.TryGetValueAs<string>(out var stringValue) is false)
return await base.GetExportValueAsync(value, editorAlias);

var values = attempt.Result.ToDelimitedList().ConvertItems<int>();
var values = stringValue.ToDelimitedList().ConvertItems<int>();

var groups = new List<string>();

Expand Down Expand Up @@ -86,11 +86,10 @@ public override async Task<IEnumerable<uSyncDependency>> GetDependenciesAsync(ob
return Enumerable.Empty<uSyncDependency>();

// get the int value and load the group
var attempt = value.TryConvertTo<string>();
if (attempt.Success is false || attempt.Result is null)
if (value.TryGetValueAs<string>(out var stringValue) is false)
return await base.GetDependenciesAsync(value, editorAlias, flags);

var values = attempt.Result.ToDelimitedList().ConvertItems<int>();
var values = stringValue.ToDelimitedList().ConvertItems<int>();

var dependencies = new List<uSyncDependency>();

Expand Down
2 changes: 1 addition & 1 deletion uSync.Core/Mapping/SyncValueMapperBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ protected IEnumerable<uSyncDependency> CreateDependencies(IEnumerable<string> ud
protected static TObject? GetValueAs<TObject>(object value)
{
if (value == null) return default;
return value.TryConvertPreChecked<TObject>(out var result) ? result : default;
return value.TryGetValueAs<TObject>(out var result) ? result : default;
}
}

Expand Down
4 changes: 2 additions & 2 deletions uSync.Core/Serialization/Serializers/ContentSerializerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -706,8 +706,8 @@ private static bool IsUpdatedValue(object? current, object? newValue)
if (current != null && newValue != null && current.GetType() != newValue.GetType())
{
var currentType = current.GetType();
var attempt = newValue.TryConvertTo(currentType);
if (attempt.Success) return !current.Equals(attempt.Result);
if (newValue.TryGetValueAs(currentType, out var converted))
return !current.Equals(converted);
}

return true;
Expand Down
34 changes: 13 additions & 21 deletions uSync.Core/Serialization/Serializers/ContentTypeBaseSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,15 @@ protected void SerializeNewProperty<TValue>(XElement node, IPropertyType propert
{
var value = propertyInfo.GetValue(property);

var attempt = value.TryConvertTo<TValue>();
if (attempt.Success)
// TryGetValueAs treats a null conversion result as failure, so fall back
// to an empty element - the property still gets recorded in the xml.
if (value.TryGetValueAs<TValue>(out var converted))
{
if (attempt.Result != null)
{
node.Add(new XElement(propertyName, attempt.Result));
}
else
{
node.Add(new XElement(propertyName, string.Empty));
}
node.Add(new XElement(propertyName, converted));
}
else
{
node.Add(new XElement(propertyName, string.Empty));
}
}
}
Expand Down Expand Up @@ -727,19 +725,18 @@ protected void AddAlias(string alias)
if (propertyInfo != null)
{
var value = node.Element(propertyName).ValueOrDefault(string.Empty);
var attempt = value.TryConvertTo<TValue>();
if (attempt.Success)
if (value.TryGetValueAs<TValue>(out var converted))
{
var current = ContentTypeBaseSerializer<TObject>.GetPropertyAs<TValue>(propertyInfo, property);

if (current == null || !current.Equals(attempt.Result))
if (current == null || !current.Equals(converted))
{
propertyInfo.SetValue(property, attempt.Result);
propertyInfo.SetValue(property, converted);

return uSyncChange.Update($"property/{propertyName}",
propertyName,
current.ToNonBlankValue(),
attempt.Result?.ToString());
converted?.ToString());
}
}
}
Expand All @@ -754,12 +751,7 @@ protected void AddAlias(string alias)
var value = info.GetValue(property);
if (value == null) return default;

var result = value.TryConvertTo<TValue>();
if (result.Success)
return result.Result;

return default;

return value.TryGetValueAs<TValue>(out var result) ? result : default;
}


Expand Down
18 changes: 6 additions & 12 deletions uSync.Core/Serialization/Serializers/ContentTypeSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,15 +409,14 @@ private List<uSyncChange> DeserializeCleanupHistory(IContentType item, XElement
var current = GetPropertyAs<string>(property, historyCleanup);
if (element.Value != current)
{
// now set it.
var updatedValue = element.Value.TryConvertTo(property.PropertyType);
if (updatedValue.Success)
// now set it.
if (element.Value.TryGetValueAs(property.PropertyType, out var updatedValue))
{
if (logger.IsEnabled(LogLevel.Debug))
logger.LogDebug("Saving HistoryCleanup Value: {name} {value}", element.Name.LocalName, updatedValue.Result);
logger.LogDebug("Saving HistoryCleanup Value: {name} {value}", element.Name.LocalName, updatedValue);

changes.AddUpdate($"{_historyCleanupName}:{element.Name.LocalName}", current.ToNonBlankValue(), updatedValue.Result, $"{_historyCleanupName}/{element.Name.LocalName}");
property.SetValue(historyCleanup, updatedValue.Result);
changes.AddUpdate($"{_historyCleanupName}:{element.Name.LocalName}", current.ToNonBlankValue(), updatedValue, $"{_historyCleanupName}/{element.Name.LocalName}");
property.SetValue(historyCleanup, updatedValue);
}
}
}
Expand Down Expand Up @@ -451,11 +450,6 @@ protected override XElement CleanseNode(XElement node)
var value = info.GetValue(property);
if (value is null) return default;

var result = value.TryConvertTo<TValue>();
if (result.Success)
return result.Result;

return default;

return value.TryGetValueAs<TValue>(out var result) ? result : default;
}
}
3 changes: 1 addition & 2 deletions uSync.Core/Serialization/Serializers/DomainSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ private static int GetSortableValue(IDomain item)

var result = property.GetValue(item);

var attempt = result.TryConvertTo<int>();
return attempt.Success ? attempt.Result : 0;
return result.TryGetValueAs<int>(out var sortable) ? sortable : 0;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion uSync.Core/Serialization/SyncSerializerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public TResult GetSetting<TResult>(string key, TResult defaultValue)
{
if (this.Settings?.TryGetValue(key, out var value) is true && value is not null)
{
if (value.TryConvertPreChecked<TResult>(out var result) && result is not null)
if (value.TryGetValueAs<TResult>(out var result) && result is not null)
return result;
}

Expand Down
Loading
Loading