PUT Request in C# WebForms to update one parameter - c#

I'm working on a web app that will manage WooCommerce orders, over WooCommerce REST API.
I'm trying to update the order status after the user clicks a button.
When I run the app, click the button, I get a 200 - OK status, but the order remains the same, no update is done.
This is the cURL example on the documentation:
curl -X PUT https://example.com/wp-json/wc/v3/orders/727 \
-u consumer_key:consumer_secret \
-H "Content-Type: application/json" \
-d '{
"status": "completed"
}'
On Postman, i execute the query and it works just fine, adding this code on the body (raw-JSON), over a PUT request:
{
"status": "cancelled"
}
Now, this is my C# code, on the onClick action of the button:
#region Request
string nuevoEstado = "trash";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(urlRequestInicial);
httpWebRequest.ContentType = "text/json";
httpWebRequest.Method = "PUT";
httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.Default.GetBytes(apiUsr + ":" + apiPwd));
httpWebRequest.UseDefaultCredentials = true;
httpWebRequest.Proxy.Credentials = CredentialCache.DefaultCredentials;
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
var serializaer = new JavaScriptSerializer();
var elJeison = serializaer.Serialize(new
{
status = nuevoEstado
});
streamWriter.Write(elJeison);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
string returnString = httpResponse.StatusCode.ToString();
ltErr.Text = returnString;
#endregion
returnString shows "OK", but no update is done.
Any help is muchly appreciated

Solved it with another approach. I post it here in case anyone gets to the same issue I had:
I changed the method to a async void
using System.Net.Http;
using System.Net.Http.Headers;
protected async void btnCompletarPedidoApiAxnAsync (object sender, EventArgs e)
{
...
}
And I set a using block, changing the approach over a HttpClient();
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("PUT"), laUrl))
{
var base64authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes(apiUsr + ":" + apiPwd));
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64authorization}");
request.Content = new StringContent("{\n \"status\": \"completed\"\n}");
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var response = await httpClient.SendAsync(request);
string responseBody = await response.Content.ReadAsStringAsync();
}
}

Related

WebAPI call using RestSharp gives status 404; WebRequest succeeds

I've got a section of code to do a call to an external webapi using WebRequest. I'm trying to update it to use RestSharp instead. What am I missing here to make the conversion? The closest question here to give any sort of idea what might be going on is found in Calling webapi method gives 404. The "answer" was a missing accepted content type. I've verified through the RestClient the types are present (and appear valid).
Common request JSON
var statusRequest = #"
{
""auth"": {
""type"": ""basic""
},
""requestId"": ""15"",
""method"": {
""name"": ""getStatus"",
""params"": {
""showAllStatus"": ""0""
}
}
}
";
WebRequest code
var webRequest = WebRequest.Create("https://service.url/api/status") as HttpWebRequest;
webRequest.Method = "POST";
var username = "user";
var password = "pass";
var encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1")
.GetBytes(username + ":" + password));
webRequest.Headers.Add("Authorization", "Basic " + encoded);
var requestWriter = new StreamWriter(webRequest.GetRequestStream());
webRequest.ContentType = "APPLICATION/JSON; CHARSET=UTF-8";
requestWriter.Write(statusRequest);
requestWriter.Close();
var responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
var responseData = responseReader.ReadToEnd();
responseReader.Close();
Should convert to RestSharp as
var client = new RestClient("https://service.url");
client.Authenticator = new HttpBasicAuthenticator("user", "pass");
var request = new RestRequest("api/status", Method.Post);
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(statusRequest);
client.BuildUri(request);
var response = await client.GetAsync(request);
EDIT: Make the RestRequest a POST
Please read the docs.
Also, you are calling GetAsync. Even if you set the request method to Method.Post, calling GetAsync will override it.
This will work:
var request = new RestRequest("api/status")
.AddStringBody(statusRequest, DataFormat.Json);
var response = await client.PostAsync(request);

POST binary file to ticket ServiceNow REST API - Remove boundary and Content-Type

