Multipart Data Upload - Azure Function V2 - c#

Am uploading a document to HTTP Trigger Azure function(Version 2). On receiving the request in my function I see the Files section empty and stream is moved to formdata dictionary. Below is the code how am uploading the document, could someone help me why its not populating the stream in IFormFileCollection.
using (var _httpClient = new HttpClient())
{
MultipartFormDataContent form = new MultipartFormDataContent();
String headerValue = "form-data; name=\"file\"; filename=\"" + fileName + "\"";
byte[] bytes = Encoding.UTF8.GetBytes(headerValue);
headerValue = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
fileContent.Headers.Add("Content-Disposition", headerValue);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(fileContent);
form.Add(new StringContent(metadataValue), metadataKey);
_httpClient.Timeout = TimeSpan.FromMinutes(15);
_httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + bearerToken);
logger.LogInformation($"HttpUtils: UploadFileByMultipart() url:{url}, request param: {metadataValue} reference: {traceLogId}");
var response = await _httpClient.PostAsync(url, form).Result.Content.ReadAsStringAsync();
logger.LogInformation("HttpUtils: UploadFileByMultipart() end");
return response;
}
Content received in Function
Other note how do take the stream from the Formdata dictionary which is in string format and convert to stream which I can play around. I tried below and the resultant is a blank doc, corrupting all the stream
requestHandler.stream = new MemoryStream();
var Content = formdata["file"].ToString();
var fileContent = new MemoryStream(Encoding.ASCII.GetBytes(Content));

If we want to send Multipart Data with HttpClient, you can use MultipartFormDataContent to create data.
For example
The code I send request
MultipartFormDataContent form = new MultipartFormDataContent();
form.Add(new StringContent("jack"), "userName");
var fileContent = new ByteArrayContent(File.ReadAllBytes(#"D:\my.csv"));
// I use package MimeMapping : https://www.nuget.org/packages/MimeMapping/ to get file mine type
fileContent.Headers.ContentType = new MediaTypeHeaderValue(MimeUtility.GetMimeMapping("my.csv"));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "file",
FileName = "my.csv"
};
form.Add(fileContent);
using (var client = new HttpClient())
{
var res = await client.PostAsync("<function app url>", form);
if (res.IsSuccessStatusCode)
{
var content = await res.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
}
My function app code
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
log.LogInformation("-------------------read file----------------------");
// read file
var files = req.Form.Files;
if (files.Count != 0) {
var file = files[0];
log.LogInformation(file.ContentType);
log.LogInformation(file.FileName);
log.LogInformation(file.ContentDisposition);
// use file.OpenReadStream to get a stream then use stream to rread file content
}
// read key
log.LogInformation("-------------------read key----------------------");
log.LogInformation($"The userName is {req.Form["userName"]}");
return new OkObjectResult("OK");
}

Related

How to implement WebClient.UploadFileAsync with HttpClient? [duplicate]

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;
}

Unable to pass file to web api in ASP.NET MVC Core

