3

I have a .NET Core 2.0 WebApi application in which I have added the "Flurl.Http" (Version 2.1.0) NuGet package to my project.

I am trying to use Flurl to make a simple REST API call to one of Visual Studio Team Services' (VSTS) Api endpoints.

However, the particular VSTS api endpoint that I am calling requires that the Content-Type be set to "application/json-patch+json" instead of the typical "application/json".

In my Flurl call, I am using the "WithHeader()" method to try and set the Content-Type in the header of the request, but it is not working. Flurl seems to not allow me to override the default or standard Content-Type that is built into the PostJsonAsync method.

Does anyone know how to change the Content-Type of the request using Flurl? Or how to properly override the default behavior of the Content-Type in the Flurl configuration?

Thanks in advance!

My code:

public bool CreateNewBug(NewBugRequest newBugRequest)
{
    return _apiUrlToCreateNewBug.WithHeader("Authorization", "Basic Base64PersonalAccessTokenGoesHere")
                                .WithHeader("Content-Type", "application/json-patch+json")
                                .PostJsonAsync(newBugRequest.Fields)
                                .Result
                                .IsSuccessStatusCode;
}

(This code works, but the response from the VSTS api is that the Content-Type is not allowed and needs to be changed to "application/json-patch+json", which is what I tried to set it to in the header.)

Tseng
  • 61,549
  • 15
  • 193
  • 205
Chase Harrison
  • 160
  • 1
  • 10
  • Please take a minute and read [What are tags, and how should I use them?](https://stackoverflow.com/help/tagging) to avoid people skip over your questions when you stuff it with tags. – Tseng Dec 06 '17 at 19:07

3 Answers3

4

New answer: Upgrade to the latest Flurl.Http. The issue has been fixed in 2.3.1, so the code posted in the question (the cleanest approach) should actually work as expected now.

Todd Menier
  • 37,557
  • 17
  • 150
  • 173
3

UPDATE: The bug is fixed as of Flurl.Http 2.3.1, so this work-around is no longer necessary.

The short answer is I think you've discovered a bug. PostJsonAsync does set the Content-Type header, but I think it should leave it alone if you've already set it yourself. If you could report it here I should be able to get it fixed for the next release.

The work-around is fairly straightforward. You just need to take a couple extra steps to build the content and then post it using PostAsync instead of PostJsonAsync.

var json = FlurlHttp.GlobalSettings.JsonSerializer.Serialize(newBugRequest.Fields);
var content = new CapturedStringContent(json, Encoding.UTF8, "application/json-patch+json");

return _apiUrlToCreateNewBug
    .WithHeader("Authorization", "Basic Base64PersonalAccessTokenGoesHere")
    .PostAsync(content);

If you need to do this a lot, you could wrap it up in an extension method (PostJsonPatchAsync or similar) so you can call it fluently. See here for the correct way to do that.

Todd Menier
  • 37,557
  • 17
  • 150
  • 173
0

I was able to figure it out and find a working solution to my problem.

Here is the updated version of my working code:

public HttpResponseMessage CreateNewBug(NewBugRequest newBugRequest)
{
    return _apiUrlToCreateNewBug.AllowAnyHttpStatus()
                                .WithBasicAuth("", _personalAccessTokenForBasicAuth)
                                .PostAsync(new StringContent(JsonConvert.SerializeObject(newBugRequest.Fields), Encoding.UTF8, "application/json-patch+json"))
                                .Result;
}

The PostAsync method takes in an HttpContent object. HttpContent is an abstract class. Once I figured out all the concrete classes that implement the abstract class HttpContent, then I chose the one that best fit my situation and plugged it into the PostAsync method.

In this case, the StringContent class was the one that best fit what I needed. One of StringContent's constructors takes in the Content-Type as one of its parameters. So I passed in my custom Content-Type and everything worked as expected.

Chase Harrison
  • 160
  • 1
  • 10
  • 1
    That's more or less the same solution. The main difference is that mine uses Flurl objects `CapturedStringContent`, which allows better diagnostics from `FlurlHttpException` because you have access to the request body, and `GlobalSettings`, just in case you made any tweaks to the default JSON searializer. – Todd Menier Dec 09 '17 at 16:08