dotnet-sdk icon indicating copy to clipboard operation
dotnet-sdk copied to clipboard

Losing Precision of double value over 6 decimal places when PublishEventAsync is called

Open beakersoft opened this issue 3 years ago • 4 comments

Expected Behavior

Publishing a model containing double values via PublishEventAsync shouldn't lose any precision.

Actual Behavior

We are dealing with some lat/longs in our codebase as doubles. They are sometimes accurate to 9 decimal places. The model containing these properties gets sent via PublishEventAsync, but when they hit the handler the double values are always getting rounded to 6 decimal places.

Steps to Reproduce the Problem

Example Call

public class DeliveryRequest
{
        public double DeliveryLocationLatitude { get; set; }
        public double DeliveryLocationLongitude { get; set; }
}

var model = new DeliveryRequest 
{
    DeliveryLocationLatitude = 53.7886918m
    DeliveryLocationLongitude = -2.2299881m
}

await _daprClient.DaprClient.PublishEventAsync("pubsub", "UpdateDeliveryEvent", new UpdateDeliveryEvent(model), cancellationToken);

On the handler side when the model hit, the DeliveryLocationLatitude and DeliveryLocationLongitude properties have both been rounded to 6 decimal places, so they now look like

DeliveryLocationLatitude = 53.788692m
DeliveryLocationLongitude = -2.229988m

We have managed to get around this by creating a custom json converter to use on those 2 fields in the model, which writes the value out like so

public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
{
    writer.WriteStringValue(value.ToString("G17", CultureInfo.InvariantCulture));
}

While this does work, its not ideal and probably should not be required?

beakersoft avatar Apr 12 '22 10:04 beakersoft

@beakersoft - Is the ask here to allow full precision by default? If I had to guess, the default encoding truncates it to make it a more consistent parsing experience on the read side.

Instead of creating a customer parser, have you considered saving it as a string in your message? That'd guarantee the raw value and leave all the encoding/decoding responsibility to your code which gives you more control.

halspang avatar Apr 19 '22 21:04 halspang

@beakersoft - this might be a silly question but just in case:

public class DeliveryRequest
{
        public double DeliveryLocationLatitude { get; set; }
        public double DeliveryLocationLongitude { get; set; }
}

var model = new DeliveryRequest 
{
    DeliveryLocationLatitude = 53.7886918m
    DeliveryLocationLongitude = -2.2299881m
}

Your DeliveryRequest type is defining these properties with double but your initialization of the properties is using decimal (-2.2299881m) literals. Did you mean to define the properties as decimals?

Also as-of .NET 5 there is an attribute you can use to get string-serialization without writing a converter https://docs.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonnumberhandlingattribute?view=net-6.0

rynowak avatar Apr 20 '22 03:04 rynowak

@beakersoft - Are you still having problems here?

halspang avatar Jun 21 '22 23:06 halspang

@halspang we've got around it by using the custom json converter, although it does feel a bit of a hack. We did think about just using a string, but again then feels a bit nasty as we would have to keep converting to/from the correct type

beakersoft avatar Jun 27 '22 10:06 beakersoft

@beakersoft - Since you've found a way to handle this, I'm going to close this issue. If you think this is worth a feature add, please feel free to reopen this issue or create a more specific one with the requested behavior.

halspang avatar Aug 29 '22 22:08 halspang