I am trying to read file from S3 using below code:
var dir = new S3DirectoryInfo(_amazonS3Client, bucketName, folderName);
IS3FileSystemInfo[] files = dir.GetFileSystemInfos();
if(files.Length > 0)
{
_bucketKey = files[0].Name;
var request = new GetObjectRequest
{
BucketName = bucketName,
Key = $"{folderName}/{_bucketKey}"
};
using (GetObjectResponse response = await _amazonS3Client.GetObjectAsync(request))
using (Stream responseStream = response.ResponseStream)
using (var reader = new StreamReader(responseStream))
{
var responseBody = reader.ReadToEnd();
File.WriteAllText(newFilePath, responseBody);
}
}
It is working fine for a non-compressed file, however, I need some suggestions on how could I read the .xz file? My file is like DummyData_2020-07-21.csv.xz
I found a solution using SharpCompress and below code worked for me
var request = new GetObjectRequest
{
BucketName = bucketName,
Key = $"{folderName}/{bucketKey}"
};
using (var obj = _amazonS3Client.GetObject(request))
{
obj.WriteResponseStreamToFile($"{fileLocation}{bucketKey}");
}
using (Stream xz = new XZStream(File.OpenRead($"{fileLocation}{bucketKey}")))
using (TextReader reader = new StreamReader(xz))
{
var responseBody = reader.ReadToEnd();
File.WriteAllText(newFilePath, responseBody);
}
Related
Does anyone know how to use the HttpClient in .Net 4.5 with multipart/form-data upload?
I couldn't find any examples on the internet.
my result looks like this:
public static async Task<string> Upload(byte[] image)
{
using (var client = new HttpClient())
{
using (var content =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
content.Add(new StreamContent(new MemoryStream(image)), "bilddatei", "upload.jpg");
using (
var message =
await client.PostAsync("http://www.directupload.net/index.php?mode=upload", content))
{
var input = await message.Content.ReadAsStringAsync();
return !string.IsNullOrWhiteSpace(input) ? Regex.Match(input, #"http://\w*\.directupload\.net/images/\d*/\w*\.[a-z]{3}").Value : null;
}
}
}
}
It works more or less like this (example using an image/jpg file):
async public Task<HttpResponseMessage> UploadImage(string url, byte[] ImageData)
{
var requestContent = new MultipartFormDataContent();
// here you can specify boundary if you need---^
var imageContent = new ByteArrayContent(ImageData);
imageContent.Headers.ContentType =
MediaTypeHeaderValue.Parse("image/jpeg");
requestContent.Add(imageContent, "image", "image.jpg");
return await client.PostAsync(url, requestContent);
}
(You can requestContent.Add() whatever you want, take a look at the HttpContent descendant to see available types to pass in)
When completed, you'll find the response content inside HttpResponseMessage.Content that you can consume with HttpContent.ReadAs*Async.
This is an example of how to post string and file stream with HTTPClient using MultipartFormDataContent. The Content-Disposition and Content-Type need to be specified for each HTTPContent:
Here's my example. Hope it helps:
private static void Upload()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent", "CBS Brightcove API Service");
using (var content = new MultipartFormDataContent())
{
var path = #"C:\B2BAssetRoot\files\596086\596086.1.mp4";
string assetName = Path.GetFileName(path);
var request = new HTTPBrightCoveRequest()
{
Method = "create_video",
Parameters = new Params()
{
CreateMultipleRenditions = "true",
EncodeTo = EncodeTo.Mp4.ToString().ToUpper(),
Token = "x8sLalfXacgn-4CzhTBm7uaCxVAPjvKqTf1oXpwLVYYoCkejZUsYtg..",
Video = new Video()
{
Name = assetName,
ReferenceId = Guid.NewGuid().ToString(),
ShortDescription = assetName
}
}
};
//Content-Disposition: form-data; name="json"
var stringContent = new StringContent(JsonConvert.SerializeObject(request));
stringContent.Headers.Add("Content-Disposition", "form-data; name=\"json\"");
content.Add(stringContent, "json");
FileStream fs = File.OpenRead(path);
var streamContent = new StreamContent(fs);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
//Content-Disposition: form-data; name="file"; filename="C:\B2BAssetRoot\files\596090\596090.1.mp4";
streamContent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + Path.GetFileName(path) + "\"");
content.Add(streamContent, "file", Path.GetFileName(path));
//content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
Task<HttpResponseMessage> message = client.PostAsync("http://api.brightcove.com/services/post", content);
var input = message.Result.Content.ReadAsStringAsync();
Console.WriteLine(input.Result);
Console.Read();
}
}
}
Try this its working for me.
private static async Task<object> Upload(string actionUrl)
{
Image newImage = Image.FromFile(#"Absolute Path of image");
ImageConverter _imageConverter = new ImageConverter();
byte[] paramFileStream= (byte[])_imageConverter.ConvertTo(newImage, typeof(byte[]));
var formContent = new MultipartFormDataContent
{
// Send form text values here
{new StringContent("value1"),"key1"},
{new StringContent("value2"),"key2" },
// Send Image Here
{new StreamContent(new MemoryStream(paramFileStream)),"imagekey","filename.jpg"}
};
var myHttpClient = new HttpClient();
var response = await myHttpClient.PostAsync(actionUrl.ToString(), formContent);
string stringContent = await response.Content.ReadAsStringAsync();
return response;
}
Here is another example on how to use HttpClient to upload a multipart/form-data.
It uploads a file to a REST API and includes the file itself (e.g. a JPG) and additional API parameters. The file is directly uploaded from local disk via FileStream.
See here for the full example including additional API specific logic.
public static async Task UploadFileAsync(string token, string path, string channels)
{
// we need to send a request with multipart/form-data
var multiForm = new MultipartFormDataContent();
// add API method parameters
multiForm.Add(new StringContent(token), "token");
multiForm.Add(new StringContent(channels), "channels");
// add file and directly upload it
FileStream fs = File.OpenRead(path);
multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(path));
// send request to API
var url = "https://slack.com/api/files.upload";
var response = await client.PostAsync(url, multiForm);
}
Here's a complete sample that worked for me. The boundary value in the request is added automatically by .NET.
var url = "http://localhost/api/v1/yourendpointhere";
var filePath = #"C:\path\to\image.jpg";
HttpClient httpClient = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
FileStream fs = File.OpenRead(filePath);
var streamContent = new StreamContent(fs);
var imageContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(imageContent, "image", Path.GetFileName(filePath));
var response = httpClient.PostAsync(url, form).Result;
Example with preloader Dotnet 3.0 Core
ProgressMessageHandler processMessageHander = new ProgressMessageHandler();
processMessageHander.HttpSendProgress += (s, e) =>
{
if (e.ProgressPercentage > 0)
{
ProgressPercentage = e.ProgressPercentage;
TotalBytes = e.TotalBytes;
progressAction?.Invoke(progressFile);
}
};
using (var client = HttpClientFactory.Create(processMessageHander))
{
var uri = new Uri(transfer.BackEndUrl);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
using (MultipartFormDataContent multiForm = new MultipartFormDataContent())
{
multiForm.Add(new StringContent(FileId), "FileId");
multiForm.Add(new StringContent(FileName), "FileName");
string hash = "";
using (MD5 md5Hash = MD5.Create())
{
var sb = new StringBuilder();
foreach (var data in md5Hash.ComputeHash(File.ReadAllBytes(FullName)))
{
sb.Append(data.ToString("x2"));
}
hash = result.ToString();
}
multiForm.Add(new StringContent(hash), "Hash");
using (FileStream fs = File.OpenRead(FullName))
{
multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(FullName));
var response = await client.PostAsync(uri, multiForm);
progressFile.Message = response.ToString();
if (response.IsSuccessStatusCode) {
progressAction?.Invoke(progressFile);
} else {
progressErrorAction?.Invoke(progressFile);
}
response.EnsureSuccessStatusCode();
}
}
}
I'm adding a code snippet which shows on how to post a file to an API which has been exposed over DELETE http verb. This is not a common case to upload a file with DELETE http verb but it is allowed. I've assumed Windows NTLM authentication for authorizing the call.
The problem that one might face is that all the overloads of HttpClient.DeleteAsync method have no parameters for HttpContent the way we get it in PostAsync method
var requestUri = new Uri("http://UrlOfTheApi");
using (var streamToPost = new MemoryStream("C:\temp.txt"))
using (var fileStreamContent = new StreamContent(streamToPost))
using (var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true })
using (var httpClient = new HttpClient(httpClientHandler, true))
using (var requestMessage = new HttpRequestMessage(HttpMethod.Delete, requestUri))
using (var formDataContent = new MultipartFormDataContent())
{
formDataContent.Add(fileStreamContent, "myFile", "temp.txt");
requestMessage.Content = formDataContent;
var response = httpClient.SendAsync(requestMessage).GetAwaiter().GetResult();
if (response.IsSuccessStatusCode)
{
// File upload was successfull
}
else
{
var erroResult = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
throw new Exception("Error on the server : " + erroResult);
}
}
You need below namespaces at the top of your C# file:
using System;
using System.Net;
using System.IO;
using System.Net.Http;
P.S. You are seeing a number of using blocks(IDisposable pattern) in the above code snippet which doesn't look very clean. Unfortunately, the syntax of using construct doesn't support initializing multiple variables in single statement.
X509Certificate clientKey1 = null;
clientKey1 = new X509Certificate(AppSetting["certificatePath"],
AppSetting["pswd"]);
string url = "https://EndPointAddress";
FileStream fs = File.OpenRead(FilePath);
var streamContent = new StreamContent(fs);
var FileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
FileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("ContentType");
var handler = new WebRequestHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(clientKey1);
handler.ServerCertificateValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) =>
{
return true;
};
using (var client = new HttpClient(handler))
{
// Post it
HttpResponseMessage httpResponseMessage = client.PostAsync(url, FileContent).Result;
if (!httpResponseMessage.IsSuccessStatusCode)
{
string ss = httpResponseMessage.StatusCode.ToString();
}
}
public async Task<object> PassImageWithText(IFormFile files)
{
byte[] data;
string result = "";
ByteArrayContent bytes;
MultipartFormDataContent multiForm = new MultipartFormDataContent();
try
{
using (var client = new HttpClient())
{
using (var br = new BinaryReader(files.OpenReadStream()))
{
data = br.ReadBytes((int)files.OpenReadStream().Length);
}
bytes = new ByteArrayContent(data);
multiForm.Add(bytes, "files", files.FileName);
multiForm.Add(new StringContent("value1"), "key1");
multiForm.Add(new StringContent("value2"), "key2");
var res = await client.PostAsync(_MEDIA_ADD_IMG_URL, multiForm);
}
}
catch (Exception e)
{
throw new Exception(e.ToString());
}
return result;
}
So, i made some code in C#, that checks what's inside a file on a certain website.
When it detects a change inside that file, it will execute some command.
Now i'm thinking, is there a way to send some files back to the website?
The website is hosted using Apache2 on a Raspberry Pi.
Here's the code i got:
using System;
using System.Net;
using System.IO;
using System.Threading;
namespace HttpGet
{
class Program
{
static void Main(string[] args)
{
string lastdata = "nice";
int strtp = 0;
string PCName = Environment.MachineName.ToString();
while (true)
{
Console.WriteLine("try..");
var uri = new Uri("http://192.168.1.76/comm.txt");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
using var response = (HttpWebResponse)request.GetResponse();
using var stream = response.GetResponseStream();
using var reader = new StreamReader(stream);
var data = reader.ReadToEnd();
if ((lastdata != data) || (strtp == 0))
{
Console.WriteLine("New data:");
Console.WriteLine(data);
lastdata = data;
string appdata = Environment.ExpandEnvironmentVariables("%appdata%");
string path = appdata + #"\temp\temp.bat";
string pathfold = appdata + #"\temp";
string createText = data; ;
if (!Directory.Exists(pathfold))
{
Directory.CreateDirectory(pathfold);
}
using (StreamWriter writer = new StreamWriter(path))
{
writer.WriteLine(createText);
}
System.Diagnostics.Process.Start(path);
if(strtp == 0)
{
strtp = 1;
lastdata = data;
}
using (WebClient client = new WebClient())
{
client.Headers.Add("Content-Type", "application/octet-stream");
using (Stream fileStream = File.OpenRead(#"C:\Users\JEREDEK\Desktop\2\1.rar"))
using (Stream requestStream = client.OpenWrite(new Uri("http://192.168.1.76/stuff"), "POST"))
{
fileStream.CopyTo(requestStream);
}
}
}
else
{
Console.WriteLine("Nothing new.");
}
Thread.Sleep(3000);
}
}
}
}
I use Visual studio 2019 i it matters.
The code that I have listed here works when I ReadAllText from a local file. What I need to be able to do is replace the path "C:\LocalFiles\myFile.csv" with "https://mySite.blah/myFile.csv".
I have tried several methods, but can't seem to be able to get the csv file loaded into a string variable. If I could just do that, then the code would work for me.
var csv = System.IO.File.ReadAllText(#"C:\LocalFiles\myFile.csv");
StringBuilder sb = new StringBuilder();
using (var p = ChoCSVReader.LoadText(csv).WithFirstLineHeader())
{
p.Configuration.NullValue = null;
if (p.Configuration.CSVRecordFieldConfigurations.IsNullOrEmpty())
{
p.Configuration.NullValue = null;
}
// ChoIgnoreFieldValueMode.DBNull = ChoIgnoreFieldValueMode.Empty();
using (var w = new ChoJSONWriter(sb))
w.Write(p);
}
string fullJson = sb.ToString();
If I simply replace the path, I get an error message that says that the path is invalid.
You need to get the string using a web request:
string urlAddress = "https://mySite.blah/myFile.csv";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlAddress);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream receiveStream = response.GetResponseStream();
StreamReader readStream = null;
if (response.CharacterSet == null)
{
readStream = new StreamReader(receiveStream);
}
else
{
readStream = new StreamReader(receiveStream,
Encoding.GetEncoding(response.CharacterSet));
}
string data = readStream.ReadToEnd();
response.Close();
readStream.Close();
}
or using a Webclient:
WebClient wc = new WebClient();
string data = wc.DownloadString("https://mySite.blah/myFile.csv");
Then pass data into your reader instead of using the System.IO.File.ReadAllText(#"C:\LocalFiles\myFile.csv");
Both of the above examples assume that the file is publicly accessible at that url without authentication or specific header values.
Replace this line
var csv = System.IO.File.ReadAllText(#"C:\LocalFiles\myFile.csv");
with
string result = client.GetStringAsync("https://mySite.blah/myFile.csv").Result;
or
var textFromFile = (new WebClient()).DownloadString("https://mySite.blah/myFile.csv");
There are many other ways to do it as well. Just google it.
I have backend endpoint Task<ActionResult> Post(IFormFile csvFile) and I need to call this endpoint from HttpClient. Currently I am getting Unsupported media type error.
Here is my code:
var filePath = Path.Combine("IntegrationTests", "file.csv");
var gg = File.ReadAllBytes(filePath);
var byteArrayContent = new ByteArrayContent(gg);
var postResponse = await _client.PostAsync("offers", new MultipartFormDataContent
{
{byteArrayContent }
});
You need to specify parameter name in MultipartFormDataContent collection matching action parameter name (csvFile) and a random file name
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(byteArrayContent, "csvFile", "filename");
var postResponse = await _client.PostAsync("offers", multipartContent);
or equivalent
var postResponse = await _client.PostAsync("offers", new MultipartFormDataContent {
{ byteArrayContent, "csvFile", "filename" }
});
Use this snippet:
const string url = "https://localhost:5001/api/Upload";
const string filePath = #"C:\Path\To\File.png";
using (var httpClient = new HttpClient())
{
using (var form = new MultipartFormDataContent())
{
using (var fs = File.OpenRead(filePath))
{
using (var streamContent = new StreamContent(fs))
{
using (var fileContent = new ByteArrayContent(await streamContent.ReadAsByteArrayAsync()))
{
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
// "file" parameter name should be the same as the server side input parameter name
form.Add(fileContent, "file", Path.GetFileName(filePath));
HttpResponseMessage response = await httpClient.PostAsync(url, form);
}
}
}
}
}
This worked for me as a generic
public static Task<HttpResponseMessage> PostFormDataAsync<T>(this HttpClient httpClient, string url, string token, T data)
{
var content = new MultipartFormDataContent();
foreach (var prop in data.GetType().GetProperties())
{
var value = prop.GetValue(data);
if (value is FormFile)
{
var file = value as FormFile;
content.Add(new StreamContent(file.OpenReadStream()), prop.Name, file.FileName);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = prop.Name, FileName = file.FileName };
}
else
{
content.Add(new StringContent(JsonConvert.SerializeObject(value)), prop.Name);
}
}
if (!string.IsNullOrWhiteSpace(token))
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
return httpClient.PostAsync(url, content);
}
Solved by using this code:
const string fileName = "csvFile.csv";
var filePath = Path.Combine("IntegrationTests", fileName);
var bytes = File.ReadAllBytes(filePath);
var form = new MultipartFormDataContent();
var content = new StreamContent(new MemoryStream(bytes));
form.Add(content, "csvFile");
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "csvFile",
FileName = fileName
};
content.Headers.Remove("Content-Type");
content.Headers.Add("Content-Type", "application/octet-stream; boundary=----WebKitFormBoundaryMRxYYlVt8KWT8TU3");
form.Add(content);
//Act
var postResponse = await _sellerClient.PostAsync("items/upload", form);
Post the attachment as an MultipartFormDataContent
var type = typeof(Startup);
var stream = type.Assembly.GetManifestResourceStream(type, "Resources.New.docx");
var fileContent = new StreamContent(stream);
var data = new MultipartFormDataContent
{
{ fileContent, "file", "New.docx" }
};
var response = await _client.PostAsync("upload", multipartContent);
Source: https://medium.com/#woeterman_94/c-webapi-upload-files-to-a-controller-e5ccf288b0ca
Please see the following working code with .NET 5.0 Environment.
You send the file as a byte[] and receive it as a IFormFile in the API.
//api controller receiver
[HttpPost("SendBackupFiles")]
public IActionResult SendBackupFiles(IFormFile file)
{
var filePath = Path.GetTempFileName();
using (var stream = System.IO.File.Create(filePath))
file.CopyToAsync(stream);
}
//client code sender example, not optimized lol.
const string filePath = #"C:\temp\hallo.csv";
using (var httpClient = new HttpClient())
{
var form = new MultipartFormDataContent();
byte[] fileData = File.ReadAllBytes(filePath);
ByteArrayContent byteContent = new ByteArrayContent(fileData);
byteContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(byteContent, "file", Path.GetFileName(filePath));
var result = httpClient.PostAsync("http://localhost:5070/..yourControllerName.../SendBackupFiles", form).ConfigureAwait(false).GetAwaiter().GetResult().Content.ReadAsStringAsync().Result;
}
I am trying to upload the file to web API so I have the following code
public async Task<Token> upload(string fullMd5, IEnumerable<HttpPostedFileBase> files)
{
string uploadUrl = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// Call CMS API
string jsonContent = string.Empty;
HttpClientHandler handler = new HttpClientHandler();
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
var filesData = new MultipartFormDataContent();
foreach (var item in files)
{
HttpContent filecontent = new StreamContent(item.InputStream);
filecontent.Headers.ContentType = new MediaTypeHeaderValue(item.ContentType);
filecontent.Headers.ContentLength += item.InputStream.Length;
filecontent.Headers.ContentDisposition = new ContentDispositionHeaderValue("multipart/form-data")
{
Name = "file",
FileName = item.FileName,
};
content.Add(filecontent);
}
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + userObj.access_token);
client.DefaultRequestHeaders.Add("Api-version", "2.4");
client.DefaultRequestHeaders.Add("CMSId", UserId);
var response = await client.PostAsync(uploadUrl, content);
jsonContent = await response.Content.ReadAsStringAsync();
}
}
var result = JsonConvert.DeserializeObject<Token>(jsonContent);
return result;
}
}
the API receive the files but corrupted with zero size , the API works well as I tested using postman , I tried to save the files before sending using SaveAs and it worked well any problem in how I send the file
Try using postAsync like this with these headers
using (var client = new HttpClient(handler) {BaseAddress = new Uri(_host)})
{
var requestContent = new MultipartFormDataContent();
var fileContent = new StreamContent(fileInfo.OpenRead());
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
Name = "\"file\"",
FileName = "\"" + fileInfo.Name + "\""
};
fileContent.Headers.ContentType =
MediaTypeHeaderValue.Parse(MimeMapping.GetMimeMapping(fileInfo.Name));
var folderContent = new StringContent(folderId.ToString(CultureInfo.InvariantCulture));
requestContent.Add(fileContent);
requestContent.Add(folderContent, "\"folderId\"");
var result = client.PostAsync("Company/AddFile", requestContent).Result;
}