PostAsJsonAsync doesnt seem to post body parameters - c#

I have created an Azure logic app that exposes a REST endpoint.
The following JSON body works fine when I call it through postman.
{
"to": "ggtest#yahoo.com",
"subject": "Hello there",
"message": "Hello there!!!!!"
}
I'm able to see the incoming request formed nicely
{
"headers": {
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Accept": "*/*",
"Accept-Encoding": "gzip,deflate",
"Host": "maskedout.northcentralus.logic.azure.com:443",
"User-Agent": "PostmanRuntime/6.4.1",
"Content-Length": "99",
"Content-Type": "application/json"
},
"body": {
"to": "ggtest#yahoo.com",
"subject": "Hello there",
"message": "Hello there!!!!!"
}
}
However, when I try to make the same call using C# PostAsJsonAsync with this code:
var email = new Email
{
to = "gg#live.com.sg",
subject = "from webapp",
message = "hello world"
};
var client = new HttpClient();
var uri = "maskedout";
var response = await client.PostAsJsonAsync<Email>(uri, email);
I'm able to call my REST endpoint successfully, but it does not contain the body
This is the incoming request I see:
{
"headers": {
"Connection": "Keep-Alive",
"Transfer-Encoding": "chunked",
"Host": "maskedout.northcentralus.logic.azure.com",
"x-ms-request-root-id": "9e5513c2-43961642a3688718",
"x-ms-request-id": "|9e5513c2-43961642a3688718.1.",
"Request-Id": "|9e5513c2-43961642a3688718.1.1.",
"Content-Type": "application/json; charset=utf-8",
"Content-Length": "0"
}
}
What am I missing here? What's different in my C# code compared to postman?

I've just run into this problem too. The issue appears to be the Content-Length header. In Postman it is the length of the content but using HttpClient the length is 0 so I am guessing the endpoint is ignoring the body as it is being told it is empty.
I created my own extension to get around this:
public static async Task<HttpResponseMessage> PostJsonAsync<T>(
this HttpClient client,
string requestUri,
T value)
{
var data = JsonConvert.SerializeObject(value);
var content = new StringContent(data,
Encoding.UTF8,
MimeTypes.Json);
Debug.WriteLine(client.BaseAddress + requestUri);
return await client.PostAsync(requestUri,
content)
.WithRequestTimeout()
.ConfigureAwait(false);
}

I just had the same problem. It seems that the content-length header is set to 0 when using the default PostAsJsonAsync extension method, which causes the server to ignore the request body.
My solution was to install the System.Net.Http.Json nuget package that uses the new System.Text.Json serializer.
When you add using System.Net.Http.Json;, you should be able to use the new extension method PostAsJsonAsync that works (sets the content-length header) properly.
namespace System.Net.Http.Json
{
public static class HttpClientJsonExtensions
{
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this HttpClient client, string? requestUri, TValue value, CancellationToken cancellationToken)
{
return client.PostAsJsonAsync(requestUri, value, null, cancellationToken);
}
}
}

the TransferEncodingChunked header property should be false by default.
However, try this:
var email = new Email
{
to = "gg#live.com.sg",
subject = "from webapp",
message = "hello world"
};
var client = new HttpClient();
var uri = "maskedout";
client.DefaultRequestHeaders.TransferEncodingChunked = false;
var response = await client.PostAsJsonAsync<Email>(uri, email);

Related

Post request to Minimal API service with JSON body

I've got a minimal API service with a MapPost:
app.MapPost("/sendmessage", (RabbitMessage rm) => server.SendMessage(rm.exchange,
rm.routingkey, rm.message));
app.Run();
record RabbitMessage(string exchange, string routingkey, string message);
It works fine when sending a JSON with Postman:
{
"message": "msg",
"routingkey": "freestorage",
"exchange": "system"
}
But from a C# client:
var kv = new Dictionary<string, string> {
{ "exchange", "system" },
{ "routingkey", routingkey },
{ "message", message }
};
var content = new FormUrlEncodedContent(kv);
string contentType = "application/json";
if (Client.DefaultRequestHeaders.Accept.FirstOrDefault(hdr => hdr.MediaType == contentType) == default)
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
var response = await Client.PostAsync("sendmessage", content);
The response is UnsupportedMediaType. What is the proper way to send these values to minimal API? Or do I need to setup the API itself differently?
I don't think using FormUrlEncodedContent is the correct way as it is used for application/x-www-form-urlencoded MIME type.
Instead, you should pass the request body with StringContent and serialize the kv as content.
using System.Text;
using Newtonsoft.Json;
var stringContent = new StringContent(JsonConvert.SerializeObject(kv),
Encoding.UTF8,
"application/json");
var response = await Client.PostAsync("sendmessage", stringContent);

Trying to use Google TTS using HttpWebRequest but it doesn't work

I'm trying to use Google's TTS to convert a text to speech and I want to use HttpWebRequest for this, as I want to avoid any third-party clients. (This is because I'm practicing calling Web API's.) So I have this code:
HttpWebRequest requestVoices = (HttpWebRequest)WebRequest.Create($"https://texttospeech.googleapis.com/v1/voices?key={bearerKey}");
using StreamReader streamReader = new(requestVoices.GetResponse().GetResponseStream());
var voiceList = GoogleVoices.LoadFromJson(streamReader.ReadToEnd()).Sort();
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "Speaking.json"), voiceList.SaveAsJson());
This works fine. I get a list of all voices, ordered by gender, then name. So, being ambitious, I want to generate a sound file, using this configuration:
var sound = new SpeechConfig()
{
Input = new SpeechConfig.InputConfig(){Text = "Hello, World!"},
AudioConfig = new SpeechConfig.AudioSpeechConfig()
{
AudioEncoding = "MP3",
EffectsProfileId = new List<string>(){ "large-home-entertainment-class-device" },
Pitch = 0.0,
SpeakingRate = 1.0
},
Voice = new SpeechConfig.VoiceConfig()
{
Name = "en-IN",
LanguageCode = "en-IN-Wavenet-D"
}
};
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "Speak.json"), sound.SaveAsJson());
And to check if it generates proper JSON, this is what gets written to that file:
{
"AudioConfig": {
"AudioEncoding": "MP3",
"EffectsProfileId": [
"large-home-entertainment-class-device"
],
"Pitch": 0.0,
"SpeakingRate": 1.0
},
"Input": {
"Text": "Hello, World!"
},
"Voice": {
"LanguageCode": "en-IN-Wavenet-D",
"Name": "en-IN"
}
}
So, that looks good too. So now I need to call the TTS API, using this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://texttospeech.googleapis.com/v1/text:synthesize/");
request.Headers.Add("Authorization", $"Bearer {bearerKey}");
request.Headers.Add("Content-Type", "application/json; charset=utf-8");
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter streamWriter = new(request.GetRequestStream()))
{
streamWriter.Write(sound.SaveAsJson());
streamWriter.Flush();
streamWriter.Close();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string soundFileName= Path.Combine(Environment.CurrentDirectory, "Sound.mp3");
var soundFile = File.Create(soundFileName);
response.GetResponseStream().CopyTo(soundFile);
soundFile.Close();
But nothing gets written and I get the error: Unhandled exception. System.Net.WebException: The remote server returned an error: (401) Unauthorized. at System.Net.HttpWebRequest.GetResponse() at Program.<Main>$(String[] args)...
Now, I know the bearer key is correct as I get a list of voices.
Using Google gives me way too many results, most of which use third-party libraries or talk about the "Translate" API. So that's not very useful. So I used OpenAI (ChatGPT) to give me an example, which wasn't much different, but used this as url: "https://texttospeech.googleapis.com/v1/text:synthesize?key=YOUR_API_KEY&input.text=" + textToSynthesize;
Well, that doesn't work either. So, I tried this as something suggested it:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("Authorization", "Bearer $(gcloud auth print-access-token)");
request.Headers.Add("X-goog-api-key", $"{bearerKey}");
Still no luck. And there are no restrictions on this API key, except it's less than an hour old. Could it be that I just have to wait longer? Or am I doing something wrong? I must be doing something wrong, I think. I get the list of voices, but not the sound.
What am I doing wrong?
And I'm an idiot! :D This part:
"Voice": {
"LanguageCode": "en-IN-Wavenet-D",
"Name": "en-IN"
}
should be:
"Voice": {
"LanguageCode": "en-IN",
"Name": "en-IN-Wavenet-D"
}
Also, the JSON is case-sensitive...
Working code:
public async Task Speak(string filename, string bearerKey, string text)
{
string url = $"https://texttospeech.googleapis.com/v1/text:synthesize?key={bearerKey}";
var client = new HttpClient();
var context = new StringContent(Sound(text).SaveAsJson(), Encoding.UTF8, "application/json");
using HttpResponseMessage response = await client.PostAsync(url, context);
var result = AudioContent.LoadFromJson(await response.Content.ReadAsStringAsync());
File.WriteAllBytes(filename, System.Convert.FromBase64String(result.Content));
}
And yes, decided to use HttpClient() as it was easier. This method is part of a class that holds the voice data. Sound is created by:
public SpeechConfig Sound(string text) =>
new()
{
Input = new SpeechConfig.InputConfig()
{
Text = text
},
AudioConfig = new SpeechConfig.AudioSpeechConfig()
{
AudioEncoding = "MP3",
EffectsProfileId = new List<string>() { "large-home-entertainment-class-device" },
Pitch = Value.Pitch,
SpeakingRate = Value.SpeakingRate
},
Voice = new SpeechConfig.VoiceConfig()
{
Name = Value.Selection.Name,
LanguageCode = Value.Selection.LanguageCode
}
};
In the same class.

C# Amazon SP API CreateFeedDocument not working

There are 3 steps to upload a feed via Amazon SP API, the first one is to get feed encryption info via createFeedDocument API. But I am getting Bad Request as response with following content:
{
"errors": [
{
"code": "InvalidInput",
"message": "Invalid Input",
"details": ""
}
]
}
C# code
private async Task<IRestResponse> CreateFeedDocument()
{
IRestRequest restRequest = new RestRequest("feeds/2020-09-04/documents", Method.POST);
restRequest.AddParameter("contentType", "application/xml; charset=UTF-8", ParameterType.RequestBody);
restRequest.AddQueryParameter("MarketplaceIds", "A21TJRUUN4KGV");
restClient = new RestClient(live_url_base);
restRequest = await signRequest(restRequest, restClient);
return restClient.Execute(restRequest);
}
private async Task<IRestRequest> signRequest(IRestRequest restRequest, RestClient restClient)
{
var roleAcccess = await GetAssumeRoleTokenDetail();
restRequest.AddHeader("x-amz-access-token", accessToken);
AWSAuthenticationCredentials AWSCredentials = new AWSAuthenticationCredentials();
AWSCredentials.AccessKeyId = roleAcccess.Credentials.AccessKeyId;
AWSCredentials.SecretKey = roleAcccess.Credentials.SecretAccessKey;
AWSCredentials.Region = region;
restRequest.AddHeader("X-Amz-Security-Token", roleAcccess.Credentials.SessionToken);
return new AWSSigV4Signer(AWSCredentials).Sign(restRequest, restClient.BaseUrl.Host);
}
I doubt that I am not using restRequest.AddParameter properly, but I am not sure.
I have been following below links:
https://github.com/amzn/selling-partner-api-docs/blob/main/references/feeds-api/feeds_2020-09-04.md#createfeeddocument
https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/use-case-guides/feeds-api-use-case-guide/feeds-api-use-case-guide-2020-09-04.md#step-1-create-a-feed-document
How to Encrypt and upload data using selling-partner-api in Amzon using .net
Update
I also tried replacing below line
restRequest.AddParameter("contentType", "application/xml; charset=UTF-8", ParameterType.RequestBody);
with
restRequest.AddJsonBody(new { contentType = "text/xml; charset=UTF-8" });
but then I was getting InvalidSignature error as below:
{
"errors": [
{
"message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The Canonical String for this request should have been
'POST
/feeds/2020-09-04/documents
host:sellingpartnerapi-eu.amazon.com
x-amz-access-token:Atza|IwEBIA5KgrCsBbSXHmrXFS_FIgBTInh_xPAydLfi5q2P9xaFQf7p8Zl4NjqhHHxqRzUku__Q7GN1p2WQGRzuAoAa8oMkPLx57NJ05SqxEVXXG-fet3_XgKj8uBCU30HaGPsKltf4g2MD8Pqqt2OUrOXtkv4dAAjjCIxC-bFwVqOhvHktAur--NBv-bJaPZ608Av1GEu96GsNEV9eb0saVBwLaZD7NW3oOjzlCc8GPV9hdqHV5TUXY77QZgBLD1y94Vs1fSo54ShpyoMMOZebzbSr1K5gtf3wJZ.........................{ I hid it }...........................................
x-amz-date:20210524T175148Z
x-amz-security-token:FwoGZXIvYXdzEGsaDNUytY0xuP5/u61APiK2ARMZgv4IT+y2HLzdg5FjZOv6aL2bJ3baJPxBtCY2/7ASntTXfAF5s39P3/qspLLQfmqHPZiMGjweCE3Yf3aW5Q1mt+FLT2s2VUwuOawOQwDll51T2HB3wqyaDOSEpsWeR2Iym4TJXE2hbo7q5CQQBXissOo1Oruk5gcAp7uQHpnyuhCRCkfv/ErEpzdDA0JqfhMxdzmViVgsL1Kzalnbcy9lp+ACI4TL70iOl6j6xkyhFexe/aLXKLLPr4UGMi3Ver2CL6Q4kz.........................{ I hid it }...........................................
host;x-amz-access-token;x-amz-date;x-amz-security-token
4d719849acd655844ab5129f5e54a0ed16954c9580c7a9a737504faf42b309e2'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20210524T175148Z
20210524/eu-west-1/execute-api/aws4_request
a20e7ffe252dbf98d6a4b9213511ac1918f8bbad75ccbfd7ec46f5c9c1457b08'
",
"code": "InvalidSignature"
}
]
}
Note: I have removed some trailing chars of tokens and placed ......{ I hid it }..........
try this one
restRequest.AddJsonBody("{\"contentType\":\"text/tab-separated-values; charset=UTF-8\"}");
RestClient restClient = new RestClient("https://sandbox.sellingpartnerapi-eu.amazon.com/");
IRestRequest restRequest = new RestRequest("/feeds/2021-06-30/documents", Method.POST);
restRequest.AddJsonBody("{\"contentType\":\"text/tab-separated-values; charset=UTF-8\"}");
I do that in my open source library and its work without problem
https://github.com/abuzuhri/Amazon-SP-API-CSharp
Here sample to create and submit feed
ConstructFeedService createDocument = new ConstructFeedService("A3J37AJU4O9RHK", "1.02");
var list = new List<PriceMessage>();
list.Add(new PriceMessage()
{
SKU = "8201031206122...",
StandardPrice = new StandardPrice()
{
currency = BaseCurrencyCode.AED.ToString(),
Value = (201.0522M).ToString("0.00")
}
});
createDocument.AddPriceMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_PRODUCT_PRICING_DATA);
Thread.Sleep(1000*30);
var feedOutput=amazonConnection.Feed.GetFeed(feedID);
var outPut=amazonConnection.Feed.GetFeedDocument(feedOutput.ResultFeedDocumentId);
var reportOutpit = outPut.Url;
private async Task UploadFile(byte[] bytes, string url)
{
var contentType = "text/plain; charset=utf-8"; // this should be the same as what was used in Step #1 (in the CreateFeedDocument API request)
RestClient restClient = new RestClient(url);
IRestRequest restRequest = new RestRequest(Method.PUT);
restRequest.AddParameter(contentType, bytes, ParameterType.RequestBody);
var response = await restClient.ExecuteAsync(restRequest);
if (!response.IsSuccessful)
{
// your error logic
}
// success. Move to Step #3
}
IllegalLocationConstraintExceptionThe unspecified location constraint is incompatible for the region specific endpoint this request was sent to.5B8EGG143CSG45XCi7DqESeN8Q/1QfotMvQIiijcEj/76sr2T+gNh9Ubhq5aQZ7SbZMXCIS/8Mgw6iDod2mCwX/LX6Q=

Get Response Header data from Post Call

I'm calling a Microsoft API to create a printer however I need a way to get the response header where the information about the post is.
I'm following this guide https://learn.microsoft.com/en-us/graph/api/printer-create?view=graph-rest-beta&tabs=csharp but not sure how to extract the response from the call as I can not assign a variable to the call.
await graphClient.Print.Printers
.Create(displayName,manufacturer,model,certificateSigningRequest,physicalDeviceId,hasPhysicalDevice,connectorId)
.Request()
.PostAsync();
Operation-Location
You can send HTTP request with the .Net Microsoft Graph client library and read response headers.
Something like this:
var requestUrl = graphClient.Print.Printers.Request().RequestUrl;
var content = "json_content";
var hrm = new HttpRequestMessage(HttpMethod.Post, requestUrl);
hrm.Content = new StringContent(content, System.Text.Encoding.UTF8, "aplication/json");
// Authenticate (add access token)
await client.AuthenticationProvider.AuthenticateRequestAsync(hrm);
// Send the request and get the response.
var response = await client.HttpProvider.SendAsync(hrm);
if (!response.IsSuccessStatusCode)
{
throw new ServiceException(
new Error
{
Code = response.StatusCode.ToString(),
Message = await response.Content.ReadAsStringAsync()
});
}
else
{
// read header values
var headerValues = response.Headers.GetValues("Operation-Location");
}
Example of the request body:
{
"displayName": "Test Printer",
"manufacturer": "Test Printer Manufacturer",
"model": "Test Printer Model",
"physicalDeviceId": null,
"hasPhysicalDevice": false,
"certificateSigningRequest": {
"content": "{content}",
"transportKey": "{sampleTransportKey}"
},
"connectorId": null
}
Documentation

JIRA rest api attaching attachment with the issue. how to set MIME type

i have successfully attached an image with the issue using JIRA rest API in c# console application. but when i see the issue in jira it gives me error.
Error rendering 'com.atlassian.jira.jira-view-issue-plugin:attachmentmodule'. Please contact your JIRA administrators.
on searching this issue on the internet. the possible problem seems with the MIME type. when i watch the issue using rest api.(using rest api client postman)
here is my out put
"attachment": [
{
"self": "http://localhost:8080/rest/api/2/attachment/10103",
"id": "10103",
"filename": "images.jpg",
"author": {
"self": "http://localhost:8080/rest/api/2/user?username=wayne",
"name": "wayne",
"emailAddress": "brucewayne#waynecorp.com",
"avatarUrls": {
"16x16": "http://www.gravatar.com/avatar/faf8b9c4d44a4d05ca963d512c8d8805?d=mm&s=16",
"24x24": "http://www.gravatar.com/avatar/faf8b9c4d44a4d05ca963d512c8d8805?d=mm&s=24",
"32x32": "http://www.gravatar.com/avatar/faf8b9c4d44a4d05ca963d512c8d8805?d=mm&s=32",
"48x48": "http://www.gravatar.com/avatar/faf8b9c4d44a4d05ca963d512c8d8805?d=mm&s=48"
},
"displayName": "The Batman",
"active": true
},
"created": "2014-07-24T12:53:06.080+0530",
"size": 13303,
"content": "http://localhost:8080/secure/attachment/10103/images.jpg",
"thumbnail": "http://localhost:8080/secure/thumbnail/10103/_thumb_10103.png"
}
]
here i see
"mimeType": "image/jpeg" missing in the attachment array.
and i want to know where to add this mime type in my request.
my code is as follows
string postUrl = "http://localhost:8080/rest/api/latest/issue/" + projKey + "/attachments";
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Add("X-Atlassian-Token", "nocheck");
client.BaseAddress = new System.Uri(postUrl);
byte[] cred = UTF8Encoding.UTF8.GetBytes(credentials);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(cred));
MultipartFormDataContent content = new MultipartFormDataContent();
HttpContent fileContent = new ByteArrayContent(File.ReadAllBytes(filePath));
/*
content.Headers.ContentType= new MediaTypeHeaderValue("content-type")
{
MediaType = System.Net.Mime.MediaTypeNames.Image.Jpeg
}; */
content.Add(fileContent, "file", fileName);
var result = client.PostAsync(postUrl, content).Result;
Please suggest me a solution. i want to use httpclient for sending request
i found the solution. i was correct issue was related to the MIME type. for MultipartFormDataContent i need to give it as follows (Rest of code is written above).
HttpContent fileContent = new ByteArrayContent(File.ReadAllBytes(filePath)
string mimeType = System.Web.MimeMapping.GetMimeMapping(fileName);
//specifying MIME Type
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(mimeType);
content.Add(fileContent, "file",fileName);
var result = client.PostAsync(postUrl, content).Result;
this fixed the problem.

Categories

Resources