Upload a pdf file to azure blob using azure function - c#

I am trying to upload a PDF file from postman and trigger the azure function to upload the PDF file into azure blob storage. But when i try to open the PDF file it is always empty.
I tried to convert the file into memory stream and upload it into azure blob. The file gets uploaded but when i try to open the file it will be blank.
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info(req.Content.ToString());
string Message = "";
log.Info("Test storage conn string" + req.Content.Headers.ContentDisposition.ToString());
string contentType = req.Content.Headers?.ContentType?.MediaType;
log.Info("contentType : " + req.Content.IsMimeMultipartContent());
string name = Guid.NewGuid().ToString("n");
log.Info("Name" + name);
string body;
body = await req.Content.ReadAsStringAsync();
log.Info("body" + body.Substring(body.IndexOf("filename=\""),body.IndexOf("pdf")- body.IndexOf("filename=\"")));
//Upload a file to Azure blob
string storageConnectionString = "xxxx";
//DirectoryInfo directoryInfo = new DirectoryInfo("D:\\Upload_Files");
// var files = directoryInfo.EnumerateFiles();
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageConnectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("docstorage");
//foreach (FileInfo inputFile in files)
//{
CloudBlockBlob blockBlob = container.GetBlockBlobReference("Test\\" + name+".pdf");//write name here
//blockBlob.Properties.ContentType = "application/pdf";
//blockBlob.UploadFromFile(inputFile.FullName);
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(body)))
{
log.Info("streaming : ");
await blockBlob.UploadFromStreamAsync(stream);
}
//}
return Message == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Error")
: req.CreateResponse(HttpStatusCode.OK, "Doc Uploaded Successfully");
}
I want to open the PDF file as it is from the blob. I see that i am able to upload text file and when i download i can see the content but when i upload pdf file i dont see the content

Calling .ReadAsStringAsync on a binary document wont work - you have to call ReadAsByteArrayAsync or ReadAsStreamAsync.
var body = await req.Content.ReadAsByteArrayAsync();
...
using (Stream stream = new MemoryStream(body))
{
await blockBlob.UploadFromStreamAsync(stream);
}
OR
var body2 = await req.Content.ReadAsStreamAsync();
body.Position = 0;
...
await blockBlob.UploadFromStreamAsync(body);

It's really simple to do something like that. Everything relative to bindings should be declared in the function parameters so, having this in mind, you have to declare your blob stream as a parameter. Check this as an example:
public static async Task<string> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
[Blob("azurefunctions/test.pdf", FileAccess.Write)] Stream blob,
ILogger log)
Please, note the second parameter called blob is declared as a Stream to be able to save the content read from the input. The second point is the attribute decorating the parameter, Blob allows to define several aspects of the new blob file that will be uploaded in our Azure Storage service. As you can see, the container is called azurefunctions and the file will be called test.pdf.
In order to save the content you can use the following code:
byte[] content = new byte[req.Body.Length];
await req.Body.ReadAsync(content, 0, (int)req.Body.Length);
await blob.WriteAsync(content, 0, content.Length);
Hope this can be helpful for your question.
These are useful links to check and test your code:
Azure Blob storage bindings for Azure Functions
How to send multipart/form-data with PowerShell Invoke-RestMethod

Related

send file using HttpClient in PostAsync using function app in req.Form.Files c#

