Uploading images to a server with blob - asp.net

I have both asp.net API and vue.js Front. I want to upload images to my blob azure storage. Is it better to do it on API side? I mean send image to API and from API to blob Azure or directly from vue.js to blob azure?

Ideally we should try to send the image as POST to the API in ASP.NET and then call the API for uploading the image.
Instead of taking the image directly and uploading, we must check if the file is not corrupted (or any other issue) and then upload it.
In .NET, try out the below code:
string loc = Directory.GetCurrentDirectory() + "/" + location;
CloudStorageAccount account = CloudStorageAccount.Parse(*connection_string*);
CloudBlobClient client = account.CreateCloudBlobClient();
CloudBlobContainer container = client.GetContainerReference(*container_name*);
container.CreateIfNotExists();
CloudBlockBlob blob = container.GetBlockBlobReference(*blobName*);
blob.UploadFromFile(loc);

Related

ASP .net 6 download file by httpclient - problem with stream

I'm creating blazor server app. I use external file storage with RestAPI.
I want to create download button to get file from storage. This may seem easy, but not necessarily.
From file storage I download HttpContent like that
var request = new HttpRequestMessage(HttpMethod.Get, _url);
request.Headers.Add("auth-token", token);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
HttpResponseMessage response = await _Http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
var content = response.Content;
next I act like this tutorial https://learn.microsoft.com/en-us/aspnet/core/blazor/file-downloads?view=aspnetcore-6.0
var fileStream = content.ReadAsStream();
using (var streamRef = new DotNetStreamReference(fileStream))
{
await JS.InvokeVoidAsync("downloadFileFromStream", "file.txt", streamRef);
}
For small files everything work great. But if I try to download large file (100mb), algoritm firstable download file to memory(RAM) of server and later save on local disk of client.
In ideal world I dream that when I click button download, file from external storage will download after delay (with progressbar) like physical file (no stream buffer) form http server e.g. https://www.example.com/file.txt. Of course by my BlazorServer Application with authorization and authentication, and whole neccesery services.
I have solution.
Create Service to service File Storage API
Create controller to avoid cros-origin error
Use microsoft tutorial to create download button https://learn.microsoft.com/en-us/aspnet/core/blazor/file-downloads?view=aspnetcore-6.0

Download images to users local machines via Firebase Functions

Is it possible to download images to users local machines directly via Firebase functions? How to do it in case that:
Images are stored in Firebase storage.
Images are stored on other cloud storage providers (I can access them with url).
I don't want to download those images via url links so that I don't reveal the url the image is located on.
Is it possible to download images to users local machines directly via Firebase functions?
No, it's not possible. The client must reach out to the server in order to download content. The content can't be "pushed" to the client without its authorization. That would be a huge security hole for the client.
This is why download URLs exist - to give the client something to download via a normal HTTP request.
You can create a presigned URL using the Google APIs library. The Firebase bucket is just a regular GCS bucket. Something like this:
const admin = getFirebaseAdmin();
let bucket = admin.storage().bucket(firebaseConfig.storageBucket);
const f = bucket.file(location);
if (!(await f.exists())) {
throw logError(`No file found at specified location: ${location}`, functionName)
}
const url1 = await f.getSignedUrl({
action: 'read',
expires: new Date((new Date).getTime() + (24 * 60) * 60000) // expires in 24 hours
});
const url = url1[0];
return url;

How to get the download url after uploading a file to firebase storage in springboot

I am trying to upload images to firebase storage and to save the download URL in my database. However, I cannot find a way to get the download Url in springboot unlike when an upload is performed in android. Saving the media URL does not work as it doesn't have the access token. Below is the code I've used to upload the image to firebase.
File file = convertMultiPartToFile(multipartFile);
Path filePath = file.toPath();
String objectName = generateFileName(multipartFile);
BlobId blobId = BlobId.of(bucketName, objectName);
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
Blob blob = storage.create(blobInfo, Files.readAllBytes(filePath));
log.info("File " + filePath + " uploaded to bucket " + bucketName + " as " + objectName);
return blob.getMediaLink();
I had the same problem this week when I was developing an endpoint responsible for uploading a file to Firebase and retrieving the downloadable URL in order to save it in a database. It seems like Firebase Admin Java JDK does not give any feature to either directly retrieve a downloadable URL for the file just uploaded or retrieving an access token to make possible to build it. Although there is a property configured as a metadata named 'firebaseStorageDownloadTokens' that can be find after the file get uploaded to the Firebase and stores the necessary token to authorize the download of the file, it still not working because this property is not retrieved for all requests and to be honest I cannot find why it happens. Anyway, the solution that worked for me was to add 'firebaseStorageDownloadTokens' directing as a metadata for the BlobInfo before uploading the file. It will make the Firebase assuming the passed value as the access token for the file being uploaded and once handing this information it's possible to build the downloadable URL.
In your scenario it would be like:
File file = convertMultiPartToFile(multipartFile);
Path filePath = file.toPath();
String objectName = generateFileName(multipartFile);
BlobId blobId = BlobId.of(bucketName, objectName);
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setMetadata(Map.of("firebaseStorageDownloadTokens","randomAccessToken")).build();
Blob blob = storage.create(blobInfo, Files.readAllBytes(filePath));
log.info("File " + filePath + " uploaded to bucket " + bucketName + " as " + objectName);
return blob.getMediaLink().concat("&token=randomAccessToken");
Firebase by default does not return any download URLs on Service Accounts until in Client Side SDKs, therefore, what you can do is, construct your own download URL by following the Firebase Convention.
`https://firebasestorage.googleapis.com/v0/b/<bucket name>/o/%s?alt=media`
`<bucket name>` = Firebase Storage Bucket Name
`%s` = The media name (file name)
You can get the download link after uploading a file to firebase Storage by using: storage.get(BlobId.of(bucketName,fileName)).getSelfLink();

