How to correctly send json with httpWebRequest? - c#

I have a httpWebRequest object.
It is initialised like this:
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://myURL.com"); // This is actually my company URL I can't show
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
Then I want to send to this URL json datas. After tries, I figured I do it wrong, but I don't get what it is... Here is where I send it datas:
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
List<string> datas = new List<string>();
datas.Add("1");
string json = Newtonsoft.Json.JsonConvert.SerializeObject(datas);
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
It doesn't seem to be working. Is there a way to catch the URL I'm sending? I tried Fiddler, but I don't see my request.
Also this code works with a chrome console:
jQuery.ajax({
'url': 'http://myURL.com',
'type': 'POST',
'data': {data:[7]},
'success': function (data) {
console.log(data);
}
});

From the code you use at Chrome it is denoted your data structure is not correct.
First, you need a class to store the data, lets call it DataHolder:
public class DataHolder
{
public int[] data { get; set; }
}
So now you need to fill it:
var newData = new DataHolder{ data = new int[] { 1 } };
And now you can serialize it and it should work:
string json = Newtonsoft.Json.JsonConvert.SerializeObject(newData);
EDIT: as a note, in a previous question you posted you tried to send "{ data: [1] }" which is incorrect, it should be "{ \"data\": [1] }" but better stick to a class with the correct structure and let the serializer deal with those implementation details.

Related

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.

Calling PayU rest api (create order) returns html instead of json response

