Xamarin Forms upload image Laravel POST Request failed - android

If I upload over Insomnia an image to my Laravel application everything is ok and I get following log
[2020-03-04 05:26:39] local.DEBUG: array (
'image' =>
Illuminate\Http\UploadedFile::__set_state(array(
'test' => false,
'originalName' => 'Screenshot_1583210368.png',
'mimeType' => 'image/png',
'error' => 0,
'hashName' => NULL,
)),
)
But if I upload an image on android emulator the log file in Laravel looks like (1000+ lines) :
�"#�G����ޠ��U��H��I�G"Ĉ`.SB^G
This is my Xamarin Function :
public async Task<string> uploadImage(Stream stream)
{
using (var client = new HttpClient())
{
var content = new MultipartFormDataContent();
content.Add(new StreamContent(stream),"image");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", (Application.Current.Properties["access_token"].ToString()));
var result = await client.PostAsync("https://example.com/api/upload/image", content);
return "";
}
}

Example of uploading a image to server side in Xamarin:
private MediaFile _image;
// code here to assign image to _image
var content = new MultipartFormDataContent();
content.Add(new StreamContent(_image.GetStream()), "\"file\"", $"\"{_image.Path}\"");
var httpClient = new System.Net.Http.HttpClient();
var url = "http://upload.here.io/folder/subdir";
var responseMsg = await httpClient.PostAsync(url, content);
var remotePath = await responseMsg.Content.ReadAsStringAsync();

Related

Uploading image file from React native to ASP.net core API

I'm trying to upload image from React native(without expo) (on Android OS only) to a post endpoint in ASP.net core web API.
In my react native app, I have used 'react-native-image-picker' to capture the image using camera like below.
launchCamera(options, (response: ImagePickerResponse) => {
console.log('Response = ', response);
if (response.assets) {
setVehicle({
...vehicle,
image: {
name: response.assets[0].fileName,
uri: response.assets[0].uri,
type: response.assets[0].type,
},
});
}
});
Once I have the image details is my vehicle state, I'm adding it to form data and doing axios post call like below.
const data = new FormData();
data.append('image', {
name: vehicle.image.name,
uri: vehicle.image.uri,
type: vehicle.image.type,
});
axios.post('https://localhost:44343/api/vehicle', data, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
My post endpoint in ASP.net core web api looks like this.
[Route("")]
[HttpPost]
public IActionResult Post([FromForm(Name = "image")]IFormFile image)
{
//Upload the image to blob storage
}
The image argument variable always contains null value in this endpoint, I tried many think but couldn't fix this. Can anyone help me?😞
Finally found a way to upload images. Not sure if this is the ideal way, but this the only way I could make it work.
After getting the image URI of captured image, I fetched the blob for the image.
const image = await fetch(vehicleImageURI);
const blob = await image.blob();
const fileReaderInstance = new FileReader();
fileReaderInstance.readAsDataURL(blob);
fileReaderInstance.onload = () => {
const base64data = fileReaderInstance.result;
postVehicle({ ...vehicle, base64Image: base64data as string })
.then((res) => {
console.log(res);
})
.catch((ex) => {
console.log(ex);
});
};
On the API side I removed the IFormFile and FromForm from post endpoint and removed the base64image as string.
[Route("")]
[HttpPost]
public IActionResult Post(string image)
{
Regex regex = new Regex(#"^[\w/\:.-]+;base64,");
var base64File = regex.Replace(data.Base64Image, string.Empty);
byte[] imageBytes = Convert.FromBase64String(base64File);
MemoryStream stream = new MemoryStream(imageBytes, 0, imageBytes.Length);
}
Please let us known if you know a better way to do this!🤞

Uploading blob with XMLHttpRequest doesn't work in Android - React Native/Expo

I'm using Firestore v9 within Expo/React Native. I use XMLHttpRequest to convert a base64 image into a blob file. Then I send/upload that blob file to Firebase Storage. It works perfectly with iOS but not with Android. In Android it returns {istrusted: false}, like the network request is not sent or something went wrong during converting the base64 image into a blob file.
I tried to use react-native-fetch-blob library as mentioned here but it's not supported by Expo.
This is my code:
const getBlob = async (photo) => {
return await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log("consoleloge",e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", photo, true);
xhr.send(null);
});
}
const upload64BaseImage = async (photo, newDocRef) => {
try {
const blob = await getBlob(photo)
const imageRef = ref(storage, `images/${newDocRef}.jpg`);
const metadata = {
contentType: "image/jpeg",
};
const snapshot = await uploadBytes(imageRef, blob, metadata);
const downloadUrl = await getDownloadURL(snapshot.ref);
return downloadUrl;
} catch (error) {
console.log(`error`, error.message);
}
};

Uploading to Firebase Storage using uri from GIF [duplicate]

I'm wondering how to upload file onto Firebase's storage via URL instead of input (for example). I'm scrapping images from a website and retrieving their URLS. I want to pass those URLS through a foreach statement and upload them to Firebase's storage. Right now, I have the firebase upload-via-input working with this code:
var auth = firebase.auth();
var storageRef = firebase.storage().ref();
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var file = evt.target.files[0];
var metadata = {
'contentType': file.type
};
// Push to child path.
var uploadTask = storageRef.child('images/' + file.name).put(file, metadata);
// Listen for errors and completion of the upload.
// [START oncomplete]
uploadTask.on('state_changed', null, function(error) {
// [START onfailure]
console.error('Upload failed:', error);
// [END onfailure]
}, function() {
console.log('Uploaded',uploadTask.snapshot.totalBytes,'bytes.');
console.log(uploadTask.snapshot.metadata);
var url = uploadTask.snapshot.metadata.downloadURLs[0];
console.log('File available at', url);
// [START_EXCLUDE]
document.getElementById('linkbox').innerHTML = 'Click For File';}
Question what do I replace
var file = evt.target.files[0];
with to make it work with external URL instead of a manual upload process?
var file = "http://i.imgur.com/eECefMJ.jpg"; doesn't work!
There's no need to use Firebase Storage if all you're doing is saving a url path. Firebase Storage is for physical files, while the Firebase Realtime Database could be used for structured data.
Example . once you get the image url from the external site this is all you will need :
var externalImageUrl = 'https://foo.com/images/image.png';
then you would store this in your json structured database:
databaseReference.child('whatever').set(externalImageUrl);
OR
If you want to actually download the physical images straight from external site to storage then this will require making an http request and receiving a blob response or probably may require a server side language ..
Javascript Solution : How to save a file from a url with javascript
PHP Solution : Saving image from PHP URL
This answer is similar to #HalesEnchanted's answer but with less code. In this case it's done with a Cloud Function but I assume the same can be done from the front end. Notice too how createWriteStream() has an options parameter similar to bucket.upload().
const fetch = require("node-fetch");
const bucket = admin.storage().bucket('my-bucket');
const file = bucket.file('path/to/image.jpg');
fetch('https://example.com/image.jpg').then((res: any) => {
const contentType = res.headers.get('content-type');
const writeStream = file.createWriteStream({
metadata: {
contentType,
metadata: {
myValue: 123
}
}
});
res.body.pipe(writeStream);
});
Javascript solution to this using fetch command.
var remoteimageurl = "https://example.com/images/photo.jpg"
var filename = "images/photo.jpg"
fetch(remoteimageurl).then(res => {
return res.blob();
}).then(blob => {
//uploading blob to firebase storage
firebase.storage().ref().child(filename).put(blob).then(function(snapshot) {
return snapshot.ref.getDownloadURL()
}).then(url => {
console.log("Firebase storage image uploaded : ", url);
})
}).catch(error => {
console.error(error);
});
Hopefully this helps somebody else :)
// Download a file form a url.
function saveFile(url) {
// Get file name from url.
var filename = url.substring(url.lastIndexOf("/") + 1).split("?")[0];
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", transferComplete);
xhr.addEventListener("error", transferFailed);
xhr.addEventListener("abort", transferCanceled);
xhr.responseType = 'blob';
xhr.onload = function() {
var a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response); // xhr.response is a blob
a.download = filename; // Set the file name.
a.style.display = 'none';
document.body.appendChild(a);
a.click();
delete a;
if (this.status === 200) {
// `blob` response
console.log(this.response);
var reader = new FileReader();
reader.onload = function(e) {
var auth = firebase.auth();
var storageRef = firebase.storage().ref();
var metadata = {
'contentType': 'image/jpeg'
};
var file = e.target.result;
var base64result = reader.result.split(',')[1];
var blob = b64toBlob(base64result);
console.log(blob);
var uploadTask = storageRef.child('images/' + filename).put(blob, metadata);
uploadTask.on('state_changed', null, function(error) {
// [START onfailure]
console.error('Upload failed:', error);
// [END onfailure]
}, function() {
console.log('Uploaded',uploadTask.snapshot.totalBytes,'bytes.');
console.log(uploadTask.snapshot.metadata);
var download = uploadTask.snapshot.metadata.downloadURLs[0];
console.log('File available at', download);
// [START_EXCLUDE]
document.getElementById('linkbox').innerHTML = 'Click For File';
// [END_EXCLUDE]
});
// `data-uri`
};
reader.readAsDataURL(this.response);
};
};
xhr.open('GET', url);
xhr.send();
}
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
function transferComplete(evt) {
window.onload = function() {
// Sign the user in anonymously since accessing Storage requires the user to be authorized.
auth.signInAnonymously().then(function(user) {
console.log('Anonymous Sign In Success', user);
document.getElementById('file').disabled = false;
}).catch(function(error) {
console.error('Anonymous Sign In Error', error);
});
}
}
function transferFailed(evt) {
console.log("An error occurred while transferring the file.");
}
function transferCanceled(evt) {
console.log("The transfer has been canceled by the user.");
}

Uploading files to Firebase Storage from URL file [duplicate]

I'm wondering how to upload file onto Firebase's storage via URL instead of input (for example). I'm scrapping images from a website and retrieving their URLS. I want to pass those URLS through a foreach statement and upload them to Firebase's storage. Right now, I have the firebase upload-via-input working with this code:
var auth = firebase.auth();
var storageRef = firebase.storage().ref();
function handleFileSelect(evt) {
evt.stopPropagation();
evt.preventDefault();
var file = evt.target.files[0];
var metadata = {
'contentType': file.type
};
// Push to child path.
var uploadTask = storageRef.child('images/' + file.name).put(file, metadata);
// Listen for errors and completion of the upload.
// [START oncomplete]
uploadTask.on('state_changed', null, function(error) {
// [START onfailure]
console.error('Upload failed:', error);
// [END onfailure]
}, function() {
console.log('Uploaded',uploadTask.snapshot.totalBytes,'bytes.');
console.log(uploadTask.snapshot.metadata);
var url = uploadTask.snapshot.metadata.downloadURLs[0];
console.log('File available at', url);
// [START_EXCLUDE]
document.getElementById('linkbox').innerHTML = 'Click For File';}
Question what do I replace
var file = evt.target.files[0];
with to make it work with external URL instead of a manual upload process?
var file = "http://i.imgur.com/eECefMJ.jpg"; doesn't work!
There's no need to use Firebase Storage if all you're doing is saving a url path. Firebase Storage is for physical files, while the Firebase Realtime Database could be used for structured data.
Example . once you get the image url from the external site this is all you will need :
var externalImageUrl = 'https://foo.com/images/image.png';
then you would store this in your json structured database:
databaseReference.child('whatever').set(externalImageUrl);
OR
If you want to actually download the physical images straight from external site to storage then this will require making an http request and receiving a blob response or probably may require a server side language ..
Javascript Solution : How to save a file from a url with javascript
PHP Solution : Saving image from PHP URL
This answer is similar to #HalesEnchanted's answer but with less code. In this case it's done with a Cloud Function but I assume the same can be done from the front end. Notice too how createWriteStream() has an options parameter similar to bucket.upload().
const fetch = require("node-fetch");
const bucket = admin.storage().bucket('my-bucket');
const file = bucket.file('path/to/image.jpg');
fetch('https://example.com/image.jpg').then((res: any) => {
const contentType = res.headers.get('content-type');
const writeStream = file.createWriteStream({
metadata: {
contentType,
metadata: {
myValue: 123
}
}
});
res.body.pipe(writeStream);
});
Javascript solution to this using fetch command.
var remoteimageurl = "https://example.com/images/photo.jpg"
var filename = "images/photo.jpg"
fetch(remoteimageurl).then(res => {
return res.blob();
}).then(blob => {
//uploading blob to firebase storage
firebase.storage().ref().child(filename).put(blob).then(function(snapshot) {
return snapshot.ref.getDownloadURL()
}).then(url => {
console.log("Firebase storage image uploaded : ", url);
})
}).catch(error => {
console.error(error);
});
Hopefully this helps somebody else :)
// Download a file form a url.
function saveFile(url) {
// Get file name from url.
var filename = url.substring(url.lastIndexOf("/") + 1).split("?")[0];
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", transferComplete);
xhr.addEventListener("error", transferFailed);
xhr.addEventListener("abort", transferCanceled);
xhr.responseType = 'blob';
xhr.onload = function() {
var a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response); // xhr.response is a blob
a.download = filename; // Set the file name.
a.style.display = 'none';
document.body.appendChild(a);
a.click();
delete a;
if (this.status === 200) {
// `blob` response
console.log(this.response);
var reader = new FileReader();
reader.onload = function(e) {
var auth = firebase.auth();
var storageRef = firebase.storage().ref();
var metadata = {
'contentType': 'image/jpeg'
};
var file = e.target.result;
var base64result = reader.result.split(',')[1];
var blob = b64toBlob(base64result);
console.log(blob);
var uploadTask = storageRef.child('images/' + filename).put(blob, metadata);
uploadTask.on('state_changed', null, function(error) {
// [START onfailure]
console.error('Upload failed:', error);
// [END onfailure]
}, function() {
console.log('Uploaded',uploadTask.snapshot.totalBytes,'bytes.');
console.log(uploadTask.snapshot.metadata);
var download = uploadTask.snapshot.metadata.downloadURLs[0];
console.log('File available at', download);
// [START_EXCLUDE]
document.getElementById('linkbox').innerHTML = 'Click For File';
// [END_EXCLUDE]
});
// `data-uri`
};
reader.readAsDataURL(this.response);
};
};
xhr.open('GET', url);
xhr.send();
}
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
function transferComplete(evt) {
window.onload = function() {
// Sign the user in anonymously since accessing Storage requires the user to be authorized.
auth.signInAnonymously().then(function(user) {
console.log('Anonymous Sign In Success', user);
document.getElementById('file').disabled = false;
}).catch(function(error) {
console.error('Anonymous Sign In Error', error);
});
}
}
function transferFailed(evt) {
console.log("An error occurred while transferring the file.");
}
function transferCanceled(evt) {
console.log("The transfer has been canceled by the user.");
}

react-native upload pictures on android

I have a react-native app on Android and a backend server written in NodeJS + Express and I'm using multer to handle file uploads.
const multer = require('multer');
const mime = require('mime');
const crypto = require('crypto');
const storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, config.uploads),
filename: (req, file, cb) => {
crypto.pseudoRandomBytes(16, (err, raw) => {
cb(null, raw.toString('hex') + Date.now() + '.' + mime.extension(file.mimetype));
});
}
});
const upload = multer({ storage });
const Router = require('express').Router;
const controller = require('./upload.controller');
const router = new Router();
const auth = require('./../../auth/auth.service');
router.post('/', [auth.isAuthenticated(), upload.any()], controller.create);
module.exports = router;
And on my react-native app I try to do like this:
ImagePicker.launchCamera(options, image => {
let { uri } = image
const API_URL = 'http://192.168.1.2:9000/api/uploads'
var form = new FormData();
form.append("FormData", true)
form.append("access_token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjU3YjgyZGQ2MTEwZDcwYmEwYjUxZjM5YyIsImlzTWVkaWMiOnRydWUsImlhdCI6MTQ3MTY4ODE1MiwiZXhwIjoxNDcxNzA2MTUyfQ.gPeql5g66Am4Txl1WqnbvOWJaD8srTK_6vihOJ6kFbY")
form.append("Content-Type", "image/jpg")
form.append('image', uri)
fetch(API_URL, {body: form, mode: "FormData", method: "post", headers: {"Content-Type": "multipart/form-data"}})
.then((response) => console.log(response))
.catch((error) => {
console.log("ERROR " + error)
})
.then((responseData) => {
console.log("Succes "+ responseData)
})
.done();
})
But when I try to upload I recive the following error
multipart body must have at least one part
I am doing something wrong?
Does anybody knows a better solution to do this?
Fetch may not support Blob and FormData at this moment, but you can use XMLHttpRequest polyfill instead.
let xhr = new XMLHttpRequest()
xhr.open('post', `http://myserver.com/upload-form`)
xhr.send(form)
xhr.onerror = function(e) {
console.log('err', e)
}
xhr.onreadystatechange = function() {
if(this.readyState === this.DONE) {
console.log(this.response)
}
}

Categories

Resources