Matic Cavalleri
Matic Cavalleri

Reputation: 57

.NET5 Web Api how to allow Guid in any format

I have a Dto that looks like this:

    public class CreateObjectDto
    {
        public Guid SomeGuid { get; set; }
    }

problem I'm having is that default Guid converter does not allow values outside "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx" format, so users are required to enter Guid with dashes which is not desirable. I would like an option to parse any regular Guid whether it has dashes or not.

Error if I call api with different Guid format is:

{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "traceId": "00-1714eba1650b1548afd8581204d38a0c-ffc921fac3022540-00",
  "errors": {
    "$.attachmentList[0].documentId": [
      "The JSON value could not be converted to System.Guid. Path: $.attachmentList[0].documentId | LineNumber: 0 | BytePositionInLine: 292."
    ]
  }
}

EDIT with solution (modified accepted solution a bit):

CustomGuidConverter:

    public class CustomGuidConverter : JsonConverter<Guid>
    {
        public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (!Guid.TryParse(reader.GetString(), out var parsedGuid))
            {
                throw new Exception($"Unable to parse {reader.GetString()} to GUID");
            }
            return parsedGuid;
        }

        public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options)
            => writer.WriteStringValue(value.ToString("D"));
    }

startup.cs:

// add this line to apply conversion globally and not only for one property
services.AddMvc().AddJsonOptions(opts =>
{
    opts.JsonSerializerOptions.Converters.Add(new CustomGuidConverter());
});

Upvotes: 2

Views: 1162

Answers (1)

kipy
kipy

Reputation: 642

You have to use a custom JsonConverter https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-6-0 for the given type (Guid)

public class CustomGuidJsonConverter : JsonConverter<Guid>
{
    private Regex _uwCharsRegex = new Regex("[ \t-]");
    private Regex _validityRegex = new Regex("[a-f0-9]{32}");

    public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string value = _uwCharsRegex.Replace(reader.GetString(), "").ToLower();

        // Check validity
        if (!_validityRegex.IsMatch(value))
        {
            return Guid.Empty; // or throw exception
        }

        return new Guid(value);
    }

    public override void Write(Utf8JsonWriter writer, Guid guidValue, JsonSerializerOptions options)
        => writer.WriteStringValue(guidValue.ToString());
}

Then you can use it by annoting the wanted Guid property.

public class CreateObjectDto
{
    [JsonConverter(typeof(CustomGuidJsonConverter))]
    public Guid SomeGuid { get; set; }
}

Upvotes: 1

Related Questions