c# - DownloadString with WebClient - 404 Error - c#

I am trying to download string from discord webhook :("https://discordapp.com/api/webhooks/704770710509453432/GdR4absQHKDKjUiNMpw3aIpX2tx-9Z7nmPE2Sn3TUkQDM12zUczaV-m80orh7WGVzvGK")
When I normally open the site with browser string is : {"message": "Unknown Webhook", "code": 10015}
But when I do that with WebClient:
WebClient wc = new WebClient();
string site = "https://discordapp.com/api/webhooks/704770710509453432/GdR4absQHKDKjUiNMpw3aIpX2tx-9Z7nmPE2Sn3TUkQDM12zUczaV-m80orh7WGVzvGK";
string x = wc.DownloadString(site);
It gives an "404 Error". Is there a way to get that {"message": "Unknown Webhook", "code": 10015} string with c#?

A rough guess would be that it's to do with the accept header. Check the documentation for the api, but my browser sent an additional 17 headers along with the request.
The simple answer would be, use HttpClient. It's recommended for new development and also gives the correct response here:
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace discordapi_headers
{
class Program
{
static async Task Main(string[] args)
{
var client = new HttpClient();
var response = await client.GetAsync("https://discordapp.com/api/webhooks/704770710509453432/GdR4absQHKDKjUiNMpw3aIpX2tx-9Z7nmPE2Sn3TUkQDM12zUczaV-m80orh7WGVzvGK");
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}
}
However that doesn't help if you can't. Also I'm intrigued now...
Ha! I should have listened to my own advice. For web service related stuff, you can't beat fiddler and postman. It turns out that the api is returning a custom 404 to the browser that has json content.
Unfortunately DownloadString sees the 404 and throws a WebException.
Here's an updated version that works, using HttpClient and WebClient.
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace discordapi_headers
{
class Program
{
static readonly string url = "https://discordapp.com/api/webhooks/704770710509453432/GdR4absQHKDKjUiNMpw3aIpX2tx-9Z7nmPE2Sn3TUkQDM12zUczaV-m80orh7WGVzvGK";
static async Task Main(string[] args)
{
Console.WriteLine(await UseHttpClient(url));
Console.WriteLine(await UseWebClient(url));
}
private static async Task<string> UseHttpClient(string url)
{
var client = new HttpClient();
var response = await client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
private static async Task<string> UseWebClient(string url)
{
var client = new WebClient();
try
{
var response = await client.DownloadStringTaskAsync(url);
return response;
}
catch (WebException wex)
{
using (var s = wex.Response.GetResponseStream())
{
var buffer = new byte[wex.Response.ContentLength];
var contentBytes = await s.ReadAsync(buffer, 0, buffer.Length);
var content = Encoding.UTF8.GetString(buffer);
return content;
}
}
}
}
}

Related

How to handle multiple http requests using single instance of HttpClient?

after doing some research I got to know that it's best to instantiate HttpClient once and then reuse it's instance everwhere else.
My GetAsync requests are working absolutely fine. However, with PostAsync I'm getting error.
Please find my code below :
using System;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Net.Http.Headers;
using System.Net.Mime;
namespace ConsoleApplication
{
public class Program
{
private static HttpClient client = new HttpClient();
public static async Task Main(string[] args)
{
string Event_MSG ="[{\"ID\":354,\"EventTimeStamp\":\"2022-05-
17T05:35:25\",\"Title\":\"Failedtoretrieveequipmentlogs\",\"ControllerId\":24,
\"Details\":\"UnabletoretrievelogsfromdeviceP25-SC-
023322.Cyclepoweratfieldunit.Iftheproblemreturns,contactyourHunterrepresentative.\",
\"ControllerName\":\"P25-SC-0233\"},{\"ID\":353,\"EventTimeStamp\":\"2022-05-
17T05:34:20\",\"Title\":\"Failedtoretrieveequipmentlogs\",\"ControllerId\":17,
\"Details\":\"UnabletoretrievelogsfromdeviceP25-SC-
022615.Cyclepoweratfieldunit.Iftheproblemreturns,contactyourHunterrepresentative.\",
\"ControllerName\":\"P25-SC-0226\"},{\"ID\":352,\"EventTimeStamp\":\"2022-05-
17T05:33:50\",\"Title\":\"Failedtoretrieveequipmentlogs\",\"ControllerId\":16,
\"Details\":\"UnabletoretrievelogsfromdeviceP25-SC-
022514.Cyclepoweratfieldunit.Iftheproblemreturns,contactyourHunterrepresentative.\",
\"ControllerName\":\"P25-SC-0225\"},{\"ID\":351,\"EventTimeStamp\":\"2022-05-
17T05:33:20\",\"Title\":\"Failedtoretrieveequipmentlogs\",\"ControllerId\":15,
\"Details\":\"UnabletoretrievelogsfromdeviceP25-SC-
022413.Cyclepoweratfieldunit.Iftheproblemreturns,contactyourHunterrepresentative.\",
\"ControllerName\":\"P25-SC-0224\"},{\"ID\":350,\"EventTimeStamp\":\"2022-05-
17T05:32:50\",\"Title\":\"Failedtoretrieveequipmentlogs\",\"ControllerId\":14,
\"Details\":\"UnabletoretrievelogsfromdeviceP25-SC-
022312.Cyclepoweratfieldunit.Iftheproblemreturns,contactyourHunterrepresentative.\",
\"ControllerName\":\"P25-SC-0223\"}]";
Console.WriteLine("Starting connections");
List<KeyValue> keyvalue = JsonConvert.DeserializeObject<List<KeyValue>>(Event_MSG);
JArray EventMSG = JArray.Parse(Event_MSG);
int i = 0;
foreach(var item in EventMSG)
{
var inc_val = i++;
client.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Basic","auth_val");
HttpResponseMessage get_response = await
client.GetAsync("https://myurl.com/"+keyvalue[inc_val]);
var get_responseString = await get_response.Content.ReadAsStringAsync();
JObject obj = JObject.Parse(get_responseString);
string DeviceID = (string) obj["managedObject"]["id"];
string isoTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
string c8y_payloadString = $"{{\"time\": \"{isoTime}\",\"source\": {{\"id\": \"
{DeviceID}\" }},\"type\": \"c8y_Golf_Controller\",\"text\": \"PilotCC Event\"}}";
JObject c8y_payloadObject = JObject.Parse(c8y_payloadString);
var c8y_finalPayload = new JObject();
c8y_finalPayload.Merge(item);
c8y_finalPayload.Merge(c8y_payloadObject);
string c8y_finalPayloadString = JsonConvert.SerializeObject(c8y_finalPayload);
Console.WriteLine(get_responseString);
client.DefaultRequestHeaders.Add("Accept",
"application/vnd.com.nsn.cumulocity.event+json");
var stringContent = new StringContent(c8y_finalPayloadString, Encoding.UTF8,
MediaTypeNames.Application.Json);
stringContent.Headers.ContentType.CharSet = "";
HttpResponseMessage response = await client.PostAsync("https://myurl.com",
stringContent);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
}
Console.WriteLine("Connections done");
}
}
public class KeyValue
{
[JsonProperty("ControllerName")]
public string ControllerName { get; set; }
public override string ToString()
{
return String.Format(ControllerName);
}
}
}
Now If I remove the following lines from the code, it works completely fine and returns correct json response for all 5 get requests :
POST REQUEST CODE
client.DefaultRequestHeaders.Add("Accept",
"application/vnd.com.nsn.cumulocity.event+json");
var stringContent = new StringContent(c8y_finalPayloadString, Encoding.UTF8,
MediaTypeNames.Application.Json);
stringContent.Headers.ContentType.CharSet = "";
HttpResponseMessage response = await client.PostAsync("https://myurl.com", stringContent);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
But when I'm using this it throws an error : -
Unhandled exception. Newtonsoft.Json.JsonReaderException: Error reading JObject from JsonReader. Path '', line 0, position 0.
at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings)
at Newtonsoft.Json.Linq.JObject.Parse(String json, JsonLoadSettings settings)
at Newtonsoft.Json.Linq.JObject.Parse(String json)
at ConsoleApplication.Program.Main(String[] args) in Program.cs:line 31
at ConsoleApplication.Program.<Main>(String[] args)
Only the first iteration runs successfully making both GetAsync and PostAsync calls, after that I get the above error.
Line which is throwing error is : JObject obj = JObject.Parse(get_responseString); and it is because in second iteration the get request is not returning any response(happening only when the lines in POST REQUEST CODE are included)
Sample Get Request response : -
{"managedObject":{"self":"https://url.co/inventory/managedObjects/43432113",
"id":"43432113"},"externalId":"P25-SC-0233","self":"https://url.co/identity/externalIds/c8y_Serial/P25-SC-0233",
"type":"c8y_Serial"}
What am I missing here?

How to properly do this C# MultiPartFormDataContent API Call?

I am currently trying to make an api call in c# using a MultiPartFormDataContent but I keep
getting the following error:
"Response: {"statusCode":400,"error":"Bad Request","message":""Image file" must be of type object","validation":{"source":"payload","keys":["images"]}}"
This is my Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace Example
{
public class Test
{
public static void Main(string[] args)
{
Task<string> test = testFunction();
Console.WriteLine("Result: " + test.Result);
}
public static async Task<string> testFunction()
{
const string file = "C:\\ExamplePath\\image_1.jpeg";
const string URL = "https://example-api?api-key=example-key";
string boundary = "---8d0f01e6b3b5dafaaadaad";
MultipartFormDataContent multipartContent = new MultipartFormDataContent(boundary);
var streamContent = new StreamContent(File.Open(file, FileMode.Open));
var stringContent = new StringContent("flower");
multipartContent.Add(stringContent, "organs");
multipartContent.Add(streamContent, "images");
try
{
HttpClient httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.PostAsync(URL, multipartContent);
Console.WriteLine("Response: " + await response.Content.ReadAsStringAsync());
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine("IN METHIOD: " + content);
return content;
}
return null;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}
}
}
It's obviously a problem with how I am trying to do the api call but I don't know how to do it with an object instead like mentioned the error message.
This link has some good examples and where I actually got my code snippet from below.
Here's a basic example of using MultiFormDataContent:
HttpClient httpClient = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
form.Add(new StringContent(username), "username");
form.Add(new StringContent(useremail), "email");
form.Add(new StringContent(password), "password");
form.Add(new ByteArrayContent(file_bytes, 0, file_bytes.Length), "profile_pic", "hello1.jpg");
HttpResponseMessage response = await httpClient.PostAsync("PostUrl", form);
response.EnsureSuccessStatusCode();
httpClient.Dispose();
string sd = response.Content.ReadAsStringAsync().Result;
I hope this helps or points you in the right direction.

400 (An HTTP header that's mandatory for this request is not specified.) when trying to upload to Azure in c#

I am trying to upload a simple emtpy .txt to Azure blob storage from c# (currently just a proof of concept). I am doing this using a SAS token (which is working for all other cases I have tried sofar, like listing the containers or deleting a blob).
But when trying to create a new blob I get the error that 400 (An HTTP header that's mandatory for this request is not specified.)
I guess I have configured the request in the wrong way but I can not figure out the correct way. Can someone help? The Put Rest API call can be found here.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Xml.Linq;
namespace ConsoleProgram
{
public class Class1
{
private static string URL = "https://example.blob.core.windows.net/";
private static string sasToken = "sv=2019-12-12&ss=b&srt=sco&sp=rwdlacx&se=2021-02-02T15:52:32Z&st=2021-02-02T07:52:32Z&spr=https&sig=realSig";
private static string command = "";
private static string commandType = "Put";
static void PutBlob()
{
URL = "https://example.blob.core.windows.net/test/hello2.txt";
command = "?";
commandType = "Put";
}
static void ListContainers()
{
URL = "https://example.blob.core.windows.net/";
command = "?comp=list&";
commandType = "Get";
}
static void ListBlobs()
{
URL = "https://example.blob.core.windows.net/test";
command = "?restype=container&comp=list&";
commandType = "Get";
}
static void DeleteBlob()
{
URL = "https://example.blob.core.windows.net/test/hello2.txt";
command = "?";
commandType = "Delete";
}
static void Main(string[] args)
{
PutBlob();
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response;
// List data response.
if (commandType == "Get")
{
response = client.GetAsync(command + sasToken).Result; // Blocking call! Program will wait here until a response is received or a timeout occurs.
}
else if (commandType == "Delete")
{
response = client.DeleteAsync(command + sasToken).Result;
}
else
{
// This is the Code that causes the problems
var s=new StringContent("hello2.txt");
response = client.PutAsync(command+sasToken,s).Result;
}
if (response.IsSuccessStatusCode)
{
Console.WriteLine("---------------Positive Responce----------------");
Console.WriteLine(response.ToString());
// Parse the response body.
var dataObjects = response.Content.ReadAsStringAsync().Result; //Make sure to add a reference to System.Net.Http.Formatting.dll
}
else
{
Console.WriteLine("---------------Negative Responce----------------");
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
// Make any other calls using HttpClient here.
// Dispose once all HttpClient calls are complete. This is not necessary if the containing object will be disposed of; for example in this case the HttpClient instance will be disposed automatically when the application terminates so the following call is superfluous.
client.Dispose();
}
}
}
Simple adding the line:
client.DefaultRequestHeaders.Add("x-ms-blob-type", "BlockBlob");
fixed it for me.

C# Firebase Admin SDK Push Notifications

I want to send push notifications to a mobile app, so I installed Firebase Admin SDK to my .Net project.
I followed the instructions on Firebase docs, but when I call the SendAsync from the SDK, it just hangs. Any idea why it would hang? Am I missing steps?
Here is my API code (Note this is only demo code to get it to work):
public async void SendPushNotification()
{
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile("path to json file"),
});
var registrationToken = "fqCo_-tXKvY:APA91bGQ47Q2egnqn4Ml...";
var message = new FirebaseAdmin.Messaging.Message()
{
Token = registrationToken,
};
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
Console.WriteLine("Successfully sent message: " + response);
}
you have a deadlock because SendAsync will never finish.
if you are calling from ui thread you need to consider using ConfigureAwait(false)
so your snippet will look like below:
public async void SendPushNotification()
{
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile("path to json file"),
});
var registrationToken = "fqCo_-tXKvY:APA91bGQ47Q2egnqn4Ml...";
var message = new FirebaseAdmin.Messaging.Message()
{
Token = registrationToken,
};
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message).ConfigureAwait(false);
Console.WriteLine("Successfully sent message: " + response);
}
The firebaseAdmin messaging throw a token error with the .net libraries hence i tested with Postman and works i was able to send the notifications and I see postman generates a code for Resharper library and was easy to install and use, is better to serialize the message with Json and send as parameter
using Firebase.Auth;
using FirebaseAdmin;
using FirebaseAdmin.Auth;
using Google.Apis.Auth.OAuth2;
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using FirebaseAuth = FirebaseAdmin.Auth.FirebaseAuth;
using FirebaseAdmin.Messaging;
using RestSharp;
using Newtonsoft.Json;
namespace messaging
{
class Program
{
static async System.Threading.Tasks.Task Main(string[] args)
{
string token = "dtPMeTshqr??????????????";
var data = new
{
to = token,
notification = new
{
body = "Nueva notificacion de prueba",
title = "Notificacion de prueba",
},
priority = "high"
};
var json = JsonConvert.SerializeObject(data);
Sendmessage(json);
}
private static string Sendmessage(string json)
{
var client = new RestClient("https://fcm.googleapis.com/fcm/send");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "key=AAAAexjc2Qg:APx??????????????");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", json, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
return response.Content;
}
}
}

