Search code examples
c#.net-coredotnet-httpclient

StringContent(json) vs JsonContent.Create(obj)


This works:

var json = JsonConvert.SerializeObject(obj);
var content = new StringContent(json);
var httpResponse = await httpClient.PostAsync("", content);
// 200 OK

This doesn't:

var content = JsonContent.Create(obj);
var httpResponse = await httpClient.PostAsync("", content);
// 500 Internal Server Error

Does JsonContent serialize or encode the content differently? Are there serialization options that might make the second example behave like the first?

I know I can use the first, but I am trying to understand why the 2nd isn't working.

Object definitions:

var obj = new AccountLookupService.GetUserOnlineProfileRequest
{
    ContractAccountNumber = "100087751101",
    Address = new ServiceAddress
    {
        HouseNumber = string.Empty,
        StreetName = string.Empty,
        HouseNumberSupplement = string.Empty,
        City = string.Empty,
        State = string.Empty,
        ZipCode = "48386",
    },
    Phone = string.Empty,
    Name = string.Empty,
};

And...

public class GetUserOnlineProfileRequest
{
    public string? ContractAccountNumber { get; set; }
    public ServiceAddress? Address { get; set; }
    public string? Phone { get; set; }
    public string? Name { get; set; }
    public int AccountLimit { get; set; } = 10;
}

And...

public class ServiceAddress
{
    public string? HouseNumber { get; set; }
    public string? StreetName { get; set; }
    public string? HouseNumberSupplement { get; set; }
    public string? City { get; set; }
    public string? State { get; set; }
    public string? ZipCode { get; set; }
}

Solution

  • I set up the following test to compare the default serialization of the two serializers:

    [Fact]
    public async Task CompareSerializers()
    {
        var jsonContent = JsonContent.Create(obj);
        var ms = await jsonContent.ReadAsStringAsync();
    
        var json = JsonConvert.SerializeObject(obj);
        var stringContent = new StringContent(json);
        var ns = await stringContent.ReadAsStringAsync();
    
        Assert.Equal(ms, ns);
    }
    

    And this was the result:

    ms: {"contractAccountNumber":"100087751101","ad···
    ns: {"ContractAccountNumber":"100087751101","Ad···

    The two were identical in every way except that the System.Text.Json serializer camelCased the property names, whereas Newtonsoft.Json did not.

    Strangely, just setting JsonSerializerOptions.Default made the two strings identical.

    var jsonContent = JsonContent.Create(obj, options: JsonSerializerOptions.Default);
    

    ms: {"ContractAccountNumber":"100087751101","Ad···
    ns: {"ContractAccountNumber":"100087751101","Ad···

    So, it appears that JsonContent.Create(obj) does not use JsonSerializerOptions.Default by default.

    😵

    UPDATE: As expected, this also preserves PascalCase and works with the service I am calling...

    var httpResponse = await httpClient.PostAsJsonAsync("", obj, options: JsonSerializerOptions.Default);