Firebase Storage REST API

I need very simple static image server for my flutter app. I am thinking about Cloud Storage, because I don't want to worry about own server administrating. I am using experimental Flutter for Desktop as tool for preparation data for mobile app, so I can use only REST API. I found out that Firebase Storage doesn't have own REST API and uses Google Cloud's one. To upload image to Cloud Storage I should make something like this:
curl -X POST --data-binary #[IMAGE_LOCATION] \
-H "Authorization: Bearer [OAUTH2_TOKEN]" \
-H "Content-Type: image/jpeg" \
"https://www.googleapis.com/upload/storage/v1/b/[BUCKET_NAME]/o?uploadType=media&name=[IMAGE_NAME]"
The problem is I can't understand how to get [OAUTH2_TOKEN] (access token) from my Dart code, and how to administrate my images (should I do something with Firebase Admin SDK?)
Could anyone help me, please?
I found answer to this question. First you need to create private key for service account in Firebase settings. Then use it to get access token using dart packages googleapis_auth and http.
var accountCredentials = ServiceAccountCredentials.fromJson({
"private_key_id": "<please fill in>",
"private_key": "<please fill in>",
"client_email": "<please fill in>#developer.gserviceaccount.com",
"client_id": "<please fill in>.apps.googleusercontent.com",
"type": "service_account"
});
var scopes = [
'https://www.googleapis.com/auth/cloud-platform',
];
var client = Client();
AccessCredentials credentials = await obtainAccessCredentialsViaServiceAccount(accountCredentials, scopes, client);
String accessToken = credentials.accessToken.data;
File image = File('path/to/image');
var request = Request(
'POST',
Uri.parse('https://storage.googleapis.com/upload/storage/v1/b/[BUCKET_NAME]/o?uploadType=media&name=images/$imageName'),
);
request.headers['Authorization'] = "Bearer $accessToken";
request.headers['Content-Type'] = "image/jpeg";
request.bodyBytes = await image.readAsBytes();
Response response = await Response.fromStream(await request.send());
print(response.statusCode);
client.close();
Get request you can make the similar way, but you have to encode firebase path to image:
var imagePath = 'images/img.jpg';
var encodedImagePath = Uri.encodeQueryComponent(imagePath);
var request = Request(
'GET',
Uri.parse('https://storage.googleapis.com/storage/v1/b/[BUCKET_NAME]/o/$encodedImagePath?alt=media'),
);
request.headers['Authorization'] = "Bearer $accessToken";
Google Cloud REST API: https://cloud.google.com/storage/docs/downloading-objects
The Firebase Storage REST API allows you to upload and download files from Cloud Storage using HTTP requests. You can use this API to build server-side applications that interact with Cloud Storage, or to integrate Cloud Storage into your existing server-side application.
To use the Firebase Storage REST API, you will need to have a Firebase project and a Cloud Storage bucket set up. You can set up a new Firebase project and Cloud Storage bucket by following the instructions in the Firebase documentation.
Once you have a Cloud Storage bucket set up, you can use the following HTTP methods to access and manipulate files in your bucket:
POST: To upload a new file to Cloud Storage, you can send a POST request to the /upload endpoint, along with the file data in the request body.
GET: To download a file from Cloud Storage, you can send a GET request to the /download endpoint, specifying the file's path in the bucket as a query parameter.
DELETE: To delete a file from Cloud Storage, you can send a DELETE request to the /delete endpoint, specifying the file's path in the bucket as a query parameter.
To authenticate your requests to the Firebase Storage REST API, you will need to provide a valid Firebase Authorization header with each request. You can generate this header using a JSON service account key file, which you can obtain from the Firebase console.
For more information about using the Firebase Storage REST API, including examples of how to make requests and handle responses, you can refer to the Firebase Storage REST documentation.
I hope this helps!

trying to upload image to Azure but getting 404

I'm trying to upload an image from Server to Azure:
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(GLOBAL_AZURE.AZURE_STORAGE_CONNECTION_STRING);
CloudBlobContainer container = storageAccount.CreateCloudBlobClient().GetContainerReference("my-container");
CloudBlockBlob blockBlob = container.GetBlockBlobReference("my-img.jpg");
using (FileStream img = File.Open("d:\...\my-img.jpg",FileMode.Open))
{
blockBlob.UploadFromStream(img);
}
Everything works fine until UploadFromStream throws:
"The remote server returned an error: (404) Not Found."
my-container was created on the Portal and was defined "Public Blob".
Any ideas what might be the problem?
This is caused if the container does not exist
See this SO question as well getting 404 error when connecting to azure storage account
You can ensure the container exists by calling container.CreateIfNotExists() prior to uploading the blob.
Personally I run this as part of some application start up code rather than on every blob upload.
This article has background
https://azure.microsoft.com/en-gb/documentation/articles/storage-monitoring-diagnosing-troubleshooting/#the-client-is-receiving-404-messages
In the scenario where a client is attempting to insert an object, it
may not be immediately obvious why this results in an HTTP 404 (Not
found) response given that the client is creating a new object.
However, if the client is creating a blob it must be able to find the
blob container, if the client is creating a message it must be able to
find a queue, and if the client is adding a row it must be able to
find the table.

Resources