Attempting to upload image with fetch api and C# web API - javascript

I have inherited the following C# code to upload an image, and I am attempting to try to call the endpoint using the fetch api.
Error I keep receiving:
{"Invalid 'HttpContent' instance provided. It does not have a content type header starting with 'multipart/'.\r\nParameter name: content"}
Any idea what I am doing wrong with calling this endpoint? I have included the C#/web api code, and the javascript code beneath that. Thanks for any help you can provide.
[Route( "coverpicture" )]
public virtual Task<HttpResponseMessage> Post()
{
HttpContext.Current.Response.ContentType = "application/json";
var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
var personId = CurrentUser.PersonId;
if ( !Request.Content.IsMimeMultipartContent() )
{
throw new HttpResponseException( HttpStatusCode.UnsupportedMediaType );
}
var task = Request.Content.ReadAsMultipartAsync().ContinueWith( t =>
{
var parts = t.Result.Contents;
var content = parts.First( x => x.Headers.ContentDisposition.Name.Contains( "CoverPicture" ) );
if ( content == null )
{
var resp = new HttpResponseMessage( HttpStatusCode.NotAcceptable )
{
Content = new ObjectContent<string>( "No ContentDisposition named CoverPicture.", formatter )
};
return resp;
}
using ( var imgStream = content.ReadAsStreamAsync().Result )
using ( var photos = new PhotosProvider() )
{
var photo = photos.CreateOrUpdateCoverPicture( personId, imgStream );
var resp = new HttpResponseMessage( HttpStatusCode.OK )
{
Content = new ObjectContent<Photo>( photo, formatter )
};
return resp;
}
} );
return task;
}
Javascript code:
let data = new FormData()
for (var x = 0; x < files.length; x++){
data.append("file" + x, files[x]);
}
fetch(url, {
method: 'POST',
mode: 'cors',
contentType: false,
processData: false,
body: JSON.stringify({}),
data: data
})
.then(parseResponse)
.then(resolve)
.catch(reject);

I think you should try as follows...
let data = new FormData()
for (var x = 0; x < files.length; x++){
data.append("file" + x, files[x]);
}
fetch(url, {
method: 'POST',
mode: 'cors',
body: data
})
.then(parseResponse)
.then(resolve)
.catch(reject);

Related

Complex HTML output to PDF in ASP.NET C#

A page in our asp.net C# project is producing the following output:
Sample real output
The charts which I am using here are "Highcharts" (in the rows too, as shown in the image).
The requirement is to export this to PDF.
The above output is being produced in a div.
The following is what I have tried:
HTML part:
<input type="button" id="cmdExport" value="Export" style="width:70px" />
JS part:
<script type="text/javascript">
const toDataURL = url => fetch(url)
.then(response => response.blob())
.then(blob => new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.onerror = reject
reader.readAsDataURL(blob)
}));
$('#cmdExport').click(function() {
var charts = Highcharts.charts,
exportUrl = 'https://export.highcharts.com/',
doc = new jsPDF(),
//doc = new jsPDF('p', 'pt', 'a4'),
pageHeight = doc.internal.pageSize.getHeight(),
ajaxCalls = [],
promises = [],
yDocPos = 0,
k = 0,
chart,
imgUrl,
i,
j;
for (i = 0; i < charts.length; i++) {
chart = charts[i];
ajaxCalls.push($.ajax({
type: 'post',
url: exportUrl,
data: {
options: JSON.stringify(chart.userOptions),
type: 'image/png',
async: true
}
}));
}
$.when.apply(null, ajaxCalls).done(function() {
for (j = 0; j < arguments.length; j++) {
imgUrl = exportUrl + arguments[j][0];
promises[j] = toDataURL(imgUrl);
}
Promise.all(promises).then((values) => {
values.forEach((value, index) => {
var page = doc.internal.getCurrentPageInfo();
if (yDocPos > pageHeight - 150) {
doc.addPage();
yDocPos = 25;
k = 0;
} else {
yDocPos = 25 + k * 140;
}
doc.setFontSize(30);
doc.text(50, yDocPos, 'jspdf title for Chart' + (index + 1));
yDocPos += 15;
doc.addImage(value, 'PNG', 20, yDocPos);
k++;
});
doc.save('charts.pdf');
});
});
});
</script>
The above code is giving error
"Access to XMLHttpRequest at 'https://export.highcharts.com/' from origin 'http://localhost:1042' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
Is there any other way to fulfill this requirement?
Any help on this would be appreciated.

