Skip to content
Draft
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 @@ -68,7 +68,9 @@ public CreateLabelFromShipmentDetailsTest()
}
}
},
ValidateAddress = ValidateAddress.ValidateAndClean
ValidateAddress = ValidateAddress.ValidateAndClean,
LabelLayout = LabelLayout.FourBySix,
LabelFormat = LabelFormat.ZPL
};
}

Expand Down Expand Up @@ -154,6 +156,7 @@ public async Task ValidCreateLabelFromShipmentDetailsTest()
[Fact]
public void TestParamsSerialization()
{
LabelParams.LabelLayout = "A4";
string labelParamsString = JsonSerializer.Serialize(LabelParams, new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
Expand All @@ -170,8 +173,9 @@ public void TestParamsSerialization()

Assert.Equal("John Doe", parsedJson["shipment"]["ship_from"]["name"].ToString());
Assert.Equal("delivery_mailed", parsedJson["shipment"]["confirmation"].ToString());
Assert.Null(parsedJson["label_layout"]);
Assert.Null(parsedJson["label_format"]);
Assert.Equal("A4", parsedJson["label_layout"].ToString());
Assert.Equal("zpl", parsedJson["label_format"].ToString());
Assert.Null(parsedJson["display_scheme"]);
}


Expand Down
15 changes: 5 additions & 10 deletions ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/Params.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,32 +43,27 @@ public class Params
/// <summary>
/// The possible validate address values
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter))]
public ValidateAddress? ValidateAddress { get; set; }
public StringEnum<ValidateAddress> ValidateAddress { get; set; }

/// <summary>
/// There are two different ways to download a label:
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter))]
public LabelDownloadType? LabelDownloadType { get; set; }
public StringEnum<LabelDownloadType> LabelDownloadType { get; set; }

/// <summary>
/// The file format that you want the label to be in. We recommend pdf format because it is supported by all carriers, whereas some carriers do not support the png or zpl formats.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter))]
public LabelFormat? LabelFormat { get; set; }
public StringEnum<LabelFormat> LabelFormat { get; set; }

/// <summary>
/// The display format that the label should be shown in.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter))]
public DisplayScheme? DisplayScheme { get; set; }
public StringEnum<DisplayScheme> DisplayScheme { get; set; }

/// <summary>
/// The layout (size) that you want the label to be in. The labelFormat determines which sizes are allowed. 4x6 is supported for all label formats, whereas letter (8.5" x 11") is only supported for pdf format.
/// </summary>
[JsonConverter(typeof(JsonStringEnumMemberConverter))]
public LabelLayout LabelLayout { get; set; }
public StringEnum<LabelLayout> LabelLayout { get; set; }

/// <summary>
/// The label image resource that was used to create a custom label image.
Expand Down
90 changes: 90 additions & 0 deletions ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/StringEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#nullable disable
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;

[JsonConverter(typeof(StringEnumJsonConverterFactory))]
public class StringEnum<T> where T : struct
{

public StringEnum(string value)
{
if (Enum.TryParse(value, out T parsed))
{
IsValidEnum = true;
EnumValue = parsed;
}
StringValue = value;
}

public StringEnum(T value)
{
EnumValue = value;
IsValidEnum = true;
StringValue = typeof(T)
.GetTypeInfo()
.DeclaredMembers
.SingleOrDefault(x => x.Name == value.ToString())
?.GetCustomAttribute<EnumMemberAttribute>(false)
?.Value ?? value.ToString();
}

public T EnumValue { get; }
public string StringValue { get; }
public bool IsValidEnum { get; }

public static implicit operator StringEnum<T>(T e) => new(e);
public static implicit operator StringEnum<T>(string s) => new(s);
public static implicit operator T(StringEnum<T> se) => se.IsValidEnum ? se.EnumValue : throw new InvalidOperationException($"The custom value {se.StringValue} cannot be represented as a {typeof(T).Name}.");
public static implicit operator string(StringEnum<T> se) => se.StringValue;
}

public class StringEnumJsonConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
return typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(StringEnum<>);
}

public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options)
{
Type[] typeArguments = type.GetGenericArguments();
Type enumType = typeArguments[0];


JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(StringEnumConverter<>).MakeGenericType(
[enumType]),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: [options],
culture: null)!;

return converter;
}
}
public class StringEnumConverter<T> : JsonConverter<StringEnum<T>> where T : struct
{
private readonly JsonConverter<T> _valueConverter;
private readonly JsonConverter<string> _stringConverter;

public StringEnumConverter(JsonSerializerOptions options)
{
_stringConverter = (JsonConverter<string>)options.GetConverter(typeof(string));
}

public override StringEnum<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
string readValue = _stringConverter.Read(ref reader, typeToConvert, options);
return new StringEnum<T>(readValue);
}

public override void Write(Utf8JsonWriter writer, StringEnum<T> value, JsonSerializerOptions options)
{
_stringConverter.Write(writer, value.StringValue, options);
}

}