Capitalized handlers ignore custom serializers
I was surprised to find out that the following samples behave differently (given a request that accepts json):
// This uses my registered IJsonSerializer:
Successful.ok (json { x = 1 })
// This uses the default serializer:
Successful.OK { x = 1 }
I don't know if this is intentional or a bug, but it's at least unexpected.
Hi, this is not intended, so must be a bug. I'll have a look later tonight!
Can you show me how you configured your custom serializer?
I add a services.AddSingleton<IJsonSerializer, MySerializer>() to my ConfigureServices.
Here's a repro based on the default template: https://github.com/Tarmil/giraffe-411-repro
Looking into this it seems that both are using the registered IJsonSerializer but Successful.OK uses Content Negotiation and therefore might attempt to serialize the response in a different content type based on the client's accept headers.
We got bitten by this at $WORK yesterday, and after some investigation it turned out that it is indeed content negotiaton that causes the issue. In our specific instance, we had custom serializer options for a certain type, which were ignored. Interestingly, the configuration was respected when the type was returned as part of a collection, i.e.:
type Stuff = Stuff of string
// This ignored the serialization options
Succesful.OK (Stuff "problematic")
// This was fine
Succesful.OK [ Stuff "all good" ]
In any case, after some investigation, I noticed that the negotiate function defines responseObj with type obj, this is what trips the serializer.
https://github.com/giraffe-fsharp/Giraffe/blob/6fe39c21abdf85bf1e49db55a053342c42186e7f/src/Giraffe/Negotiation.fs#L174
I was able to copy the functions and add a type parameter instead of obj, which fixes the problem, but I was not able to make the whole content negotiation "pipeline" generic in Giraffe itself. I got stuck when registering INegotiationConfig and its default implementation, after having turned it into a generic type.
I suspect the fix for this issue is going to be a bit more involved than just slapping type parameters everywhere like I tried doing. :sweat_smile: