Issue
I am working on a web application that allows users to store and retrieve files using Azure Storage. Currently, I am facing a problem when trying to retrieve the files from Azure Storage. I have implemented the Azure Blob Storage SDK to handle interactions with Azure Storage.
Frontend:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const Filelist = () => {
const [files, setFiles] = useState([]);
useEffect(() => {
const fetchFiles = async () => {
try {
const response = await axios.get('http://localhost:3000/api/filelist');
setFiles(response.data);
} catch (error) {
console.error('Error fetching files:', error);
}
};
fetchFiles();
}, []);
async function downloadFile(filename) {
try {
const response = await axios.post('http://localhost:3000/api/display-file', {
filename,
});
} catch (error) {
console.error('Error downloading file:', error);
}
}
return (
<div>
<h2>Files:</h2>
<ul>
{files.map((file) => (
<li key={file._id}>
<a href={file.fileURL} target="_blank" rel="noopener noreferrer">
{file.filename}
</a>
<button onClick={() => downloadFile(file.filename)}>Download</button>
</li>
))}
</ul>
</div>
);
};
export default Filelist;
Backend:
exports.displayFile = async (req, res) => {
try {
const storageAccount = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const containerName = process.env.AZURE_CONTAINER_NAME;
const accessKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;
const connectionString = process.env.AZURE_CONNECTION_STRING;
const blobService = azure.createBlobService(connectionString);
const blobName = req.filename;
var downloadedFileName = util.format('%s/CopyOf%s', blobName);
blobService.getBlobToLocalFile(containerName, blobName, downloadedFileName, function (error, serverBlob) {
if (error) {
console.error('Error downloading blob:', error);
}
});
} catch (error) {
console.log(error);
res.send(401);
}
};
exports.fileList = async (req, res) => {
try {
const files = await File.find();
return res.status(200).json(files);
} catch (error) {
console.error('Error fetching files:', error);
return res.status(500).json({ error: 'Internal server error!' });
}
}
I am using the azure-storage library to interact with Azure Blob Storage and download the files. However, when I attempt to retrieve the PDF files using the getBlobToLocalFile method, I encounter the "ArgumentNullError: Required argument blob for function getBlobToLocalFile is not defined" error.
Solution
I made some changes to your code and can able to upload and download files in the storage account container from Azure Portal.
Code:
frontend/src/components/FileList.js:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const FileList = () => {
const [files, setFiles] = useState([]);
useEffect(() => {
const fetchFiles = async () => {
try {
const response = await axios.get('http://localhost:3000/api/filelist');
setFiles(response.data);
} catch (error) {
console.error('Error fetching files:', error);
}
};
fetchFiles();
}, []);
async function downloadFile(filename) {
try {
const response = await axios.post(
'http://localhost:3000/api/display-file',
{ filename },
{ responseType: 'blob' }
);
const blob = new Blob([response.data]);
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
console.log('File downloaded:', filename);
} catch (error) {
console.error('Error downloading file:', error);
}
}
return (
<div>
<h2>Files:</h2>
<ul>
{files.map((file) => (
<li key={file._id}>
<a href={file.fileURL} target="_blank" rel="noopener noreferrer">
{file.filename}
</a>
<button onClick={() => downloadFile(file.filename)}>Download</button>
</li>
))}
</ul>
</div>
);
};
export default FileList;
backend/controllers/fileController.js:
const azure = require('azure-storage');
const fs = require('fs');
const path = require('path');
const storageAccount = "<storage_name>";
const containerName = "<container_name>";
const accessKey = "<storage_key>";
const connectionString = "<connec_string>";
const blobService = azure.createBlobService(connectionString);
exports.displayFile = async (req, res) => {
try {
const blobName = req.body.filename;
res.setHeader('Content-Disposition', `attachment; filename=${blobName}`);
res.setHeader('Content-Type', 'application/pdf');
blobService.getBlobToStream(containerName, blobName, res, function (error) {
if (error) {
console.error('Error downloading blob:', error);
return res.status(500).json({ error: 'Error downloading blob!' });
}
});
} catch (error) {
console.log(error);
return res.status(401).json({ error: 'Unauthorized' });
}
};
exports.fileList = async (req, res) => {
try {
const files = [
{ _id: 1, filename: '<file1_name>.pdf', fileURL: 'https://<storage_name>.blob.core.windows.net/<container_name>/<file1_name>.pdf' },
{ _id: 2, filename: '<file2_name>.pdf', fileURL: 'https://<storage_name>.blob.core.windows.net/<container_name>/<file2_name>.pdf' },
];
return res.status(200).json(files);
} catch (error) {
console.error('Error fetching files:', error);
return res.status(500).json({ error: 'Internal server error!' });
}
};
backend/app.js:
const express = require('express');
const cors = require('cors');
const multer = require('multer');
const apiRouter = require('./routes/api');
const azure = require('azure-storage');
const path = require('path');
require('dotenv').config();
const app = express();
app.use(express.json());
app.use(cors());
const storageAccount = "<storage_name>";
const containerName = "<container_name>";
const accessKey = "<storage_key>";
const connectionString = "<connec_string>";
const blobService = azure.createBlobService(connectionString);
const storage = multer.memoryStorage();
const upload = multer({ storage });
app.use('/api', apiRouter);
app.post('/api/upload-file', upload.single('file'), (req, res) => {
const file = req.file;
if (!file) {
return res.status(400).json({ error: 'No file uploaded' });
}
const blobName = file.originalname;
const container = containerName;
blobService.createBlockBlobFromText(container, blobName, file.buffer, (error, result, response) => {
if (error) {
console.error('Error uploading blob:', error);
return res.status(500).json({ error: 'Error uploading blob to Azure' });
}
console.log('File uploaded to Azure:', blobName);
res.sendStatus(200);
});
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
Output:
Firstly, we should run the backend code and it runs successfully as below,
Then, I run the frontend code and it also runs successfully as below,
And it opens in the browser like below. I click on Choose File to choose a file that I want to upload and then click on Upload,
I uploaded another file like the same as below,
Above two files were uploaded successfully to the storage account container as a blob-like below in the VS code terminal,
The two files uploaded successfully to the storage account container as a blob at the Azure Portal like below,
Then, I click on the Download button in Files, and those files downloaded successfuly as below,
Answered By – Dasari Kamali
This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0