Search code examples
c#asp.net-coreasp.net-core-2.2

How to configure controller to return null instead of Guid.Empty?


To make developers of frontend for my ASP.Net Core 2.2 API life easier, I would like them to receive "null" instead of Guid.Empty value (defined in .net core as "00000000-0000-0000-0000-000000000000").

It's not complicated to achieve this behaviour by creating dtos like this:

public class ExampleDto
{
    public Guid? Id { get; set; }
}

and then mapping them like this

public static void MapExampleEntity(this AutoMapperProfile profile)
{
    profile.CreateMap<ExampleEntity, ExampleDto>()
    .ForMember(dto => dto.Id, o => o.MapFrom(e => e.Id == Guid.Empty ? null : e.Id);
}

however, that's a lot of code duplication for task I feel controllers should be able to handle with some configuration. Is it possible to achieve this behaviour by default?

Edit to further specify my problem (I received several working solutions, but I don't feel like any of them is 100% clean way to achieve what I want to do):

I know that the general movement is to leave null and that is also the reason why I don't want to pollute my code with nulls. I would like to keep my dtos in this form:

public class ExampleDto
{
    public Guid Id { get; set; }
}

instead of this form:

public class ExampleDto
{
    public Guid? Id { get; set; }
}

to avoid infinite HasValue() checks. Hovewer, I think that it is far more informative and consistent to return this (see customerId):

{
"Id": "b3431f4d-ef87-4fb5-83e0-995a9e7c9f6a",
"Name": "A001",
"Description": null,
"Currency": null,
"CustomerId": null,
"Customer": null,
"CountryIso": 2
}

than this:

{
"Id": "b3431f4d-ef87-4fb5-83e0-995a9e7c9f6a",
"Name": "A001",
"Description": null,
"Currency": null,
"CustomerId": "00000000-0000-0000-0000-000000000000",
"Customer": null,
"CountryIso": 2
}

which is current behaviour. Those are the reasons I would like to let the Guid.Empty => null mapping do the controller instead of AutoMapper (if this behaviour is possible).


Solution

  • Ok, no idea why I didn't found this solution before asking here, but I feel like it would be appropriate to write it here (since I already asked the question) for future developers that might face the same problem.

    It is indeed possible to format controller output without manually checking value in every Dto or add AutoMapper line to it's mapping configuration!

    First create class derived from JsonConverted like this:

       public class NullGuidJsonConverter : JsonConverter<Guid>
       {
          public override void WriteJson(JsonWriter writer, Guid value, JsonSerializer serializer)
          {
             writer.WriteValue(value == Guid.Empty ? null : value.ToString());
          }
    
          public override Guid ReadJson(JsonReader reader, Type objectType, Guid existingValue, bool hasExistingValue, JsonSerializer serializer)
          {
             var value = reader.Value.ToString();
             return reader.Value == null ? Guid.Empty : Guid.Parse(value);
          }
       }
    

    and then add this class to Mvc settings in Startup.cs

    services.AddMvc()
            .AddJsonOptions(options =>
                options.SerializerSettings.Converters.Insert(0, new NullGuidJsonConverter()))
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    

    And that's it! Controller is now handling conversion from Guid.Empty value to null!