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
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static async Task<Result<List<PersistentSubscriptionInfo>>> GetSubscripti
String responseBody = await responseMessage.Content.ReadAsStringAsync(cancellationToken);

if (responseMessage.IsSuccessStatusCode) {
List<PersistentSubscriptionInfo> list = StringSerialiser.Deserialise<List<PersistentSubscriptionInfo>>(responseBody);
List<PersistentSubscriptionInfo> list = StringSerialiser.Deserialise<List<PersistentSubscriptionInfo>>(responseBody, new SerialiserOptions(SerialiserPropertyFormat.CamelCase));

return Result.Success(list);
}
Expand Down
18 changes: 18 additions & 0 deletions Shared/Serialisation/ExpressionHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using System.Linq.Expressions;

namespace Shared.Serialisation;

public static class ExpressionHelpers
{
public static string GetPropertyName<T>(Expression<Func<T, object>> expression)
{
if (expression.Body is MemberExpression member)
return member.Member.Name;

if (expression.Body is UnaryExpression unary && unary.Operand is MemberExpression unaryMember)
return unaryMember.Member.Name;

throw new ArgumentException("Expression must be a property access", nameof(expression));
}
}
19 changes: 19 additions & 0 deletions Shared/Serialisation/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;

namespace Shared.Serialisation;

public static class Extensions
{
public static JsonSerializerOptions AddModifier(
this JsonSerializerOptions options,
Action<JsonTypeInfo> modifier)
{
if (options.TypeInfoResolver is not DefaultJsonTypeInfoResolver resolver)
throw new InvalidOperationException("TypeInfoResolver must be DefaultJsonTypeInfoResolver");

resolver.Modifiers.Add(modifier);
return options;
}
}
40 changes: 40 additions & 0 deletions Shared/Serialisation/JsonTypeInfoExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Text.Json.Serialization.Metadata;

namespace Shared.Serialisation;

public static class JsonTypeInfoExtensions
{
public static void IgnoreProperty<T>(
this JsonTypeInfo typeInfo,
Expression<Func<T, object>> selector)
{
var name = ExpressionHelpers.GetPropertyName(selector);

var prop = typeInfo.Properties.FirstOrDefault(p =>
string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase));

if (prop != null)
{
prop.ShouldSerialize = (_, _) => false;
}
}

public static void RenameProperty<T>(
this JsonTypeInfo typeInfo,
Expression<Func<T, object>> selector,
string newName)
{
var name = ExpressionHelpers.GetPropertyName(selector);

var prop = typeInfo.Properties.FirstOrDefault(p =>
string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase));

if (prop != null)
{
prop.Name = newName;
}
}
}
66 changes: 66 additions & 0 deletions Shared/Serialisation/JsonTypeInfoModifierExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization.Metadata;

namespace Shared.Serialisation;

public static class JsonTypeInfoModifierExtensions
{
/// <summary>
/// Apply a modifier only to a specific type T
/// </summary>
public static Action<JsonTypeInfo> ForType<T>(Action<JsonTypeInfo> modifier)
{
return typeInfo =>
{
if (typeInfo.Type == typeof(T))
{
modifier(typeInfo);
}
};
}

/// <summary>
/// Apply a modifier to multiple specific types
/// </summary>
public static Action<JsonTypeInfo> ForTypes(IEnumerable<Type> types, Action<JsonTypeInfo> modifier)
{
var set = new HashSet<Type>(types);

return typeInfo =>
{
if (set.Contains(typeInfo.Type))
{
modifier(typeInfo);
}
};
}

/// <summary>
/// Apply a modifier to a type and all types assignable to it (base class / interface)
/// </summary>
public static Action<JsonTypeInfo> ForAssignableTo<TBase>(Action<JsonTypeInfo> modifier)
{
return typeInfo =>
{
if (typeof(TBase).IsAssignableFrom(typeInfo.Type))
{
modifier(typeInfo);
}
};
}

/// <summary>
/// Combine multiple modifiers into one
/// </summary>
public static Action<JsonTypeInfo> Combine(params Action<JsonTypeInfo>[] modifiers)
{
return typeInfo =>
{
foreach (var modifier in modifiers)
{
modifier(typeInfo);
}
};
}
}
7 changes: 3 additions & 4 deletions Shared/Serialisation/StringSerialiser.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Options;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -7,7 +8,6 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;

namespace Shared.Serialisation;

Expand All @@ -18,7 +18,6 @@ public enum SerialiserPropertyFormat
}
public record SerialiserOptions(SerialiserPropertyFormat PropertyFormat, Boolean IgnoreNullValues = true, Boolean WriteIndented = false);


public interface IStringSerialiser {
string Serialize<T>(T obj, SerialiserOptions serialiserOptions= null);
T Deserialize<T>(string json, SerialiserOptions serialiserOptions = null);
Expand Down Expand Up @@ -205,4 +204,4 @@ public static T GetValue<T>(String json, String propertyName, SerialiserOptions
if (!IsInitialised) throw new InvalidOperationException(NotInitialisedErrorMessage);
return Serializer.GetValue<T>(json, propertyName);
}
}
}
Loading