1

I have a request (going to an APIM endpoint.) From Postman the test runs just fine, but from my code it fails with a 400. I looked at the requests in fiddler and the only difference is this:

 // This works
 Content-Type: application/json

 // This gives a 400
 Content-Type: application/json; charset=utf-8

APIM is supposed to use UTF-8 by default, so I don't understand. Plus there doesn't seem to be a way within the C# code to produce the first. If I try to add the header directly it complains that I need to add it as part of the content string. So I have this:

  requestMessage.Content = new StringContent(content, Encoding.UTF8, "application/json");

This produces the second Content-Type header. There seems to be no overload on the StringContent class to allow me to produce the first version (without specifying the encoding.)

I'm stuck. It seems a really simply problem but I don't see a way to get through all the "helper" code that Microsoft has put in place to get what I need.

Insofar as it matters I am running .net8.

Any suggestions?

7
  • 1
    How about if you clear the CharSet? content.Headers.ContentType.CharSet = null Commented Nov 4 at 8:12
  • What is APIM? What you describe sounds like a service bug. Also, why are you serializing manually instead of using eg PostAsJsonAsync ? Or use JsonContent ? JsonContent.Create allows you to set your own MediaTypeHeaderValue Commented Nov 5 at 13:38
  • @Magnus that seemed to work, thanks. Commented Nov 5 at 14:17
  • @PanagiotisKanavos APIM is a component of Azure for creating APIs and I am not serializing manually, I am looking at the output the regular libraries produce. Commented Nov 5 at 14:19
  • What's the exact name? Almost certainly, it has a C# SDK. I am not serializing manually if you generate a string from your DTO and send it as a StringContent , you are. You can just post your DTO so why don't you? Was there a problem? Commented Nov 5 at 14:23

2 Answers 2

1

Need to clear the headers and then set them:

var stringContent = new StringContent(content);
stringContent.Headers.Clear();
stringContent.Headers.ContentType = new MediaTypeHeaderValue(MediaTypeNames.Application.Json);

requestMessage.Content = stringContent;

Here is a unit test you can run debugger on that will return the result you want.

[Fact]
public void TestStringContentHeaders()
{
    var stringContent = new StringContent(string.Empty);
    stringContent.Headers.Clear();
    stringContent.Headers.ContentType = new MediaTypeHeaderValue(MediaTypeNames.Application.Json);
    Assert.Equal("application/json", stringContent.Headers.ContentType?.MediaType);
    Assert.Null(stringContent.Headers.ContentType?.CharSet);
}
Sign up to request clarification or add additional context in comments.

Comments

0

It's unclear what APIM means, why that service complains or why the code uses manual serialization to a string. JSON must be UTF8 so charset has no effect and should be ignored by the recipient. RFC-8259 says :

Note: No "charset" parameter is defined for this registration. Adding one really has no effect on compliant recipients.

Instead of manually serializing to a string you can use JsonContent.Create with an explicit MediaTypeHeaderValue value that doesn't include charset.


var myDTO=...;
var jsonType=new MediaTypeHeaderValue("application/json");
requestMessage.Content = JsonContent.Create(myDTO, jsonType);

You don't have to clear the headers, you just pass the headers you actually want.

If APIM means the Azure API Management, there's a .NET SDK for it with a Quickstart in Github. Admittedly, a Quickstart isn't enough documentation. Using the SDK means you don't have to manually create DTOs and serialize them.

The Quickstart page shows how you can create a resource for example :

using System;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.Compute;
using Azure.ResourceManager.Resources;

// Code omitted for brevity

// First, initialize the ArmClient and get the default subscription
ArmClient client = new ArmClient(new DefaultAzureCredential());
// Now we get a ResourceGroupResource collection for that subscription
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();

// With the collection, we can create a new resource group with an specific name
string resourceGroupName = "myRgName";
AzureLocation location = AzureLocation.WestUS2;
ResourceGroupData resourceGroupData = new ResourceGroupData(location);
ArmOperation<ResourceGroupResource> operation = await resourceGroups.CreateOrUpdateAsync(WaitUntil.Completed, resourceGroupName, resourceGroupData);
ResourceGroupResource resourceGroup = operation.Value;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.