I am trying to attach a binary file (Excel, MS-Word or Image or anything) to ServiceNow ticket using the POST method available in their REST API.
It works fine when I try to do that using Postman app, however, when I try to do that using C# code, the file gets added successfully however, in the beginning and end of file there is some data due to which files are not valid any more. If I open the attached files using Notepad++, I can see that the file has something like below:
--dc5fc6f1-c907-4a26-b410-1d54256954d6
Content-Disposition: form-data; name=Attachment; filename=Download_14Jul20151332195868.xlsx; filename*=utf-8''Download_14Jul20151332195868.xlsx
If I remove above lines from the file and save it again, then I am able to open the file in excel. Same thing happens with any other file type.
I am using below URL to POST the file to ServiceNow:
https://mycompany.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=1abc60ccdabc1c14215fc082ba9619b0&file_name=SampleExcel3.xlsx
And below is my code:
private static string SendMultiPartRequest(string URL, ExecutionEnvironment executionEnvironment)
{
var response = "";
try
{
byte[] file_bytes = File.ReadAllBytes(AttachmentFilePath);
if (!string.IsNullOrWhiteSpace(AttachmentFilePath))
{
using (var client = CreateNewClient(URL, executionEnvironment))
{
using (var multipartContent = new MultipartFormDataContent())
{
multipartContent.Add(new StreamContent(new MemoryStream(file_bytes)), "Attachment", AttachmentFilePath.Substring(AttachmentFilePath.LastIndexOf("\\") + 1));
//multipartContent.Headers.Remove("Content-Type");
Task responseTask = client.PostAsync(WSIUrl, multipartContent).ContinueWith((Task<HttpResponseMessage> authRes) =>
{
response = HandleResponse(authRes);
});
responseTask.Wait();
}
}
}
else
{
response = "{ \"ErrorMessage\" : \"Attachment file not specified.\"}";
}
}
catch (Exception ex)
{
response = "{ \"ErrorMessage\" : \"Unspecified error: " + ex.Message + " \"}";
}
return response;
}
I also tried to Remove the header but it failed to attach file when I un-comment this line:
//multipartContent.Headers.Remove("Content-Type");
I don't have control over how ServiceNow API is using the file submitted. Please suggest how can I submit a binary file to attach to ServiceNow ticket.
UPDATE:
I am still trying with various options but still no luck. I tried to explore how Postman is able to attach the file successfully and found below code from Postman application. However, I can't see in this code how Postman is adding the Binary contents in the payload:
var client = new RestClient("https://mycompany.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=1abc60ccdabc1c14215fc082ba9619b0&file_name=Sample.xlsx");
var request = new RestRequest(Method.POST);
request.AddHeader("Postman-Token", "34584fo4-f91a-414f-8fd0-ff44b0c6b345");
request.AddHeader("cache-control", "no-cache");
request.AddHeader("Authorization", "Basic c4Ajc2NvcmNoOmVOdBEzOSNSQGspqr==");
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
IRestResponse response = client.Execute(request);
However, when I send the POST request through Postman Application, it is working fine:
URL used in postman is: POST - https://MyCompany.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=1abc60ccdabc1c14215fc082ba9619b0&file_name=Sample.xlsx
I finally got this working using RestSharp. Below is the code if anyone else is looking for the solution:
private static string SendMultiPartRestClient(string URL, ExecutionEnvironment executionEnvironment)
{
string response;
try
{
if (!string.IsNullOrWhiteSpace(AttachmentFilePath))
{
string FileNameWithoutExtension = Path.GetFileNameWithoutExtension(AttachmentFilePath);
string FileExtension = Path.GetExtension(AttachmentFilePath);
string AttachmentFileName = $"{FileNameWithoutExtension}{FileExtension}";
string AskNowPasswordToBeUsed;
if (executionEnvironment == ExecutionEnvironment.NonProduction)
AskNowPasswordToBeUsed = AskNowPasswordEagle;
else
AskNowPasswordToBeUsed = AskNowPasswordProduction;
byte[] byteArray = Encoding.ASCII.GetBytes(AskNowUserName + ":" + AskNowPasswordToBeUsed);
var Auth = Convert.ToBase64String(byteArray);
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
X509Certificate2 c1 = new X509Certificate2(asknowCertPath, CertPass);
var client = new RestClient(WSIUrl);
client.Timeout = -1;
client.AddDefaultHeader(DP_EXTERNAL_URL, URL);
client.ClientCertificates = new X509CertificateCollection() { c1 };
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", $"Basic {Auth}");
request.AddHeader("Accept", "*/*");
request.AddHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
request.AddParameter("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
File.ReadAllBytes(AttachmentFilePath),
ParameterType.RequestBody);
IRestResponse restResponse = client.Execute(request);
switch (restResponse.ResponseStatus)
{
case ResponseStatus.None:
response = "{ \"ErrorMessage\" : \"No response\"}";
break;
case ResponseStatus.Completed:
response = restResponse.Content;
break;
case ResponseStatus.Error:
response = "{ \"ErrorMessage\" : \"Unspecified error: " + restResponse.ErrorMessage + " \"}";
break;
case ResponseStatus.TimedOut:
response = "{ \"ErrorMessage\" : \"Request timed out\"}";
break;
case ResponseStatus.Aborted:
response = "{ \"ErrorMessage\" : \"Request aborted\"}";
break;
default:
response = "{ \"ErrorMessage\" : \"Unspecified response type.\"}";
break;
}
}
else
{
response = "{ \"ErrorMessage\" : \"Attachment file not specified.\"}";
}
}
catch (Exception ex)
{
response = "{ \"ErrorMessage\" : \"Unspecified error: " + ex.Message + " \"}";
}
return response;
}