I have created Function App for uploading multiple files on FTP server. I have received all files using req.Form.Files. but When I get the request. I actually found my file from HttpClient request in req.Body. When I upload file from Postman in Body->FormData it, works fine but now I need to send post request with file by code.
I had tried below code with reference of Sending a Post using HttpClient and the Server is seeing an empty Json file this link.
HttpContent content = new StreamContent (stream);
content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
HttpResponseMessage response = client.PostAsync ("url", content).Result;
But I want file in req.Form.Files . Where user might have uploaded multiple files or one file.
Note : For now I have a file which is being generated by code. But it should not be saved on local so I'm trying to send stream. in HttpContent
Below are the steps for Post Async using function app
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
{
string Connection = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
string containerName = Environment.GetEnvironmentVariable("ContainerName");
var file = req.Form.Files["File"];**
var filecontent = file.OpenReadStream();
var blobClient = new BlobContainerClient(Connection, containerName);
var blob = blobClient.GetBlobClient(file.FileName);
byte[] byteArray = Encoding.UTF8.GetBytes(filecontent.ToString());
File details while using req.Form.Files
Successfully uploaded a text file to blob storage.
Edit:
Here is the Post request Using HttpClient
var file = #"C:\Users\...\Documents\test.txt";
await using var stream = System.IO.File.OpenRead(file);
using var request = new HttpRequestMessage(HttpMethod.Post, "file");
using var content = new MultipartFormDataContent
{
{ new StreamContent(stream),"File", "test.txt" }
};
request.Content = content;
await client.SendAsync(request);
return new OkObjectResult("File uploaded successfully");

How to upload file to Azure DataLake through API?

Net core application. I am trying to upload file to data lake through API. I have below controller method which accepts file.
[HttpPost]
public async Task<IActionResult> Upload(IFormFile files)
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "Uploads", files.FileName);
var stream = new FileStream(path, FileMode.Create);
string containerName = "raw";
DataLakeServiceClient dataLakeServiceClient = _dataLakeRepository.GetDataLakeServiceClient("test");
DataLakeFileSystemClient dataLakeFileSystemClient = _dataLakeRepository.GetFileSystem(dataLakeServiceClient, containerName);
await _dataLakeRepository.UploadFile(dataLakeFileSystemClient, "directory2", "text1.txt", stream);
return Ok();
}
I have below DataLake method which will upload file to data lake.
public async Task UploadFile(DataLakeFileSystemClient fileSystemClient, string directoryName, string fileName, Stream content)
{
DataLakeDirectoryClient directoryClient = fileSystemClient.GetDirectoryClient(directoryName);
DataLakeFileClient fileClient = await directoryClient.CreateFileAsync(fileName);
long fileSize = content.Length;
await fileClient.AppendAsync(content, offset: 0);
await fileClient.FlushAsync(position: fileSize);
}
Below method to get file system client
public DataLakeFileSystemClient GetFileSystem(DataLakeServiceClient serviceClient, string FileSystemName)
{
return serviceClient.GetFileSystemClient(FileSystemName);
}
I tried to upload file and In below line
await fileClient.AppendAsync(content, offset: 0);
I got below error
Azure.RequestFailedException: The value for one of the HTTP headers is not in the correct format.
Status: 400 (The value for one of the HTTP headers is not in the correct format.)
ErrorCode: InvalidHeaderValue
Also when I debug I see content.Length is also zero. I think I am missing something in stream because I am having some issue with stream. I am not able to figure out the issue. Can someone help me to fix this. Any help would be appreciated. Thanks
After read official doc, we can find the sample code use FileStream.
So you should convert Stream to FileStream .

Converting IFormFile to Stream set content type to application/octet-stream

I want to upload image files to a Azure Blob Container. I am using .net core webapi post method to upload the image.The upload getting success but the content type is invalid, which convert the original image/jpeg type to application/octet-stream.
[HttpPost]
public async Task<string> Post(IFormFile files)
{
BlobClient blobClient = _containerClient.GetBlobClient(files.FileName);
await blobClient.UploadAsync(files.OpenReadStream());
}
Can anyone help me how to upload the image keeping the original content type.
Thanks in advance.
If you want to set content-type when you upload file to Azure blob, please refer to the following code
// I use the sdk Azure.Storage.Blobs
[HttpPost]
public async Task<string> Post(IFormFile file)
{
var connectionString = "the account connection string";
BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
BlobContainerClient containerClient =blobServiceClient.GetBlobContainerClient("test");
await containerClient.CreateIfNotExistsAsync();
BlobClient blobClient = containerClient.GetBlobClient(file.FileName);
BlobHttpHeaders httpHeaders = new BlobHttpHeaders() {
ContentType=file.ContentType
};
await blobClient.UploadAsync(file.OpenReadStream(), httpHeaders);
return "OK";
}
Test(I test in Postman)