How to open multiple sheets inside a google sheet using openByUrl() method in Apps Script

Currently, I'm using the code (written in Apps Script) given below to sync data from multiple google sheets to the database with the help of URLs. When the "sheetLinks" is given URL of sheets within a single google sheet file, it doesn't read the gid of the URL which is the only thing that differs between multiple sheets within a google sheet file thus making the for loop to run twice(as it is considering only the base URL which is same in both).
const sheetLinks = [
"https://docs.google.com/spreadsheets/d/same/edit#gid=0",
"https://docs.google.com/spreadsheets/d/same/edit#gid=654836738"
];
let baseUrl = "https://something/api";
function syncData() {
for (filenum = 0; filenum < sheetLinks.length; filenum++) {
let spreadsheet = SpreadsheetApp.openByUrl(sheetLinks[filenum]);
let values = spreadsheet.getDataRange().getValues();
for (let y = 1; y < values.length; y++)
{
let data = {};
data.name = values[y][11].toString();
data.platform = values[y][5].toString();
data.platform_link = values[y][6].toString();
let dbId = values[y][0];
let responseData = {};
if (dbId) {
responseData = updateSession(dbId, data);
console.log("Session updated! session ID: " + responseData.id);
} else {
responseData = createSession(data);
// write the id to the dbId cell
let actualRowNumber = y + 1; // y + 1 because we start the loop from y 1
spreadsheet.getRange("A" + actualRowNumber).setValue(responseData.id);
console.log("Session created! New session ID: " + responseData.id);
}
y++;
}
}
function apiRequest(url, method, data) {
let options = {
method,
contentType: "application/json",
payload: JSON.stringify(data),
muteHttpExceptions: true,
};
return UrlFetchApp.fetch(url, options);
}
function createSession(sessionData) {
let url = baseUrl + "/session";
let response = apiRequest(url, "post", sessionData);
console.log(response.getContentText());
let responseData = JSON.parse(response.getContentText());
return responseData;
}
function updateSession(sessionId, sessionData) {
let url = baseUrl + "/session/" + sessionId;
let response = apiRequest(url, "patch", sessionData);
let responseData = JSON.parse(response.getContentText());
return responseData;
}
}

javascript fetch an image and create base64

I'm using CloudFlare service workers and I want to fetch an image and then generate a base64 representation of it.
So something like this:
const res = await fetch('https://cdn.cnn.com/cnnnext/dam/assets/211010073527-tyson-fury-exlarge-169.jpg')
const blob = await res.blob();
console.log(blob)
console.log(btoa(blob))
this of course doesn't work, any ideas how to get this resolved?
complete worker script with cloudflare using btao
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
const imageUrl =
'https://upload.wikimedia.org/wikipedia/commons/thumb/7/72/' +
'Cat_playing_with_a_lizard.jpg/1200px-Cat_playing_with_a_lizard.jpg';
function base64Encode (buf) {
let string = '';
(new Uint8Array(buf)).forEach(
(byte) => { string += String.fromCharCode(byte) }
)
return btoa(string)
}
function base64Decode (string) {
string = atob(string);
const
length = string.length,
buf = new ArrayBuffer(length),
bufView = new Uint8Array(buf);
for (var i = 0; i < length; i++) { bufView[i] = string.charCodeAt(i) }
return buf
}
async function handleRequest(request) {
const
upstreamResponse = await fetch(imageUrl),
text = base64Encode(await upstreamResponse.arrayBuffer()),
bin = base64Decode(text);
return new Response(bin, {status: 200, headers: {
'Content-type': upstreamResponse.headers.get('Content-type')
}})
}
can refer this discussion as well

Uploading files via axios to WebApi

