Multipart file upload via HTTPClient C# - c#

I am trying to convert a post request presented via cURL to c# HTTPClient with an old application using .NETFramework4
The cURL notation of the request from API docs:
curl -X POST -H 'Authorization: Token token=sfg999666t673t7t82' -H 'Content-Type: multipart/form-data' -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' -F file=#/Users/user1/Downloads/download.jpeg -F file_name=nameForFile -F is_shared=true -F targetable_id=1 -F targetable_type=Lead -X POST "https://domain.freshsales.io/api/documents"
My C# code, currently taking a file the user uploaded via input type form and trying to upload:
var filename = String.Format("status_{0}", DateTime.Now.ToString("dd/MM"));
using (var content = new MultipartFormDataContent())
{
content.Add(new ByteArrayContent(file), "file", filename);
content.Add(new StringContent(filename), "file_name");
content.Add(new StringContent("true"), "is_shared");
content.Add(new StringContent(uID), "targetable_id");
content.Add(new StringContent("Contact"), "targetable_type");
HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, $"documents") { Content = content };
return client.SendAsync(req).Result;
}
For now I always get BadRequest(400)
In PostMan I am able to get OK(201)..
For more reference this is the code PostMan presents for C# RestSharp (not sure how to fully translate if to HttpClient + byteArrayContent..
var client = new RestClient("mydomain.io/api/documents");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Token token=xxx");
request.AddFile("file", "/Users/user1/Desktop/sc.png");
request.AddParameter("targetable_id", "134");
request.AddParameter("targetable_type", "Contact");
request.AddParameter("name", "a.jpg");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

Related

Converting Curl to C# with RestSharp

I'm trying to convert this curl command to C# using RestSharp, and I'm having problems specifically with the data parameter (token and uri variables have been replaced w/dummy values for this example):
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'UserToken: usertoken' --header 'AppToken: apptoken' -d '[{"individualRecordNumber":"foo","score":"bar"}]' 'apiEndpoint'
I've been able to successfully do several GET requests within this same API, so I'm good with the overall request format and headers, I'm just having issues figuring out how to format the data and where to append it. Here's the rest of the request without the data:
var client = new RestClient(apiEndpoint);
var request = new RestRequest(Method.POST);
request.AddHeader("usertoken", usertoken);
request.AddHeader("apptoken", apptoken);
request.AddHeader("content-type", "application/json");
IRestResponse response = client.Execute(request);
I've tried using both AddParameter and AddJsonBody with various combinations of serialized and unserialized versions of the data.
Example of building data directly as string:
string examInfo = #"[{""individualRecordNumber"":""foo"",""score"":""bar""}]";
Example of building data as object:
object[] arrayObj = new object[1];
arrayObj[0] = new { individualRecordNumber = "foo", score = "bar" };
This is for a project with an extremely tight turnaround, so any help is much appreciated!
If you need a Post, to "wire in" the Post-Body, AddParameter has this overload
request.AddParameter("application/json", "mybody", ParameterType.RequestBody);
or , in your case
request.AddParameter("application/json", examInfo, ParameterType.RequestBody);
but maybe better (if you have later version)
request.AddJsonBody(new { A = "foo", B = "bar" });
And the initial constructor: (which you seem to have, but making sure to note it for future readers)
var request = new RestRequest(Method.POST);
More full example:
var client = new RestClient("https:blahblahblah");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/json");
/* option1 */
request.AddParameter("application/json", "{mybody:'yes'}", ParameterType.RequestBody);
/* OR option 2 */
request.AddJsonBody(new { A = "foo", B = "bar" });
IRestResponse response = client.Execute(request);

Unable to recreate this postman request in C# web api - unsupported_grant_type

