3

I am facing a weird issue maybe I am doing something wrong here. So I am working on WebApi Project using .Net Core 2.2. And In that I am calling Api from another server and I am parsing the response into this Model.

 public class LoginResponseModel
{
    [JsonProperty(PropertyName = "token_type")]
    public string tokenType { get; set; }

    [JsonProperty(PropertyName = "access_token")]
    public string accessToken { get; set; }

    [JsonProperty(PropertyName = "expires_in")]
    public string expiresIn { get; set; }

    [JsonProperty(PropertyName = "refresh_token")]
    public string refreshtToken { get; set; }
}

As from above model you can see from Api I am getting response in SnakeCase and I my model parameters are in CamelCase. When I Deserialize my Api Response:

 T1 responseModel = JsonConvert.DeserializeObject<T1>(await response.Content.ReadAsStringAsync());

Here T1 is LoginResponseModel And it successfully parse the Api Response in my model, see the attached screenshot, enter image description here

But when I call my Api which is calling another api whose response I just parsed (above example) the response returned is in SnakeCase. See ScreenShot enter image description here

Clarification Just to clarify Mobile App calls my Api i.e Login() and than my Login Methods calls another Api from another server i.e AuthenticateUser(...). So response of AuthenticateUser is SnakeCase which I am parsing into my LoginResponseModel and than that response is returned as Login api response. But than I am getting response with SnakeCase

Can someone please tell me what I am missing here or what can be done to fix that. I don't want to use another Model to transform to my desired response.

Update @Darkonekt Answer helped me, but now I am facing another issue in Serialization & Deserialization. So this is my Generic Method for PostAsync

private async Task<object> PostAsync<T1,T2>(string uri, T2 content)
    {
        using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, uri))
        {
            var json = JsonConvert.SerializeObject(content);
            using (var stringContent = new StringContent(json, Encoding.UTF8, "application/json"))
            {
                requestMessage.Content = stringContent;

                HttpResponseMessage response = await _client.SendAsync(requestMessage);
                if (response.IsSuccessStatusCode)
                {
                    _logger.LogInformation("Request Succeeded");
                    var dezerializerSettings = new JsonSerializerSettings
                    {
                        ContractResolver = new DefaultContractResolver
                        {
                            NamingStrategy = new SnakeCaseNamingStrategy()
                        }
                    };
                    T1 responseModel = JsonConvert.DeserializeObject<T1>(await response.Content.ReadAsStringAsync(), dezerializerSettings);
                    return  responseModel;
                }
                else
                {
                    return await GetFailureResponseModel(response);

                }
            }
        }
    }

As this Method is generic and will be used for any other Post Request, but as here I am setting Deserializer as SnakeCase and it works fine when api response is in SnakeCase, but issue occurs when my other Post Request returns response in CamelCase. I am getting Null values as parsing fails. How can I fix this issue as well.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Shabir jan
  • 2,295
  • 2
  • 23
  • 37
  • You can try this method of creating a mapping class from this post https://stackoverflow.com/a/31484563/9448191 – Kaizer69 Apr 19 '19 at 15:41
  • You need a new model without the attributes so that it uses the property names. and map to that model before returning the result. – Jonathan Alfaro Apr 19 '19 at 15:45
  • As i mentioned in my question, don’t want to use other model for transforming response. – Shabir jan Apr 19 '19 at 16:26
  • @Shabirjan you have only two choices: 1 Remap before returning or 2 a contract serializer. Other than that there is not much you can do. – Jonathan Alfaro Apr 19 '19 at 16:49
  • @Shabirjan as for part two of your question. You can can multiple contract resolvers and settings.... Then based on the API you are calling you can choose one or the other. – Jonathan Alfaro Apr 21 '19 at 01:57

1 Answers1

1

The [JsonProperty(PropertyName = "refresh_token")] Attribute is a two way street.

It is applied when serializing and when deserializing.

If you want to have a different name on serialization you will need ContractResolver and your own settings.

Look at this stackoverflow question on details how to do it: Serialize and Deserialize with different property names

Or you will need to create two models one for serialization and one for deserialization and map between them and then return the model that has no attributes.

Jonathan Alfaro
  • 4,013
  • 3
  • 29
  • 32
  • thanks. But for me Deserialization is working fine. Issue is when i return that response. That’s when camelcase values are converted into snakecase. – Shabir jan Apr 19 '19 at 16:31
  • @Shabirjan I corrected my answer. The point is when you "return" that response the Json serializer uses that same attribute to serialize the response. My answer is correct. Just look at the link I provided. – Jonathan Alfaro Apr 19 '19 at 16:44
  • @Shabirjan That Attribute you are using is applied when deserializing and ALSO when serializing! That is why your API returns that json; because it has to serialize the class before returning it. So if you want to return something different you have to do one of the two options I provided in my answer. Either "mapping" to a new class before returning the object or using a contract resolver. – Jonathan Alfaro Apr 19 '19 at 16:46
  • 1
    Ok the link you provided did helped me, I used SnakeCase strategy while using desearlization and i removed JSONProperty Annotations. Now I have another confusion right now this one api returned response in SnakeCase but all other Api return camelCase response. And I have wrote generic method for api parsing. So If i am setting deserialization as SnakeCase and My Api returns CamelCase will there be any issue? – Shabir jan Apr 20 '19 at 06:25
  • Please check Updated section in my question. – Shabir jan Apr 20 '19 at 09:06
  • @Shabirjan you can have different Contract Resolvers and settings for each scenario (each API) and apply these accordingly. – Jonathan Alfaro Apr 21 '19 at 01:55
  • I know but as I updated my question you can see i have a generic post method. How can i use different settings in that generic method. – Shabir jan Apr 21 '19 at 05:37
  • @Shabirjan you could add an extra parameter with an Enum that represents the different "kinds" of serialization your system supports. The caller of the Post method is responsible for telling it what serialization/deserialization strategy to use. then you can switch on that parameter to choose the correct contract resolver. – Jonathan Alfaro Apr 21 '19 at 14:43