diff --git a/ShipEngine.Tests/ShipEngineMethodTests/CreateLabelFromShipmentDetailsTest.cs b/ShipEngine.Tests/ShipEngineMethodTests/CreateLabelFromShipmentDetailsTest.cs
index d810f87a..52e0f79a 100644
--- a/ShipEngine.Tests/ShipEngineMethodTests/CreateLabelFromShipmentDetailsTest.cs
+++ b/ShipEngine.Tests/ShipEngineMethodTests/CreateLabelFromShipmentDetailsTest.cs
@@ -68,7 +68,9 @@ public CreateLabelFromShipmentDetailsTest()
}
}
},
- ValidateAddress = ValidateAddress.ValidateAndClean
+ ValidateAddress = ValidateAddress.ValidateAndClean,
+ LabelLayout = LabelLayout.FourBySix,
+ LabelFormat = LabelFormat.ZPL
};
}
@@ -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,
@@ -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"]);
}
diff --git a/ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/Params.cs b/ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/Params.cs
index 53207ad7..58682241 100644
--- a/ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/Params.cs
+++ b/ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/Params.cs
@@ -43,32 +43,27 @@ public class Params
///
/// The possible validate address values
///
- [JsonConverter(typeof(JsonStringEnumMemberConverter))]
- public ValidateAddress? ValidateAddress { get; set; }
+ public StringEnum ValidateAddress { get; set; }
///
/// There are two different ways to download a label:
///
- [JsonConverter(typeof(JsonStringEnumMemberConverter))]
- public LabelDownloadType? LabelDownloadType { get; set; }
+ public StringEnum LabelDownloadType { get; set; }
///
/// 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.
///
- [JsonConverter(typeof(JsonStringEnumMemberConverter))]
- public LabelFormat? LabelFormat { get; set; }
+ public StringEnum LabelFormat { get; set; }
///
/// The display format that the label should be shown in.
///
- [JsonConverter(typeof(JsonStringEnumMemberConverter))]
- public DisplayScheme? DisplayScheme { get; set; }
+ public StringEnum DisplayScheme { get; set; }
///
/// 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.
///
- [JsonConverter(typeof(JsonStringEnumMemberConverter))]
- public LabelLayout LabelLayout { get; set; }
+ public StringEnum LabelLayout { get; set; }
///
/// The label image resource that was used to create a custom label image.
diff --git a/ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/StringEnum.cs b/ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/StringEnum.cs
new file mode 100644
index 00000000..dba2ebd5
--- /dev/null
+++ b/ShipEngine/Models/Dto/CreateLabelFromShipmentDetails/StringEnum.cs
@@ -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 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(false)
+ ?.Value ?? value.ToString();
+ }
+
+ public T EnumValue { get; }
+ public string StringValue { get; }
+ public bool IsValidEnum { get; }
+
+ public static implicit operator StringEnum(T e) => new(e);
+ public static implicit operator StringEnum(string s) => new(s);
+ public static implicit operator T(StringEnum 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 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 : JsonConverter> where T : struct
+{
+ private readonly JsonConverter _valueConverter;
+ private readonly JsonConverter _stringConverter;
+
+ public StringEnumConverter(JsonSerializerOptions options)
+ {
+ _stringConverter = (JsonConverter)options.GetConverter(typeof(string));
+ }
+
+ public override StringEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ string readValue = _stringConverter.Read(ref reader, typeToConvert, options);
+ return new StringEnum(readValue);
+ }
+
+ public override void Write(Utf8JsonWriter writer, StringEnum value, JsonSerializerOptions options)
+ {
+ _stringConverter.Write(writer, value.StringValue, options);
+ }
+
+}
\ No newline at end of file