How do I pull data from a Slack API response with WebClient? - c#

I am making a portal for our team's Slack channel, and I'm wanting to pull a list of all of our current users using the Slack Web API - using the method api/users.list.
The code I am playing around with is:
var response = client.UploadValues("https://slack.com/api/users.list",
"POST", new NameValueCollection()
{
{ "token" ,"mySecretToken"}
});
I get an OK response back, but I'm having trouble actually finding out how to pull the data I want. When I look at the response object all I have is an array of bytes.
What am I missing to actually pull back an object with the user list information?

I needed to encode the response.
Just add this after:
var encoding = new UTF8Encoding();
var responseText = encoding.GetString(response);
I can then use the responseText to pull out the data I need.

Related

Issue while creating product using Shopify API

I am experiencing a weird issue while exporting some products to Shopify. When I save a JSON generated using JSON.net to txt file and then read it and then send it to Shopify's create product API, it works fine. However, if I just save the JSON to string and send post request directly, I get a 502 gateway error from Shopify. This happens only when creating certain products, where the JSON payload is somewhat bigger than normal. On other products, just saving JSON to a string and then sending to Shopify works OK. Weirdly, when I save the JSON to file from C#, then read that file a few lines below in the same code, and use that content as JSON string and send a post request, it again doesn't work. What do you think could be the issue?
Here's the JSON generated using JSON.net which works OK when read from file (https://pastebin.com/9SKFPjGJ)
var jsonContent = JsonConvert.SerializeObject(myObject);
using (var requestMessage = new HttpRequestMessage(HttpMethod.Put, $"https://{shopifySlug}.myshopify.com/admin/products/{originalShopifyProductId}.json"))
{
requestMessage.AddShopifyHeaders(shopifyAccessToken); // just a method for adding necessary shopify headers
requestMessage.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
response = await client.SendAsync(requestMessage);
}
Its getting hard for me to know the reason.
Here's what works:
Code that works:
json.txt was generated using this separately:
System.IO.File.WriteAllText("E:\\json.txt",JsonConvert.SerializeObject(myObject));
(Note that if the above line of code is inserted before the code below in the same file, then the code below doesn't work, i.e. the file has to be saved separately for it to work).
And then, just reading the JSON from file and sending that in the POST request works. Code below:
var jsonContent = System.IO.File.ReadAllText("E:\\json.txt");
using (var requestMessage = new HttpRequestMessage(HttpMethod.Put, $"https://{shopifySlug}.myshopify.com/admin/products/{originalShopifyProductId}.json"))
{
requestMessage.AddShopifyHeaders(shopifyAccessToken); // just a method for adding necessary shopify headers
requestMessage.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
response = await client.SendAsync(requestMessage);
}
Also the not working code at the very top works OK for smaller JSON payloads like this one https://pastebin.com/RhYjVuvv

Is there a way to retrieve the String the way it is actually uploaded to the server (as a whole)?

I am currently working on a OAuth2 implementation. However I am stuck on an Error 401. It seems like there is something wrong with my post request that is supposed to retrieve the access token from the Company the User logged in to. This is my code:
internal void RequestAccessToken(string code)
{
string requestBody = "grant_type="+ WebUtility.UrlEncode(GRANTTYPE)+ "&code=" + WebUtility.UrlEncode(code)+"&redirect_uri="+ WebUtility.UrlEncode(REDIRECT_URI);
WebClient client = new WebClient();
client.Headers.Add("Authorization",HeaderBase64Encode(CLIENT_ID, SECRETKEY));
var response = client.UploadString("https://thewebsiteiamcallingto.com/some/api", requestBody);
var responseString = client.OpenRead("https://thewebsiteiamcallingto.com/some/api");
}
My Questions are:
Is there anything wrong with the way I try to make the POST request ?
Is there a way to retrieve the whole string that is posted to the URI using UploadString?
P.S. I have seen this post regarding the POST creation. However I find the async part to be too complicated for my case.
Since we dont know the api documentation, I would suggest you to make a postman request and view the actual request sent and response received, and secondly make a request using your method and capture using a utility like wireshark and compare the difference.

The request body did not contain the specified number of bytes

I am calling an API from by C# Windows service. In some cases the following error is being raised.
The request body did not contain the specified number of bytes. Got 101,379, expected 102,044
In the RAW Request captured using fiddler content length as specified.
Content-Length: 102044
In the response from the API I am receiving the following message.
The request body did not contain the specified number of bytes. Got 101,379, expected 102,044
The strange thing for me is that it does not happen for each and every request, it is generated randomly and different points. Code which I am using to get the content length is specified below.
var data = Encoding.ASCII.GetBytes(requestBody); // requestBody is the JSON String
webReqeust.ContentLength = data.Length;
Is it mandatory to provide content length in REST API calls ?
Edit 1:
This is what my sample code looks like for web request
webReqeust = (HttpWebRequest)WebRequest.Create(string.Format("{0}{1}", requestURI, queryString));
webReqeust.Method = RequestMethod.ToString();
webReqeust.Headers.Add("Authorization", string.Format("{0} {1}", token_type, access_token));
webReqeust.Method = RequestMethod.ToString();
webReqeust.ContentType = "application/json";
var data = Encoding.ASCII.GetBytes(requestBody);
webReqeust.ContentLength = data.Length;
using (var streamWriter = new StreamWriter(webReqeust.GetRequestStream()))
{
streamWriter.Write(requestBody);
streamWriter.Flush();
streamWriter.Close();
}
I would suggest maybe instead try using HttpClient as done in the linked post from mjwills here. You don't have to use content length, but it sounds like that is being enforced by the API and ultimately you are trying to post too much.
Otherwise the way I see it is that something is making the request body too large. Is it serialized input data which gets encoded into a byte array? If that is what is happening then perhaps the correct length requirements are not being enforced on the data that composes the request body, and I would suggest inspecting what goes on in the composition of the request body object itself.

What is the equivalent of using StringContent (System.Net.Http) to make a post request in Python

I have some C# code that does the following post request:
string postData = newFormUrlEncodedContent(params).ReadAsStringAsync().Result;
var postContent = new StringContent(postData, UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
var responseMessage = httpClient.PostAsync(url, postContent).Result;
I would like to do the equivalent in Python using the Requests library. This is what I have:
headers = {'content-type':'application/x-www-form-urlencoded'}
postContent = requests.post(url, params=params, headers=headers, cookies=previousResponse.cookies)
But postContent.status_code for the Python code is 404, whereas the C# request returns 200. It's possible that there's something wrong with the params since I retrieve those via some Regex matching from a previous request, but that seems to be working.
Edit: I think setting the params parameter is for get requests, not post requests. Also I believe Requests takes care of form encoding:
Typically, you want to send some form-encoded data — much like an HTML form. To do this, simply pass a dictionary to the data argument. Your dictionary of data will automatically be form-encoded when the request is made
So now I have:
postContent = requests.post(url, data = params, cookies = previousResponse.cookies)
Now postContent.status_code == 500. The stack trace says the data is invalid at the root level. I will look into it.

How to get server response in JSON?

I am uploading a .json file from my local drive:
using (WebClient client = new WebClient())
{
client.Headers.Add("Content-Type", "application/json");
byte[] resp = client.UploadFile("http://mycoolWebsite.com", "POST", "path to file");
string textResponse = System.Text.Encoding.ASCII.GetString(resp)
}
The response from client.UploadFile is of type byte[] when I want it to be json so I can more easily parse through it. How can I ask the server to give me back json?
The method is defined as returning byte[] with good reason. It allows the method to be used with any web service and return back the raw response from the server. Defining server-side response is the responsibility of the server (obviously). Your best bet is to take the raw response, encode it as text (as you're doing), and then check to see if the response contains well-formed JSON, allowing you to re-encode as JSON and parse at that time.
The response will be whatever the server returns; it's up to you to handle it.

Categories