ardalis/SmartEnum

Using with FastEndpoints

MarkLFT opened this issue · 2 comments

I like the idea of SmartEnums, but I am unable to find a straightforward way to make them work with FastEndpoints. Although the projects builds, when I try to pass a Dto that contains a SmartEnum, an error is thrown with regards to being unable to deserialise the Dto, and the error points to the SmartEnum.

Has anyone found a simple or straightforward way to do this?

I have noticed on both this and the FastEndPoints Githubs that there are several posts regarding this combination causing issues, but none seem to provide a clean solution.

@ardalis I notice you seem to favour FastEndpoints, so perhaps you have a project or something you could share on how to use them together. Thanks

We are using SmartEnum with FastEndpoints
we have an enum for sort order

public sealed class SortOrder : SmartEnum<SortOrder, string>
{
    public static readonly SortOrder Asc = new(nameof(Asc), nameof(Asc));
    public static readonly SortOrder Desc = new(nameof(Desc), nameof(Desc));

    /// <summary>Gets an item associated with the specified value. Parses SmartEnum when used as query params</summary>
    /// <see href="https://github.com/ardalis/SmartEnum/issues/410#issuecomment-1686057067">this issue</see>
    /// <param name="value">The value of the item to get.</param>
    /// <param name="result">
    /// When this method returns, contains the item associated with the specified value, if the value is found;
    /// otherwise, <c>null</c>. This parameter is passed uninitialized.</param>
    /// <returns>
    /// <c>true</c> if the <see cref="SortOrder" /> contains an item with the specified name; otherwise, <c>false</c>.
    /// </returns>
    public static bool TryParse(string value, out SortOrder result)
    {
        return TryFromValue(value, out result);
    }

    private SortOrder(string name, string value) : base(name, value)
    {
    }
}

register the converters for your smart enums

app.UseFastEndpoints(x =>
{
    x.Errors.UseProblemDetails();
    x.Endpoints.Configurator = ep =>
    {
        ep.PreProcessor<CurrentUserInjector>(Order.Before);
    };
    ...
    x.Serializer.Options.Converters.Add(new SmartEnumValueConverter<SortOrder, string>());
    ...
    x.Serializer.Options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});

Decorate the property in your request (it might work without JsonConverter if it is in the body of POST/PUT)

public class BaseSortPaginatedRequest
{
    [QueryParam]
    [JsonConverter(typeof(SmartEnumNameConverter<SortOrder, string>))]
    public SortOrder? SortOrder { get; set; }
}

Decorate with [JsonConverter(typeof(SmartEnumNameConverter<SortOrder, string>))] the responses as well.

@idormenco Thanks for the feedback. I came across this also. I have added a pull request to update the documents to show this is needed for System.Text.Json also, and not just with Newtonsoft which is what the documentation implies.