I am trying to re-create a postman request in C#. Below a screenshot of the postman request that works:
(The header is application/json)
and the C# that does not:
[HttpGet]
[Route("GenerateAccessToken")]
[ProducesResponseType(typeof(bool), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(bool), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(bool), (int)HttpStatusCode.InternalServerError)]
public async Task<ActionResult<AccessTokenResponse>> GenerateAccessToken()
{
var client = new HttpClient();
MultipartFormDataContent clientData = new MultipartFormDataContent
{
{ new StringContent("[Removed]"), "client_id" },
{ new StringContent("[Removed]"), "client_secret" },
{ new StringContent("client_credentials"), "grant_type" },
};
try
{
var responseObject = new AccessTokenResponse();
var response = await client.PostAsync(AccessTokenEndpoint, clientData);
var responseString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
responseString = await response.Content.ReadAsStringAsync();
responseObject = JsonConvert.DeserializeObject<AccessTokenResponse>(responseString);
return Ok(responseObject);
}
return StatusCode(400, responseObject);
}
catch (Exception ex)
{
Logger.Log(ex);
return StatusCode(500, false);
}
}
The response from the C# code is:
{"error":"unsupported_grant_type","error_description":"Use \"authorization_code\" or \"refresh_token\" or \"client_credentials\" or \"urn:ietf:params:oauth:grant-type:jwt-bearer\" as the grant_type.","error_uri":"https://developer.salesforce.com/docs"}
I am very confused as to what I am missing. I clearly have the grant_type provided. However not matter what I set grant_type to I get the same error message listed above. I suspected it might be something to do with the content-type. On the valid request in Postman I clicked code -> then cURL and it gave me this:
curl -X POST \
https://[removed].auth.marketingcloudapis.com/v2/token \
-H 'Content-Type: application/json' \
-H 'Postman-Token: f469a34a-194e-44b4-82aa-c5d46a1528f7' \
-H 'cache-control: no-cache' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F client_id=[removed] \
-F client_secret=[removed] \
-F grant_type=client_credentials
I tried adding the missing headers to my request by doing this (just above the try block):
clientData.Headers.TryAddWithoutValidation("Content-Type", "application/json");
clientData.Headers.TryAddWithoutValidation("Content-type", "multipart/form-data");
//clientData.Headers.TryAddWithoutValidation("Content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
But then I was met with error 500 responses (if I have application/json and multipart/form-data) and Unsupported Media Type if I just have application/json
I am completely stumped here. Any ideas what I am doing wrong?

How to call Google Cloud API using RestSharp and OAuth 2