I am working on an angular and .NET Core application. I have to pass the file uploaded from angular to WEB API. My code is:
public async Task ImportDataScienceAnalytics(string authToken, IFormFile file)
{
var baseUrl = Import.GetBaseURL();
var client = new RestClientExtended(baseUrl + "algorithm/import");
var request = new RestRequest(Method.POST);
request.AddHeader("authorization", authToken);
string jsonBody = JsonConvert.SerializeObject(file);
request.AddJsonBody(jsonBody);
var response = await client.ExecutePostTaskAsync(request);
var result = response.Content;
}
Issue is that i get "No Attachment Found". I think the issue is because of IFormFile. How can i resolve this issue so that i can upload the file to web api.
It seems that you'd like to post uploaded file to an external API from your API action using RestClient, you can refer to the following code snippet.
var client = new RestClient(baseUrl + "algorithm/import");
var request = new RestRequest(Method.POST);
request.AddHeader("authorization", authToken);
using (var ms = new MemoryStream())
{
file.CopyTo(ms);
var fileBytes = ms.ToArray();
request.AddFile("file", fileBytes, file.FileName, "application/octet-stream");
}
//...
Testing code of Import action
public IActionResult Import(IFormFile file)
{
//...
//code logic here
You need to make following changes to the code.
var baseUrl = Import.GetBaseURL();
var client = new RestClientExtended(baseUrl + "algorithm/import");
var request = new RestRequest(Method.POST);
byte[] data;
using (var br = new BinaryReader(file.OpenReadStream()))
data = br.ReadBytes((int)file.OpenReadStream().Length);
ByteArrayContent bytes = new ByteArrayContent(data);
MultipartFormDataContent multiContent = new MultipartFormDataContent
{
{ bytes, "file", file.FileName }
};
//request.AddHeader("authorization", authToken);
//string jsonBody = JsonConvert.SerializeObject(file);
//request.AddJsonBody(jsonBody);
/// Pass the multiContent into below post
var response = await client.ExecutePostTaskAsync(request);
var result = response.Content;
Do not forget to pass the variable multiContent into the post call.

How to Solve Azure DataLakeStore File Content-Disposition Added in file?

I was Uploaded Text file or image file or Zip File to Azure Data Lake Store. it' was Uploaded Successfully. But, before added some content in file.
I was Uploaded a File using Rest API. (Uploaded file using HttpClient in C#)
this Type of Content Added in
---b8b2dfc6-6128-43b5-8fb8-022820aedf02
Content-Disposition: form-data;
name=file1; filename=tick.txt; filename*=utf-8''tick.txt
If the Content Added So, The Image file and zip files are Not Open in Viewer/Explore.
How To Remove this type of header added in file From Upload.Here I shared my file uploaded code.
public object UploadFile(string srcfile, string destFilePath, bool force = true)
{
var uploadurl = string.Format(UploadUrl, _datalakeAccountName, destFilePath);
var stream = File.OpenRead(srcfile);
HttpContent fileStreamContent = new StreamContent(stream);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accesstoken.access_token);
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent, "file1", Path.GetFileName(srcfile));
var response = client.PutAsync(uploadurl, formData).Result;
return new { Status = response.StatusCode, Message = response.ReasonPhrase, details = response.ToString() };
}
}
}
Thanks in Advance.
Please have try to use the following code, it works correcly on my side.
public object UploadFile(string srcfile, string destFilePath, bool force = true)
{
var uploadurl = string.Format(UploadUrl, _datalakeAccountName, destFilePath);
var stream = File.OpenRead(srcfile);
HttpContent fileStreamContent = new StreamContent(stream);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new
AuthenticationHeaderValue("Bearer", _accesstoken.access_token);
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
var response = client.PutAsync(uploadurl, fileStreamContent).Result;
return new { Status = response.StatusCode, Message = response.ReasonPhrase, details = response.ToString() };
}
}

Gfycat API file upload

I am struggling to use the Gfytcat API to upload an mp4 from my machine. Maybe it's just me but the API docs don't seem very well fleshed out.
The following code successfully requests a new gfy, but fails the upload with the following error: 204: No Content.
using (var client = new HttpClient())
{
var response = await client.PostAsync(#"https://api.gfycat.com/v1/gfycats", null);
var responseString = await response.Content.ReadAsStringAsync();
var newGfycatResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<NewGfycatResponse>(responseString);
Console.WriteLine("gfyname: " + newGfycatResponse.gfyname);
Console.WriteLine("secret: " + newGfycatResponse.secret);
var filePath = #"C:\Users\Julien\Videos\black cat jumping.mp4";
var file = File.ReadAllBytes(filePath);
using (var content = new MultipartFormDataContent())
{
content.Add(new StringContent(newGfycatResponse.gfyname), "key");
content.Add(new ByteArrayContent(file), "file", newGfycatResponse.gfyname);
using (var message = await client.PostAsync("https://filedrop.gfycat.com", content))
{
var input = await message.Content.ReadAsStringAsync();
Console.WriteLine(input);
}
}
}
Looks like the below line is incorrect. You have to name the field "file", you are naming it as the name of the file.
content.Add(new StreamContent(new MemoryStream(file)), "file", newGfycatResponse.gfyname);
**** edits
You may want to modify the headers on that file content as below.
below is taken from: ASP.NET WebApi: how to perform a multipart post with file upload using WebApi HttpClient
var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(fileName));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Foo.txt"
};
content.Add(fileContent);

Send file to service using Microsoft.Net.Http

I have a method:
private bool UploadFile(Stream fileStream, string fileName)
{
HttpContent fileStreamContent = new StreamContent(fileStream);
using (var client = new HttpClient())
{
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent, fileName, fileName);
var response = client.PostAsync("url", formData).Result;
return response.StatusCode == HttpStatusCode.OK;
}
}
}
}
That is sending the file to a WCF service, but looking at the Wireshark log of the post, the fileStream isn't being appended, just the filename. Do I need to do something else?
Use a ByteArrayContent instead of a stream content.
var fileContent = new ByteArrayContent(File.ReadAllBytes(fileName));
Then specify your content disposition header:
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
formData.Add(fileContent);
Turns out the fileStream wasn't getting to the method. Using context.Request.Files[0].InputStream seemed to be the culprite. Using .SaveAs and then reading it in as a byteArray and attaching that to the MultiPartFormDataContent worked.

Categories

Resources