CanĀ“t upload file to Azure Blob Storage from my form

I need to upload a file from a form on the front-end, passing through the backend into the azure blob storage.
I need save on the blob, and get the url saved on azure blob storage.
I am receiving the file from the form on controller using a class to parse the data.
The controller deals with the file and connect on the azure blob storage.
The blob storage doesn't have example on his methods on documentation.
All examples that I found just show how to upload from a local folder.
Following the code, the problem so far is the format of the myFile var is being passed on the method UploadFromStreamAsync.
// the controller starts here
[HttpPost]
public async System.Threading.Tasks.Task<ActionResult> Index(IFormFile arquivo)
{ //here I am receving the file
var myFile = arquivo.FileItem;
var myFileName = arquivo.FileName;
// here is the connection with blob account
string storageConnection = ConfigurationManager.AppSettings["BlobStorageString"];
string accountBlob = ConfigurationManager.AppSettings["BlobStorageAccount"];
var storageAccount = CloudStorageAccount.Parse(storageConnection);
var cloudBlobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("hurrblobstest");
await cloudBlobContainer.CreateAsync();
var cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference("filname12");
// here I am trying to send the file
await cloudBlockBlob.UploadFromStreamAsync(myFile);
var result = JsonConvert.SerializeObject(cloudBlockBlob);
//here I need to return the url or the object with the file info on the azure blob storage
return Json(result);
}
I am getting a message on the: await cloudBlockBlob.UploadFromStreamAsync(myFile); that tells me that the file
HttpPostedFileBase cannot be converted into System.IO.Stream
Well, I say if something wants a stream, give it a stream:
using (Stream stream = myFile.OpenReadStream())
{
await cloudBlockBlob.UploadFromStreamAsync(stream);
}

Azure Blob Storage - Uploading Http/StreamContent to a CloudBlockBlob from WebApi Controller

I am sending a PDF file to my WebAPI Controller via a POST request using Angular as such:
$scope.upload = Upload.upload({
url: "../api/Locker/Upload", // webapi url
method: "POST",
file: controllerFile,
})
which in my POST method on my controller I get the StreamContent of that file as follows:
public async Task<HttpResponseMessage> Post()
{
HttpRequestMessage request = this.Request;
if (!request.Content.IsMimeMultipartContent())
{
request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
var result = await Request.Content.ReadAsMultipartAsync<CustomMultipartFormDataProvider>(new CustomMultipartFormDataProvider());
string fileName = result.FileData[0].Headers.ContentDisposition.FileName;
var fileData = result.Contents[0];
}
It is saying that results.Contents[0] is of type HttpContent but in the Immediate window when I type fileData it says it is of StreamContent type.
I am trying to upload to Azure Blob Storage this fileData so that I can then retrieve it using a GET request later on, but am having trouble doing so.
//in post method
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(blobConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(blobContainer);
await container.CreateIfNotExistsAsync();
string blobId = Guid.NewGuid().ToString();
UploadToBlob(container, blobId, fileData);
and method where I am stuck:
private async void UploadToBlob(CloudBlobContainer container, string blobId, HttpContent fileData)
{
CloudBlockBlob block = container.GetBlockBlobReference(blobId);
block.UploadFromStream(fileData);
}
error on block.UploadFromStream because fileData is not a Stream of course.
What can I do if I am expecting a HTTP Response with content being of type: arraybuffer so that I can expose the file in my web application such as:
//angular get request
.success(function (data, status, headers, config) {
// file is uploaded successfully
console.log(data);
var fileBack = new Blob([(data)], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(fileBack);
}
What about block.UploadFromStream(await fileData.ReadAsStreamAsync())?

Categories