I'm getting this error when trying to upload a file to webapi
Unable to cast object of type 'System.String' to type 'System.Web.HttpPostedFile'
javascript:
UploadReceivingIssueImages(e) {
if (!e.target.files || e.target.files.length === 0)
return;
let formData = new FormData();
for (var i = 0; i < e.target.files.length; i++) {
formData.append('file', e.target.files[i]);
}
var vm = this;
axios.post('../api/receiving/UploadDocReceivingIssueImages?headerId=' + this.SelectedSubIdIdObj.HeaderId,
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function () {
vm.getDocReceivingIssueImages();
console.log('SUCCESS!!');
}, function (er) {
alert("Couldn't upload images")
});
}
WebApi Code
[HttpPost]
public bool UploadDocReceivingIssueImages([FromUri] int headerId)
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count < 1)
{
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent("No File Uploaded"),
ReasonPhrase = "No File Uploaded"
};
throw new HttpResponseException(resp);
}
var dirPath = #"\\dirPath";
foreach (var f in httpRequest.Files)
{
var pf = (System.Web.HttpPostedFile)f;
pf.SaveAs(dirPath + Guid.NewGuid().ToString() + pf.FileName);
}
return true;
}
the error happens at
var pf = (System.Web.HttpPostedFile)f;
the f object is a string with value 'file'... WHY?!?!
any help would be appreciated.
Because when you enumerate over HttpRequest.PostedFiles you're enumerating over its keys (the names, which are all 'file' based on your JS), not the files:
foreach (var key in httpRequest.Files)
{
var pf = httpRequest.Files[key]; // implicit cast to HttpPostedFile
pf.SaveAs(dirPath + Guid.NewGuid().ToString() + pf.FileName);
}
EDIT TO ADD:
With that said, you'll need to update your JS to use unique names in FormData or else you'll only be able to read one file out of your HttpContext's HttpFileCollection:
for (var i = 0; i < e.target.files.length; i++) {
formData.append('file' + i, e.target.files[i]);
}
See HttpFileCollection on MSDN

Uploading JavaScript Blob Issue

I'm trying to record a video (already working) using HTML5 video tag, "getUserMedia" to access the device camera and MediaRecorder API to capture the frames and Angular1 to handle the file uploading. Now I'm having trouble uploading the Blob to my PHP server which is running on Laravel, I currently have 2 ways to upload the video, first is by "ng-click" this works fine but when I programmatically upload the Blob using the same function which "ng-click" run it seems to break the mimeType of my Blob here's how my code looks.
$scope.uploader = function() {
let fData = new FormData();
let blob = new Blob($scope.chunk, { type: 'video/webm' });
fData.append('vid', blob)
$http.post(url, fData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
}, success, error)
})
$timeout(function() {
$scope.uploader();
}, 10000)
This issue here is when the "$scope.uploader()" is called using "ng-click" it works fine but when calling the "uploader" method using the "$timeout" it seems to change the mimeType to "application/octet-stream" which causes the issue.
Hello Try this code,
function base64ToBlob(base64Data, contentType) {
contentType = contentType || '';
var sliceSize = 1024;
var byteCharacters = atob(base64Data);
var bytesLength = byteCharacters.length;
var slicesCount = Math.ceil(bytesLength / sliceSize);
var byteArrays = new Array(slicesCount);
for (var sliceIndex = 0;sliceIndex <slicesCount;++sliceIndex) {
var begin = sliceIndex * sliceSize;
var end = Math.min(begin + sliceSize, bytesLength);
var bytes = new Array(end - begin);
for (var offset = begin, i = 0;offset <end;++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, {
type: contentType});
}
Define scope
$scope.onFile = function(blob) {
Cropper.encode((file = blob)).then(function(dataUrl) {
$scope.dataUrl = dataUrl;
$scope.odataUrl = dataUrl;
$timeout(showCropper); // wait for $digest to set image's src
});
};
Submit method
$scope.uploadImage = function () {
if ($scope.myCroppedImage === '')
{
}
$scope.msgtype = "";
$scope.msgtxt = "";
var fd = new FormData();
var imgBlob = dataURItoBlob($scope.myCroppedImage);
fd.append('clogo', imgBlob);
fd.append('actionfile', 'editimage');
$http.post(
'../user/user_EditCompany.php',
fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
}
)
.success(function (response) {
// console.log(response);
if (response.status == 'success')
{
//your code
}else{
//your code
}
})
.error(function (response) {
console.log('error', response);
});
};
function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {
type: mimeString
});
}
Thanks, the issue was caused by upload and post limit in my php.ini.

Categories