Rest api get curl C#

I am getting 401 access error when running the below code. Can someone please tell me what I am doing wrong. thanks
The Curl provided is: curl -X GET --header "Authorization: " --header "Authorization: Bearer kgffj*dfkgj40fdgjkjkdfjUHHHDNhdfj" "https://api.united.com/v1/accounts"
string url = "https://api.united.com/v1/accounts";
WebRequest myReq = WebRequest.Create(url);
string credentials = "kgffj*dfkgj40fdgjkjkdfjUHHHDNhdfj";
CredentialCache mycache = new CredentialCache();
myReq.Headers["Authorization"] = "Bearer " + Convert.ToBase64String(Encoding.ASCII.GetBytes(credentials));
WebResponse wr = myReq.GetResponse();
Stream receiveStream = wr.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
string content = reader.ReadToEnd();
Console.WriteLine(content);
var json = "[" + content + "]"; // change this to array
var objects = JArray.Parse(json); // parse as array
foreach (JObject o in objects.Children<JObject>())
{
foreach (JProperty p in o.Properties())
{
string name = p.Name;
string value = p.Value.ToString();
Console.Write(name + ": " + value);
}
}
Console.ReadLine();
The curl request would be represented like this in C#
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("GET"), "https://api.united.com/v1/accounts"))
{
request.Headers.TryAddWithoutValidation("Authorization", "Bearer kgffj*dfkgj40fdgjkjkdfjUHHHDNhdfj");
var response = await httpClient.SendAsync(request);
}
}
I could not test this code as the url https://api.united.com/v1/accounts times out from my system. But This should work.
As others have pointed out you should not need to convert the token to base 64 as its not converted to base64 in the curl
I am assuming that you want to perform the same request that you would run if you use the curl command in your question
The code provided above fixes the http request.
The response object in the above code is of Type HttpResponseMessage
This object has a HttpResponseMessage.Content Property on it
This Content is of type HttpContent and it has a public method ReadAsStringAsync() which will
Serialize the HTTP content to a string as an asynchronous operation.
and that is your JSON content that you are looking for.
So your code should look like this
public static async Task<string> GetData()
{
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("GET"), "https://api.united.com/v1/accounts"))
{
request.Headers.TryAddWithoutValidation("Authorization", "Bearer kgffj*dfkgj40fdgjkjkdfjUHHHDNhdfj");
var response = await httpClient.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
}
}
This method is an async method,Since the code you provided in the question is not async you would need to use
string json = GetData().Result;
if you want to use it in a non async function
or if you change your method calling this method to async then you can use the await keyword like this
string json = await GetData();
It is unlikely you can just hardcode an OAuth Bearer token. You need to lookup the details for authentication for that specific API to see how to obtain a Bearer token for use in the API.

C# RestClient returning "Login Required" when Login Details are specified

