I'm trying to upload an image with a POST request with an API call.
Getting the image from the gallery works. By using:
StartActivityForResult(
Intent.CreateChooser(imageIntent, "Select photo"), 0);
With that, I receive an intent with different paths like:
EncodedSchemeSpecificPart,
EncodedPath,
Path, etc.
I've tested the API call with POSTMAN, as form-data that has a file with the keyname file and also an auth-token inside the header. This works.
Now my question is, how do I add a file(image) in a POST call with C#?
This is what I have so far:
try
{
Uri url = new Uri(basePath + "/pictures");
HttpWebRequest request =
(HttpWebRequest)HttpWebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "POST";
request.Headers.Add("auth-token", accesstoken);
return null;
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
return null;
}
edit: the backend code:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public Response uploadFile(#HeaderParam("Auth-Token") String token,
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataBodyPart body) throws RequestException {
secure(token, "*");
// Get the user data using the entity manager
String subtype = body.getMediaType().getSubtype();
switch(subtype) {
case "jpeg":
case "jpg":
case "png":
break;
default:
return Response.status(Response.Status.BAD_REQUEST).build();
}
String imageName = UUID.randomUUID().toString() + "." + subtype;
String uploadedFileLocation = context.getRealPath("/images/"+imageName);
Picture picture = pictureService.createPictureReference(uploadedFileLocation);
// Store the file
try {
writeToFile(uploadedInputStream, uploadedFileLocation);
// If the file is stored
return Response.status(Response.Status.OK).entity(picture).build();
} catch (IOException e){
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
You can StartActivityForResult using an intent that returns the chosen image so you can obtain a stream from
StartActivityForResult (Image picker/gallery)
using (var intent = new Intent())
{
intent.SetType("image/*");
intent.SetAction(Intent.ActionGetContent);
StartActivityForResult(Intent.CreateChooser(intent, "Select Image To Upload"), PickImage);
}
Now in your OnActivityResult you can use the ContentResolver to obtain a stream from the picked image that you can Post as binary (octet-stream) or convert it to base64 (application/json) to match your MultipartFormDataContent API/Post requirements.
Note: Using Jersey?, as I am not sure how to interpret the InputStream vs FormDataBodyPart params when using json, is the InputStream in base64?
OnActivityResult and HttpClient Post w/ StreamContent
const string url = "http://10.0.2.2:5000/api/image";
AndroidClientHandler handler;
HttpClient client;
protected async override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
string access_token = "some oauth2 token";
if (resultCode.HasFlag(Result.Ok) && requestCode == PickImage)
{
using (var imageStream = ContentResolver.OpenInputStream(data.Data))
{
await Task.Run(async () =>
{
handler = handler ?? new AndroidClientHandler();
client = client ?? new HttpClient(handler);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("OAuth2", access_token);
if (!client.DefaultRequestHeaders.Contains("Accept"))
{
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
client.Timeout = TimeSpan.FromSeconds(30);
}
using (var content = new StreamContent(imageStream))
using (var response = await client.PostAsync(url, content))
{
Log.Debug(TAG, $"Post: {response.StatusCode} : {response.IsSuccessStatusCode}");
}
}).ContinueWith((task) =>
{
Log.Debug(TAG, $"Post: {task.Status}");
if (task.IsFaulted)
{
Log.Debug(TAG, $"Post Faulted: {task.Exception.Message}");
Log.Debug(TAG, $"Post Faulted: {task.Exception?.InnerException.Message}");
}
});
}
}
}
Update:
Based upon needing to post something like this:
POST /pictures HTTP/1.1
Host: 127.0.0.1:60000
auth-token: some_token_here
Cache-Control: no-cache
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="foobar.png"
Content-Type: image/png
------WebKitFormBoundary7MA4YWxkTrZu0gW--
MultipartFormDataContent with image content:
await Task.Run(async () =>
{
handler = handler ?? new AndroidClientHandler();
client = client ?? new HttpClient(handler);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("auth-token", access_token);
using (var imageStream = ContentResolver.OpenInputStream(data.Data))
using (var streamContent = new StreamContent(imageStream))
using (var byteArrayContent = new ByteArrayContent(await streamContent.ReadAsByteArrayAsync()))
using (var formDataContent = new MultipartFormDataContent())
{
formDataContent.Add(byteArrayContent, "file", "DummyFileName.NotUsedOnServer");
foreach (var content in formDataContent)
{
content.Headers.ContentType = new MediaTypeHeaderValue(ContentResolver.GetType(data.Data));
break;
}
using (var response = await client.PostAsync(url, formDataContent))
{
Log.Debug(TAG, $"Post: {response.StatusCode} : {response.IsSuccessStatusCode}");
}
}
}).ContinueWith((task) =>
{
Log.Debug(TAG, $"Post: {task.Status}");
if (task.IsFaulted)
{
Log.Error(TAG, $"Post Faulted: {task.Exception.Message}");
Log.Error(TAG, $"Post Faulted: {task.Exception?.InnerException.Message}");
}
});
Related
I've written a python function to move a router's IO port via a HTTP post request with Basic Authentivation. This works fine. But now I'd like to implement the sam with C#.
Here is my python function:
def io_on(ip='192.168.2.1', username='adm', password='123456'):
if not isinstance(ip, str):
print('not string')
try:
payload ='_ajax=1&_web_cmd=%21%0Aio%20output%201%20on%0A'
r = requests.post('http://{}/apply.cgi'.format(ip), auth=HTTPBasicAuth(username, password), data=payload, timeout=3)
if r.status_code == 200:
print('{} : IO ON'.format(ip))
elif r.status_code == 401:
print('{} : Auth error'.format(ip))
else:
print(r.status_code)
except Exception as e:
print(e)
I've experimented with NetWorkCredentials with no success.
Something like this :
try
{
string username = "adm", password = "123456";
string payload = "http://192.168.2.1/apply.cgi/?_ajax=1&_web_cmd=%21%0Aio%20output%201%20on%0A";
HttpClient client = new HttpClient();
var byteArray = Encoding.ASCII.GetBytes($"{username}:{password}");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
HttpResponseMessage response = await client.GetAsync(payload);
HttpContent content = response.Content;
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Success");
}
else if (response.StatusCode == HttpStatusCode.Unauthorized)
{
Console.WriteLine("Auth error");
}
else
{
Console.WriteLine(response.StatusCode);
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
Here's my way to make POST with basic authentication.
var authValue = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{login}:{password}")));
using (var client = new HttpClient() { DefaultRequestHeaders = { Authorization = authValue } })
{
HttpResponseMessage response = client.PostAsync("https://localhost:44396/Documentation/All?pageNumber=0&pageSize=10", httpContent).Result;
if (response.IsSuccessStatusCode)
{
response = await response.Content.ReadAsStringAsync();
}
}
How to post video to endpoint of the videoindexer "https://videobreakdown.azure-api.net/Breakdowns/Api/Partner/Breakdowns".
static async void MakeRequest()
{
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
// Request headers
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "mykey");
// Request parameters
queryString["name"] = "name";
queryString["privacy"] = "Private";
var uri = "https://videobreakdown.azure-api.net/Breakdowns/Api/Partner/Breakdowns?" + queryString;
HttpResponseMessage response;
// Request body
using (var content = new MultipartFormDataContent())
{
content.Add(new StreamContent(File.Open(#"file", FileMode.Open)), "file", "filename");
try
{
response = await client.PostAsync(uri, content);
Console.WriteLine(response);
}
catch (Exception e)
{
}
}
}
I am getting "A Task was canceled" exception. Please help.
The api works fine when i am using videourl
It was because while trying to upload, my request was getting timed out.
I added
client.Timeout = TimeSpan.FromMinutes(30);
and now it's fixed.
I need to postAsync with header and content together. In order to get access to a website through Console Application in C#. I have my headers as an HttpHeader object with variable name header and my content named newContent as a string object with __Token, return, Email and Password. Now what I want to do is add newContent to header and then use postAsync(url, header+content) to make my POST request.
public async static void DownloadPage(string url)
{
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
using (HttpClient client = new HttpClient(handler))
{
using (HttpResponseMessage response = client.GetAsync(url).Result)
{
//statusCode
CheckStatusCode(response);
//header
HttpHeaders headers = response.Headers;
//content
HttpContent content = response.Content;
//getRequestVerificationToken&createCollection
string newcontent = CreateCollection(content);
using(HttpResponseMessage response2 = client.PostAsync(url,))
}
}
}
public static string GenerateQueryString(NameValueCollection collection)
{
var array = (from key in collection.AllKeys
from value in collection.GetValues(key)
select string.Format("{0}={1}", WebUtility.UrlEncode(key), WebUtility.UrlEncode(value))).ToArray();
return string.Join("&", array);
}
public static void CheckStatusCode(HttpResponseMessage response)
{
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception(String.Format(
"Server error (HTTP {0}: {1}).",
response.StatusCode,
response.ReasonPhrase));
else
Console.WriteLine("200");
}
public static string CreateCollection(HttpContent content)
{
var myContent = content.ReadAsStringAsync().Result;
HtmlNode.ElementsFlags.Remove("form");
string html = myContent;
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
var input = doc.DocumentNode.SelectSingleNode("//*[#name='__Token']");
var token = input.Attributes["value"].Value;
//add all necessary component to collection
NameValueCollection collection = new NameValueCollection();
collection.Add("__Token", token);
collection.Add("return", "");
collection.Add("Email", "11111111#hotmail.com");
collection.Add("Password", "1234");
var newCollection = GenerateQueryString(collection);
return newCollection;
}
I did the very same thing yesterday. I created a seperate class for my Console App and put the HttpClient stuff in there.
In Main:
_httpCode = theClient.Post(_response, theClient.auth_bearer_token);
In the class:
public long Post_RedeemVoucher(Response _response, string token)
{
string client_URL_voucher_redeem = "https://myurl";
string body = "mypostBody";
Task<Response> content = Post(null, client_URL_voucher_redeem, token, body);
if (content.Exception == null)
{
return 200;
}
else
return -1;
}
Then the call itself:
async Task<Response> Post(string headers, string URL, string token, string body)
{
Response _response = new Response();
try
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, URL);
request.Content = new StringContent(body);
using (HttpResponseMessage response = await client.SendAsync(request))
{
if (!response.IsSuccessStatusCode)
{
_response.error = response.ReasonPhrase;
_response.statusCode = response.StatusCode;
return _response;
}
_response.statusCode = response.StatusCode;
_response.httpCode = (long)response.StatusCode;
using (HttpContent content = response.Content)
{
_response.JSON = await content.ReadAsStringAsync().ConfigureAwait(false);
return _response;
}
}
}
}
catch (Exception ex)
{
_response.ex = ex;
return _response;
}
}
I hope this points you in he right direction!
How about iterating over your Headers and adding them to the Content object:
var content = new StringContent(requestString, Encoding.UTF8);
// Iterate over current headers, as you can't set `Headers` property, only `.Add()` to the object.
foreach (var header in httpHeaders) {
content.Headers.Add(header.Key, header.Value.ToString());
}
response = client.PostAsync(Url, content).Result;
Now, they're sent in one method.
If you are still looking into this you can also add headers at the request level as well as the HttpClient level. This works for me:
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, URL);
request.Content = new StringContent(body);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
I'm currently using Pushbullet API and need to upload a file.
I can successfully get an upload url as specified in the docs using this method:
public static async Task<Uploads> GetUploadUrl(string file_name, string file_type)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var json = new JObject
{
["file_name"] = file_name,
["file_type"] = file_type
};
var result = await client.PostAsync(new Uri(_uploadUrl, UriKind.RelativeOrAbsolute), new HttpStringContent(json.ToString(), UnicodeEncoding.Utf8, "application/json"));
if (result.IsSuccessStatusCode)
{
var textresult = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Uploads>(textresult);
}
}
return null;
}
The problem is when I try to upload the file. I'm currently using this method:
public static async Task<bool> UploadFile(StorageFile file, string upload_url)
{
try
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
if (file != null)
{
var streamData = await file.OpenReadAsync();
var bytes = new byte[streamData.Size];
using (var dataReader = new DataReader(streamData))
{
await dataReader.LoadAsync((uint)streamData.Size);
dataReader.ReadBytes(bytes);
}
var streamContent = new ByteArrayContent(bytes);
content.Add(streamContent);
}
client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var response = await client.PostAsync(new Uri(upload_url, UriKind.Absolute), content);
if (response.IsSuccessStatusCode)
return true;
}
catch { return false; }
return false;
}
but I get a Http 400 error. What's the right way to upload a file using multipart/form-data in a UWP app?
HTTP 400 error indicates Bad Request, it means the request could not be understood by the server due to malformed syntax. In the other word, the request sent by the client doesn't follow server's rules.
Let's look at the document, and we can find in the example request it uses following parameter:
-F file=#cat.jpg
So in the request, we need to set the name for the uploaded file and the name should be "file". Besides, in this request, there is no need to use access token. So you can change your code like following:
public static async Task<bool> UploadFile(StorageFile file, string upload_url)
{
try
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
var content = new MultipartFormDataContent();
if (file != null)
{
var streamData = await file.OpenReadAsync();
var bytes = new byte[streamData.Size];
using (var dataReader = new DataReader(streamData))
{
await dataReader.LoadAsync((uint)streamData.Size);
dataReader.ReadBytes(bytes);
}
var streamContent = new ByteArrayContent(bytes);
content.Add(streamContent, "file");
}
//client.DefaultRequestHeaders.Add("Access-Token", AccessToken);
var response = await client.PostAsync(new Uri(upload_url, UriKind.Absolute), content);
if (response.IsSuccessStatusCode)
return true;
}
catch { return false; }
return false;
}
Then your code should be able to work. You will get a 204 No Content response and UploadFile method will return true.
I have to post the multipart data to the server but I am getting below error
I am using the below code
public async static Task<string> HttpImagePostMethod(byte[] wInputData, string Uri, string path)
{
string result = string.Empty;
try
{
#region For Https (Secure) Api having SSL
var filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(Windows.Security.Cryptography.Certificates.ChainValidationResult.Untrusted);
var client = new System.Net.Http.HttpClient(new WinRtHttpClientHandler(filter));
#endregion
MultipartFormDataContent requestContent = new MultipartFormDataContent();
// StreamContent content = new StreamContent(wInputData);
var content = new ByteArrayContent(wInputData);
content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
requestContent.Add(content, "file", path);
requestContent.Headers.Add("X-API-Key", UrlFactory.X_API_Key_Value);
requestContent.Add(new StringContent("144"), "type");
HttpResponseMessage aResp = await client.PostAsync(UrlFactory.BaseUrl + Uri, requestContent);
if (aResp.IsSuccessStatusCode)
{
result = await aResp.Content.ReadAsStringAsync();
}
else
{
result = await aResp.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
result = string.Empty;
}
return result;
}
I am getting error at this line
HttpResponseMessage aResp = await client.PostAsync(UrlFactory.BaseUrl + Uri, requestContent);
Due to this line
requestContent.Headers.Add("X-API-Key", UrlFactory.X_API_Key_Value);
Myself Answer this question maybe helpful to my other friends...
HttpRequestMessage httpRequest = new HttpRequestMessage();
httpRequest.Method = HttpMethod.Post;
httpRequest.RequestUri = new System.Uri(UrlFactory.BaseUrl + Uri);
httpRequest.Content = requestContent;
httpRequest.Headers.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded");
httpRequest.Headers.TryAddWithoutValidation("X-API-Key", UrlFactory.X_API_Key_Value);
Client(HttpClient) shouldn't contain any header, we declaring header in HttpRequestMessage
As the error message says, you're trying to set a header on the content but it doesn't belong there; your API token is a property of the request itself and not of its content.
Try adding that header to client.DefaultRequestHeaders instead.