Infinite loading when calling the QnAMaker using WebMethod C#

When I tried to call the web method "QnAMakerQuestionsAnswers", It will only have an infinite loading and will not show the result. I have tried this in a console application and it works perfectly but not for the WebMethod. I am not sure which part of my code I need to modify but this is a little bit frustrating. Please help!!
Code is below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace ChatbotWebService
{
/// <summary>
/// Summary description for ChatbotWebService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class ChatbotWebService : System.Web.Services.WebService
{
// NOTE: Replace this with a valid host name.
static string host = "<Host Name>";
// NOTE: Replace this with a valid endpoint key.
// This is not your subscription key.
// To get your endpoint keys, call the GET /endpointkeys method.
static string endpoint_key = "<End Point Key>";
// NOTE: Replace this with a valid knowledge base ID.
// Make sure you have published the knowledge base with the
// POST /knowledgebases/{knowledge base ID} method.
static string kb = "<KB ID>";
static string service = "/qnamaker";
static string method = "/knowledgebases/" + kb + "/generateAnswer/";
static string question = #"
{
'question': 'Who are you?'
}
";
async static Task<string> Post(string uri, string body)
{
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(uri);
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
request.Headers.Add("Authorization", "EndpointKey " + endpoint_key);
//SUPER IMPORTANT LINE. PLEASE DO IT FOR .NET Framework v4.5.
//Explanation at https://blogs.perficient.com/2016/04/28/tsl-1-2-and-net-support/
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var response = await client.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
}
async static Task<string> GetAnswers()
{
var uri = host + service + method;
Console.WriteLine("Calling " + uri + ".");
string response = "NULL";
try
{
response = await Post(uri, question);
Console.WriteLine(response);
Console.WriteLine("Press any enter to continue.");
}
catch (HttpRequestException e)
{
Console.WriteLine(e.InnerException.Message);
}
return response;
}
[WebMethod]
public string QnAMakerQuestionsAnswers()
{
return GetAnswers().Result;
}
}
}

Categories