Just started at a new company and we all use Jira, the customers are determined to not use it as they don't like it so I have decided to build a simple Windows Form when they can both Log tickets and get Updates and Comments in a nice simple UI.
Now I have never done any coding before 2 weeks ago so it has been a struggle to get my head around both C# and Rest (Have made scripts for basic IT fixes but never anything as complex as this!)
Back onto point, Set up and got a Rest API set up with a Rest Client but everytime I try pull data from a ticket on Jira I get the error:
{"errorMessages":["You do not have the permission to see the specified issue.","Login Required"],"errors":{}}
Here is the code from the Form:
private void button3_Click_1(object sender, EventArgs e)
{
var client = new RestClient("https://jira.eandl.co.uk/rest/api/2/issue/ITREQ-" + textBox1.Text
);
client.Authenticator = new SimpleAuthenticator("username", "abc", "password", "123");
var request = new RestRequest(Method.GET);
request.AddParameter("token", "saga001", ParameterType.UrlSegment);
// request.AddUrlSegment("token", "saga001");
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
var queryResult = client.Execute(request);
Console.WriteLine(queryResult.Content);
}
And here is the code from the Rest Client itself:
public Restclient()
{
endPoint = string.Empty;
httpMethod = httpVerb.GET;
}
private string logonAttempt;
public string makeRequest()
{
string strResponseValue = string.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
request.Method = httpMethod.ToString();
String authHeader = System.Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(userName + ":" + userPassword));
request.Headers.Add("Authorization", authType.ToString() + " " + authHeader);
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
//Process the Response Stream... (Could be JSON, XML ot HTML etc...)
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream))
{
strResponseValue = reader.ReadToEnd();
}//End of Stream Reader
}
}//end of Response Stream
}
catch (Exception ex)
{
strResponseValue = "(\"errorMessages\":[\"" + ex.Message.ToString() + "\"],\"errors\":{}}";
}
finally
{
if(response != null)
{
((IDisposable)response).Dispose();
}
}
return strResponseValue;
}
}
}
Now obviously I am expecting that I have missed something absolutely bigginer as like I said, I've never taken on a project like this before and had 0 experience.
Just looking for someone to bluntly tell me what I'm doing wrong
Changed to this as per answer:
private void button3_Click_1(object sender, EventArgs e)
{
var client = new
RestClient("https://jira.eandl.co.uk/rest/api/2/issue/ITREQ-" + textBox1.Text
);
client.Authenticator = new HttpBasicAuthenticator("username", "password");
var request = new RestRequest(Method.GET);
string authHeader = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("cdale!" + ":" + "Chantelle95!"));
request.AddHeader("Authorization", "Basic " + authHeader);
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
var queryResult = client.Execute(request);
Console.WriteLine(queryResult.Content);
}
By default with the Jira REST API, you can use Basic Authentication or OAuth2. I think that more easy way for you will be to use the Basic one.
I'm not sure why you have a class where you define your custom RestClient since the first block of code uses the RestSharp one from http://restsharp.org.
In this case, you will need to modify your authenticator:
client.Authenticator = new HttpBasicAuthenticator(userName, password);
And I think that you should remove the line where you specify a token. I don't think that it's required.
Finally, the class Restclient doesn't seem to be used, then remove it.
You could also uses what you have created in your custom RestClient and manually specify a Basic header:
string authHeader = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(userName + ":" + userPassword));
request.AddHeader("Authorization", "Basic " + authHeader);
However, it's essentially the behavior of the HttpBasicAuthenticator class.
If you don't want to encode your credentials in every request here is how to do it using cookies.
When requesting the cookie you don't need to add any authorization on the headers. This method will accept a JSON string with the user name and password and the URL. It will return the cookie values.
public async Task<JiraCookie> GetCookieAsync(string myJsonUserNamePassword, string JiraCookieEndpointUrl)
{
using (var client = new HttpClient())
{
var response = await client.PostAsync(
JiraCookieEndpointUrl,
new StringContent(myJsonUserNamePassword, Encoding.UTF8, "application/json"));
var json = response.Content.ReadAsStringAsync().Result;
var jiraCookie= JsonConvert.DeserializeObject<JiraCookie>(json);
return jArr;
}
}
public class JiraCookie
{
public Session session { get; set; }
}
public class Session
{
public string name { get; set; }
public string value { get; set; }
}
When I call it using url: http://[baseJiraUrl]/rest/auth/1/session it returns the following JSON response:
{
"session" : -{
"name" : JSESSIONID,
"value" : cookieValue
}
Keep in mind the URL above is valid in the version of JIRA I'm using and may vary depending on which version you're using. Read the JIRA API documentation for the correct URL for the version you are using. I'm using the following:
https://docs.atlassian.com/software/jira/docs/api/REST/7.6.1/#auth/1/session
Remember you'll have to store your cookie and use it on every subsequent request.
Check out this answer on how add cookies to your HttpClient request: How do I set a cookie on HttpClient's HttpRequestMessage.
Once you're done with the cookie (logging out) simply send a delete http request with the same URL as the post.
Reference: https://stackoverflow.com/a/49109192/7763903

JavaScriptSerializer of JSON

Just need some help to send a POST in C# that has the same data as the following curl
curl -v -u {email_address}:{password} https://{subdomain}.zendesk.com/api/v2/users.json \
-H "Content-Type: application/json" -X POST -d '{"user": {"name": "Roger Wilco", "email": "roge#example.org"}}'
I have the basic stuff below just need to change a bit not sure how... the issue is I am no sure how to create a json of {"user": {"name": "Roger Wilco", "email": "roge#example.org"}}
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://home67.zendesk.com/api/v2/users.json");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
User user = new User();
user.email = this.email;
user.name = this.name;
string json = new JavaScriptSerializer().Serialize(user);
WriteObject(json.ToString());
// the above currently only gives {"name":"something", "email":"something#something"}
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
WriteObject(result);
}
The simplest way is probably to serialize an anonymous type with a user property:
string json = new JavaScriptSerializer().Serialize(new { user = user });
// {"user":{"name":"Roger Wilco","email":"roger#example.org"}}

Categories