I'm trying to post an order to PayU payment gateway, using Rest Client tools like post man also I got the same issue.
I'm trying to post using C#, the order created successfully but the response is not as expected, it should be a json object contains the inserted order id and the redirect url , but the current is html response!
C# Code response :
My C# Code using restsharp library :
public IRestResponse<CreateOrderResponseDTO> CreateOrder(CreateOrderDTO orderToCreate)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var actionUrl = "/api/v2_1/orders/";
var client = new RestClient(_baseUrl);
var request = new RestRequest(actionUrl, Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddJsonBody(orderToCreate);
request.AddHeader("authorization", $"Bearer {_accessToken}");
request.AddHeader("Content-Type", "application/json");
var response = client.Execute<CreateOrderResponseDTO>(request);
if (response.StatusCode == HttpStatusCode.OK)
{
return response;
}
throw new Exception("order not inserted check the data.");
}
My C# Code using built in WebRequest also returns same html :
public string Test(string url, CreateOrderDTO order)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Accept = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken);
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(new JavaScriptSerializer().Serialize(order));
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
}
}
Can anyone advise what I missed here ?
In postman, the solution is turning off redirects, like on the image below:
After some tries I found that PayU rest api returns 302 (found) also ResponseUri not OK 200 as expected.
by default rest client automatically redirect to this url so I received the html content of the payment page.
The solution is :
client.FollowRedirects = false;
Hope this useful to anyone.
Also, I would like to add that the above answer by Mohammad is correct as to get the response URL we need to set AllowAutoRedirect to false. I have been trying to implement PayU LatAM WebCheckout in a console app and I was facing similar issue. I got some inspiration from the answer given here: How to get Location header with WebClient after POST request
Based on the answer, I wrote a sample code:
public class NoRedirectWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var temp = base.GetWebRequest(address) as HttpWebRequest;
temp.AllowAutoRedirect = false;
return temp;
}
}
After creating the above class, I wrote the following code in my Main method:
var request = MakeRequestLocation(new NoRedirectWebClient());
var psi = new ProcessStartInfo("chrome.exe");
psi.Arguments = request.ResponseHeaders["Location"];
Process.Start(psi);
I am now calling the function MakeRequestLocation inside the same class.
private static WebClient MakeRequestLocation(WebClient webClient)
{
var loginUrl = #"https://sandbox.checkout.payulatam.com/ppp-web-gateway-payu/";
NameValueCollection formData = new NameValueCollection
{
{"ApiKey", "4Vj8eK4rloUd272L48hsrarnUA" },
{"merchantId", "508029" },
{"accountId", "512321" },
{"description", "Test PAYU" },
{"referenceCode", "SomeRandomReferenceCode" },
{"amount", "2" },
{"tax", "0" },
{"taxReturnBase", "0" },
{"currency", "USD" },
{"signature", "Signature generated via MD5 sum" },
{"buyerFullName", "test" },
{"buyerEmail", "test#test.com" },
{"responseUrl", #"http://www.test.com/response" },
{"confirmationUrl", #"http://www.test.com/confirmation" }
};
webClient.UploadValues(loginUrl, "POST", formData);
return webClient;
}
The object that is returned by the above function contains a header called location. The value of the location is your required URL for webcheckout.

Pass large amount of data to MVC get method

I have an angularjs form that I would like users to be able to download a filled out PDF of what they requested. I have an [HTTPGet] method that accepts a base64 encoding of the json request. Everything works except when my base64 encoding goes above 2027 characters in length. When that happens, I don't receive anything more than the 2027 characters. Is there another way to send the data on a get call or a better way to do this.
My angular js app does this.
scope.DownloadTempResults = function () {
window.open('/Home/GetCopyOfRequest?strRequest=' + window.btoa(JSON.stringify(scope.request)), '_blank', '');
}
My C# code behind does this.
[HttpGet]
public ActionResult GetCopyOfRequest(string strRequest)
{
byte[] data = Convert.FromBase64String(strRequest);
string request = Encoding.UTF8.GetString(data);
ExternalModel model = JsonHelper.Deserialize<ExternalModel>(request);
byte[] filedata = ObjectFactory.GetInstance<ManagerFactory>().Create().CreateRequestForm(model);
string contentType = "application/pdf";
var cd = new System.Net.Mime.ContentDisposition
{
FileName = "name of File",
Inline = true
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(filedata, contentType);
}
At the end of the day, what we are trying to do is encode the json in the query string so that you can not look directly at the query string and get the values of the json object. If I am going about this completely wrong, please let me know what to look up to accomplish this.
Updated below here.
So based on the comments, I changed to a post method that looks like this.
[HttpPost]
public HttpResponseMessage GetCopyOfRequest(string strRequest)
{
ExternalModel model = JsonHelper.Deserialize<ExternalModel>(strRequest);
byte[] filedata = ObjectFactory.GetInstance<IManagerFactory>().Create().CreateRequestForm(model);
string fileName = "Request form for request";
HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
httpResponseMessage.Content = new ByteArrayContent(filedata);
httpResponseMessage.Content.Headers.Add("x-filename", fileName);
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileName;
httpResponseMessage.StatusCode = HttpStatusCode.OK;
return httpResponseMessage;
}
In the angularjs app, I have the following code.
$http({
url: '/Home/GetCopyOfRequest',
method: 'POST',
data: { strRequest: JSON.stringify(request) },
responseType: 'arraybuffer'
}).success(function (data, status, headers) {
var file = new Blob([data], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}).error(function (response) {
});
When I do this on the server, my byte array has a length of 400000. On the client side, I have an array of 270. I followed an example from How to display a server side generated PDF stream in javascript sent via HttpMessageResponse Content .

C# API return HTML instead JSON

Don't know why a web request return HTML instead JSON. Can anyone please help.
private void Test()
{
string url = "https://www.netonnet.no/Category/GetFilteredCategory";
string json = "{'sectionId':'10978','filter': '[]','sortOrder':-1,'sortBy':0,'pageSize':96,'listType':'10'}";
string result = "";
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
result = client.UploadString(url, "POST", json);
}
Debug.WriteLine(result);
}
When your asking an you want it in a specific format you should add
client.Headers[HttpRequestHeader.Accept] = "application/json";
This will tell the API that you want it in json, but this only works if they can give it to you in that format.
And like Amit Kumar Ghosh said in a comment above, it seems like they don't serve json.

POSTing JSON to URL via WebClient in C#

I have some JavaScript code that I need to convert to C#. My JavaScript code POSTs some JSON to a web service that's been created. This JavaScript code works fine and looks like the following:
var vm = { k: "1", a: "2", c: "3", v: "4" };
$.ajax({
url: "http://www.mysite.com/1.0/service/action",
type: "POST",
data: JSON.stringify(vm),
contentType: "application/json;charset=utf-8",
success: action_Succeeded,
error: action_Failed
});
function action_Succeeded(r) {
console.log(r);
}
function log_Failed(r1, r2, r3) {
alert("fail");
}
I'm trying to figure out how to convert this to C#. My app is using .NET 2.0. From what I can tell, I need to do something like the following:
using (WebClient client = new WebClient())
{
string json = "?";
client.UploadString("http://www.mysite.com/1.0/service/action", json);
}
I'm a little stuck at this point. I'm not sure what json should look like. I'm not sure if I need to set the content type. If I do, I'm not sure how to do that. I also saw UploadData. So, I'm not sure if I'm even using the right method. In a sense, the serialization of my data is my problem.
Can someone tell me what I'm missing here?
Thank you!
The question is already answered but I think I've found the solution that is simpler and more relevant to the question title, here it is:
var cli = new WebClient();
cli.Headers[HttpRequestHeader.ContentType] = "application/json";
string response = cli.UploadString("http://some/address", "{some:\"json data\"}");
PS: In the most of .net implementations, but not in all WebClient is IDisposable, so of cource it is better to do 'using' or 'Dispose' on it. However in this particular case it is not really necessary.
The following example demonstrates how to POST a JSON via WebClient.UploadString Method:
var vm = new { k = "1", a = "2", c = "3", v= "4" };
using (var client = new WebClient())
{
var dataString = JsonConvert.SerializeObject(vm);
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
client.UploadString(new Uri("http://www.contoso.com/1.0/service/action"), "POST", dataString);
}
Prerequisites: Json.NET library
You need a json serializer to parse your content, probably you already have it,
for your initial question on how to make a request, this might be an idea:
var baseAddress = "http://www.example.com/1.0/service/action";
var http = (HttpWebRequest)WebRequest.Create(new Uri(baseAddress));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
string parsedContent = <<PUT HERE YOUR JSON PARSED CONTENT>>;
ASCIIEncoding encoding = new ASCIIEncoding();
Byte[] bytes = encoding.GetBytes(parsedContent);
Stream newStream = http.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
var response = http.GetResponse();
var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
var content = sr.ReadToEnd();
hope it helps,

Categories

Resources