I'm trying to call the google cloud API. Specifically, the language API from c# using the RestSharp library and OAuth 2. I'm able to successfully connect to the API using the curl call below:
curl -s -k -H "Content-Type: application/json" -H "Authorization: Bearer <access_token>"
https://language.googleapis.com/v1beta1/documents:annotateText
-d #c:\temp\entity_request.json > c:\temp\googleanalysis.json
I've tried several different ways of authenticating, but none of them so far have worked. My latest c# code looks like the following:
var client = new RestClient("https://language.googleapis.com");
client.Authenticator = new RestSharp.Authenticators.HttpBasicAuthenticator("client-app", "<access_token>");
var request = new RestRequest("/v1beta1/documents:analyzeEntities", Method.POST);
request.AddHeader("Content-Type", "application/json");
request.AddFile("filename", #"c:\temp\entity_request.json");
var response = client.Execute(request);
var content = response.Content;
When I run this call from c# I get the following error back:
{
"error": {
"code": 403,
"message": "The request cannot be identified with a client project. Please pass a valid API key with the request.",
"status": "PERMISSION_DENIED"
}
}
My question is how do I properly call the google cloud API in RestSharp the way I am successfully with curl?
This works for me:
//obtenemos el token para las peticiones
string access_token = GetAccessToken(jsonFolder, new string[] { "https://www.googleapis.com/auth/cloud-platform" });
//peticiones hacia el rest de automl
var client = new RestClient("https://language.googleapis.com");
var request = new RestRequest("v1/documents:analyzeEntities", Method.POST);
request.AddHeader("Authorization", string.Format("Bearer {0}", access_token));
request.AddHeader("Content-Type", "aplication/json");
//seteamos el objeto
var aml = new AutoMLload_entities();
aml.document.content = text;
request.AddJsonBody(aml);
IRestResponse response = client.Execute(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{

How do I send the cURL request shown below using System.Net.Http?

I am trying to use Zendesk's ticket submission API and in their documentation they give the following example in cURL:
curl https://{subdomain}.zendesk.com/api/v2/tickets.json \
-d '{"ticket": {"requester": {"name": "The Customer", "email": "thecustomer#domain.com"}, "subject": "My printer is on fire!", "comment": { "body": "The smoke is very colorful." }}}' \
-H "Content-Type: application/json" -v -u {email_address}:{password} -X POST
I'm trying to make this POST request using the System.Net.Http library:
var httpClient = new HttpClient();
HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(model));
if (httpContent.Headers.Any(r => r.Key == "Content-Type"))
httpContent.Headers.Remove("Content-Type");
httpContent.Headers.Add("Content-Type", "application/json");
httpContent.Headers.Add("Authorization", String.Format("Basic {0}", Convert.ToBase64String(Encoding.ASCII.GetBytes("{user}:{password}"))));
var httpResult = httpClient.PostAsync(WebConfigAppSettings.ZendeskTicket, httpContent);
I keep getting an error when I try to add the Authorization header to the content. I understand now that HttpContent is only supposed to contain content type headers.
How do I create and send a POST request where I can set the Content-Type header, the Authorization header, and include Json in the body using the System.Net.Http library?
I used the code below to build my request:
HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(new { ticket = model }));
if (httpContent.Headers.Any(r => r.Key == "Content-Type"))
httpContent.Headers.Remove("Content-Type");
httpContent.Headers.Add("Content-Type", "application/json");
var httpRequest = new HttpRequestMessage()
{
RequestUri = new Uri(WebConfigAppSettings.ZendeskTicket),
Method = HttpMethod.Post,
Content = httpContent
};
httpRequest.Headers.Add("Authorization", String.Format("Basic {0}", Convert.ToBase64String(Encoding.UTF8.GetBytes(#"{username}:{password}"))));
httpResult = httpClient.SendAsync(httpRequest);
Basically, I build the content separately adding the body and setting the header. I then added the authentication header to the httpRequest object. So i had to add the content headers to the httpContent object and the authorization header to the httpRequest object.

How to send POST request in Xamarin?

I've built my backend in rails.
My email address is "sample#zmail.com" and it's already registered. The password is "28902890" here
After giving the following command in terminal
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST https://auth-agdit.herokuapp.com/api/v1/sessions -d "{\"user\":{\"email\":\"sample#zmail\",\"password\":\"28902890\"}}"
I get this response from my backend,
{"success":true,"info":"Logged in :) ","data":{"authentication_token":"iexGFwJ6HwERQZ3wJ4NG"}}
Now I need to get this data from my Android app.
I can get json by using WebClient().downloadString() method for simple json where authentication is not needed and the request method is GET.
Now I need to get the output Json for POST method.
How can I accomplish that?
There are several methods of doing this. You could use the Xamarin component called RestSharp. This will provide you with easy methods of interfacing with your backend.
var request = new RestRequest("resource/{id}", Method.POST);
request.AddParameter("name", "value"); // adds to POST or URL querystring based on Method
request.AddUrlSegment("id", 123); // replaces matching token in request.Resource
// add parameters for all properties on an object
request.AddObject(object);
// execute the request
RestResponse response = client.Execute(request);
If you do want to simply use the WebClient class provided by the BCL you can use the WebClient.UploadString(string, string) method like so:
using (WebClient client = new WebClient())
{
string json = "{\"user\":{\"email\":\"sample#zmail\",\"password\":\"28902890\"}}";
client.UploadString("https://example.com/api/v1/sessions, json);
}
If you need more control over the request (such as setting accept headers, etc.) then you can use HttpRequest, see this question for an example of that.
This is how I did it:
WebClient wc = new WebClient();
string baseSiteString = wc.DownloadString("https://auth-agdit.herokuapp.com");
string csrfToken = Regex.Match(baseSiteString, "<meta name=\"csrf-token\" content=\"(.*?)\" />").Groups[1].Value;
string cookie = wc.ResponseHeaders[HttpResponseHeader.SetCookie];
Console.WriteLine("CSRF Token: {0}", csrfToken);
Console.WriteLine("Cookie: {0}", cookie);
wc.Headers.Add(HttpRequestHeader.Cookie, cookie);
wc.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
wc.Headers.Add(HttpRequestHeader.Accept, "application/json, text/javascript, */*; q=0.01");
wc.Headers.Add("X-CSRF-Token", csrfToken);
wc.Headers.Add("X-Requested-With", "XMLHttpRequest");
string dataString = #"{""user"":{""email"":""email_here"",""password"":""password_here""}}";
// string dataString = #"{""user"":{""email"":"""+uEmail+#""",""password"":"""+uPassword+#"""}}";
byte[] dataBytes = Encoding.UTF8.GetBytes(dataString);
byte[] responseBytes = wc.UploadData(new Uri("https://auth-agdit.herokuapp.com/api/v1/sessions.json"), "POST", dataBytes);
string responseString = Encoding.UTF8.GetString(responseBytes);
Console.WriteLine(responseString);
Try with this code:
Uri address = new Uri("http://example.com/insert.php");
NameValueCollection nameValueCollection = new NameValueCollection();
nameValueCollection["Name"] = "string-input";
var webClient = new WebClient();
webClient.UploadValuesAsync(address, "POST", nameValueCollection);

Categories