Seems like a straightforward issue, but how can you retrieve an image stored in a database, using Web API, then display it using Angular?
Here is an example Web API service which is correctly returning a JPG file (using HttpResponseMessage):
public HttpResponseMessage GetIncidentImages(Guid IncidentIDX) {
var response = new HttpResponseMessage();
List<T_EM_INCIDENT_ATTACH> att = db_Layer.GetT_EM_INCIDENT_ATTACH_byIncidentIDX(IncidentIDX);
if (att != null)
{
if (att.Count > 0)
{
var pictureBytes = att[0].ATTACH_CONTENT; //ATTACH_CONTENT is a byte array
if (pictureBytes == null)
response.StatusCode = HttpStatusCode.NotFound;
else
{
response.Content = new ByteArrayContent(pictureBytes);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
}
}
else
response.StatusCode = HttpStatusCode.NotFound;
}
return response;
}
Then on the http client-side, I am using angular to retrieve the data. Data is definitely getting retrieved, but just not displayed.
dbManagerService.syncIncidentAttach(ehConstants.incidenT_IDX).then(function (res) {
console.log("return", res);
$scope.cameraPic = res;
});
function _syncIncidentAttach(incIDX) {
var deferred = $q.defer();
$http.get($rootScope.serverBaseUrl + 'api/incident/GetIncidentImages?IncidentIDX=' + incIDX, { responseType: "blob" })
.success(function (res, status, headers, config) {
// encode data to base 64 url
fr = new FileReader();
fr.onload = function () {
// this variable holds your base64 image data URI (string)
// use readAsBinary() or readAsBinaryString() below to obtain other data types
console.log(fr.result);
};
fr.readAsDataURL(res);
deferred.resolve(fr);
})
.error(function(data, status, headers, config) {
conole.log('error getting image');
});
return deferred.promise;
}
And the html:
<img ng-src="{{cameraPic}}" /> </div>
Looking at your server side code, I think you can directly write like this:
<img ng-src="{{serverBaseUrl}}api/incident/GetIncidentImages?IncidentIDX={{ehConstants.incidenT_IDX}}" />
Just make sure you are replacing ehConstants.incidenT_IDX with actual content.
As documented in this answer, you can also do something like
<img ng-src="{{'data:image/png;base64,' + main.user.imageData}}">
Related
I'm working in a solution with SOA architect, and I have got an issue converting a .zip file in a byte array on WS Layer and download by a web API from the presentation layer.
The zip file download is successful, but it's not possible to unzip the file.
Let me explain with code:
Business Layer
On business layer we've defined a method that converts a file zip on a byte array
//This method is defined on business layer and exposed on WS in WCF Layer
//Class: BusinessLayer
public byte[] convertingZip(){
try{
pathFile = "directoryOnServer/myZipFile.zip"
byte[] arr = File.ReadAllBytes(pathFile);
return arr;
}catch(Exception ex){ /*Do something*/ }
}
WCF Services Layer
On WCF services layer, we code a method that returns the array bytes and exposed it
//Class: ServiceLayer
public byte[] getByteArray(){
try{
BusinessLayer blObject = new BusinessLayer();
return blObject.convertingZip();
}catch(Exception ex){ /*Do something*/ }
}
Web API
On Web API project, we code a method that consumes the WCF service layer and return byte array into content
//This controller must be return the zip file
[HttpGet]
[AuthorizeWebApi]
[Route("downloadZip")]
public async Task<IHttpActionResult> downloadZipFile(){
try{
using(ServiceLayer services = new ServiceLayer()){
arr = services.getByteArray();
var result = new HttpResponseMensage(HttpStatusCode.OK){
Content = new ByteArrayContent(arr); }
result.Content.Headers.ContentDisposition
= new ContentDispostionHeaderValue("attachment"){
FileName = "zip-dowload.zip" };
result.Content.Headers.ContentType
= new MediaTypeHeaderValue("application/octec-stream");
var response = ResponseMessage(result);
return result;
}
}cacth(Exception ex){ /*Do something*/ }
}
Presentation Layer
On presentation layer I download the file with angular JS 1.6.5
//On Web App project consume the WebApi with Angular
//MyController.js
$scope.DonwloadZip = function(){
$http.get('api/myControllerUrlBase/downloadZip')
.success(function(data, status, headers, config){
if(status === true && data != null){
var file = new Blob([data], {type: "application/zip"});
var fileURL = URL.createObjectUrl(file);
var a = document.createElement(a);
a.href = fileURL;
a.target = "_blank";
a.download = "MyZipFileName.zip";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}else { /*Do something */}
})
.error(function(data, status, headers, config) {
//show error message
});
}
I'm not sure that doing right. I test some similar with .xml, .txt. and .csv files and works. But don't work with zip files.
Then, What is the correct way to convert a zip file in a byte array and getting my web API from web app project?
I'll very grateful for help.
Well, I've resolve the issue and I would like share the solution.
The central problem it's on web-api and presentation layer, then we need modify the code here:
On Api Controller, convert the byte array into a string on base64 and send on http response content
[HttpGet]
[AuthorizeWebApi]
[Route("downloadZip")]
public async Task<IHttpActionResult> downloadZipFile(){
try{
//Using WS reference
using(ServiceLayer services = new ServiceLayer()){
//Catch the byte array
arr = services.getByteArray();
//Encode in base64 string
string base64String = System.Convert.ToBase64String(arr, 0, arr.length);
//Build the http response
var result = new HttpResponseMensage(HttpStatusCode.OK){
Content = new StringContent(base64String); }
result.Content.Headers.ContentDisposition
= new ContentDispostionHeaderValue("attachment"){
FileName = "zip-dowload.zip" };
result.Content.Headers.ContentType
= new MediaTypeHeaderValue("application/octec-stream");
var response = ResponseMessage(result);
return result;
}
}cacth(Exception ex){ /*Do something*/ }
}
On Angular Controller, no convert data response on Blob, define metadata about data response and download:
$scope.DonwloadZip = function(){
$http.get('api/myControllerUrlBase/downloadZip')
.success(function(data, status, headers, config){
if(status === true && data != null){
//No convert data on Blob
var fileURL = 'data:application/octec-stream;charset=utf-8;base64,'+ data;
var a = document.createElement(a);
a.href = fileURL;
a.target = "_blank";
a.download = "MyZipFileName.zip";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}else { /*Do something */}
})
.error(function(data, status, headers, config) {
//show error message
});
}
Remember that if you're using a Angular 1.6.5 or up version, http request must be something like:
$http({
method: 'GET',
url: 'api/myControllerUrlBase/downloadZip'
}).then(function (response){
//Success
},function (error){
//Error
});
I hope that be useful for somebody, thanks for try help!
I can achieved this from below method
downloadFile(base64: string,filename: string, mimetype: string) {
var fileURL = 'data:application/octec-stream;charset=utf-8;base64,' + base64;
var a = document.createElement('a');
a.href = fileURL;
a.target = "_blank";
a.download = filename + ".pdf";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
<a [href]="fileUrl" (click)="downloadFile(type.base64String,type.name,type.extension)"> {{type.name}}
I am trying to download a pdf file from server and show it in browser. The web api method that I have returns the file as httpResponseMessage and that is working fine because it returns the file. But on the AngularJs side I am not able to display the file. Can somebody help me understand what am I missing?
Web Api Method:
public HttpResponseMessage GetHelpReferenceDocs(Guid streamKey)
{
var fakeFileName = GetStream(streamKey); // If this succeeds, stream is known and unexpired.
// Internal file name
string staticFileName = helpFiles[fakeFileName];
var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Static/" + staticFileName);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(mappedPath, FileMode.Open, FileAccess.Read, FileShare.Read);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(mappedPath);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentLength = stream.Length;
return result;
}
AngularJS:
function loadDocument(fileName) {
REST.post(commonService.constants.webapi.helpFileStreamKey + fileName)
.then(function(response) {
var streamGuid = response.data;
REST.get(commonService.constants.webapi.helpReferenceGuide + streamGuid).then(function (response) {
$window.open(response.data);
});
})
.catch(function (e) { $scope.errorHandler(moduleName, e); })
.finally($scope.waitOn);
}
Take a look at the suggestions here, or alternatively you can try an npm module specifically for displaying pdfs where this is already taken care of for you, such as this one.
Ok I found the solution. Needed to modify my Angular code a little bit and it worked fine. Here is the code if somebody facing the same problem:
function loadDocument(fileName) {
REST.post(commonService.constants.webapi.helpFileStreamKey + 'firmUserGuid')
.then(function(response) {
var streamGuid = response.data;
REST.get(commonService.constants.webapi.helpReferenceGuide + streamGuid).then(function (response) {
var pdfFileURL = response.config.url;
$window.open(pdfFileURL);
});
})
.catch(function (e) { $scope.errorHandler(moduleName, e); })
.finally($scope.waitOn);
}
Im working on exporting data from a wordpress environment to a MongoDB using MongooseJS as data model bridges. I've got a JSON with every objects including all required information.
As a example, I've got user item including an avatarpath field pointing to the wordpress server url: (ex: http://url/wp-content/upload/img/avatar.jpg)
What I would like to do it retrieving the image from its url, upload it to my new storage folder, retrieve the new path, and store the new object in my mongodb.
My issue is that I can't manage to find a way to get the file data from a http get or any other way. Usually, I've got a file input in my html, and I start from the file object from this input. How should I proceed to make this work? Am I going into the wrong direction?
I've found this answer but it seems deprecated:
how to upload image file from url using FileReader API?
Here is what I've got for now:
$scope.curateurs_data = {};
$scope.curateurs = [];
$http.get('resources/json_curateurs.json').success(function(data) {
$scope.curateurs_data = data;
console.log(data[0]);
$scope.getPics();
});
//RETRIEVE IMAGE DATA
$scope.getPics = function(data){
console.log("RETRIEVING PICTURE")
var uploadPlace = '/upload/user';
var images;
angular.forEach($scope.curateurs_data, function(item, key) {
$scope.curitem = item;
console.log($scope.curitem);
$http.get(item.avatarpath, {responseType: "arraybuffer"}).success(function(data){
var arrayBufferView = new Uint8Array( data );
var blob = new Blob( [ arrayBufferView ], { type: "image/png" } );
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL( blob );
console.log(imageUrl);
console.log(blob);
images = blob;
var pic = {
images: images
};
Upload.upload({
url: uploadPlace,
arrayKey: '',
data: pic,
}).then(function(response) {
// Adding data paths to formData object before creating mood
// MUST respect images array order
$scope.curitem.avatarpath = response.data.files[0].path;
console.log(response.data.files[0].path);
});
}).error(function(err, status){})
$scope.curateurs.push($scope.curitem);
});
}
I've also tried something like this but I can't seems to make it work as well.
$http.get(item.avatarpath,{responseType: "blob"}).
success(function(data, status, headers, config) {
// encode data to base 64 url
fr = new FileReader();
fr.onload = function(){
// this variable holds your base64 image data URI (string)
// use readAsBinary() or readAsBinaryString() below to obtain other data types
console.log( fr.result );
};
fr.readAsDataURL(data);
console.log(fr.readAsDataURL(data));
}).
error(function(data, status, headers, config) {
alert("The url could not be loaded...\n (network error? non-valid url? server offline? etc?)");
});
Use node's http object on the backend to download the image. Something like:
http.request(url, function(response) {
// Your code to write the file out or store it in the database here.
});
I have WebAPI method which returns HttpResponseMessage with .csv file as Content:
private static HttpResponseMessage FileAsAttachment(string file)
{
var now = DateTime.Now;
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StringContent(file);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); //attachment will force download
result.Content.Headers.ContentDisposition.FileName = string.Format("Report-{0}.csv", now.ToString("MMMM"));
return result;
}
So I have just click function, which make call to server :
$scope.GenerateReport = function() {
var endDate = '2016-04-30';
UserDaysSummary.generateReport({endDate: endDate }, function (result) {
console.log("Export");
});
}
But all that I've got - is a response with data inside.
I've tried to get it as file using this and this answer, but this doesn't change anything.
Preferably, that call to the server has GET method, btw
Is your GenerateReport function returning a promise? Try this:
userDaysSummary.generateReport = function(endDate) {
var defer = $q.defer();
$http.get('path/to/api', { endDate: endDate }, { responseType: 'arrayBuffer' }).then(function(data, status, headers, config) {
var results = {
data: data, //your file is here
headers: headers(), //headers are here
status: status,
config: config
};
//return a success promise containing the response object
defer.resolve(results);
}, function(data, status, headers, config) {
defer.reject(data);
});
return defer.promise;
}
Then, using the promise to download the file:
userDaysSummary.generateReport(endDate).then(function(response) {
//get the file
var octetStreamMime = 'application/octet-stream';
//get the headers' content disposition
var cd = response.headers["content-disposition"];
//get the file name with regex
var regex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var match = regex.exec(cd);
//is there a fiel name?
var fileName = match[1] || "myDefaultFileName.csv";
//replace leading and trailing slashes that C# added to your file name
fileName = fileName.replace(/\"/g, "");
//determine the content type from the header or default to octect stream
var contentType = response.headers["content-type"] || octetStreamMime;
//finally, download it
try {
var blob = new Blob([response.data], {type: contentType});
//downloading the file depends on the browser
//IE handles it differently than chrome/webkit
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}
} catch (exc) {
console.log("Save Blob method failed with the following exception.");
console.log(exc);
}
}, function(error) {
//an error occurred while trying the API, handle this
});
I'm using the $http.get(...) method in SPA to get pdf download.
In the SPA ,print method give the blank pdf .
But when i did the debug, data come from the API.
Can you help on this?
This is the API implementation to response the stream out as application/pdf
public Stream GetConsumerInformationReport(Guid id)
{
..........
var stream = cryRpt.ExportToStream(ExportFormatType.PortableDocFormat);
return stream;
}
SPA implementation of get the data from API
var print = function () {
var downloadPath = apiEndPoint + 'Reports/' + $state.current.data.printPrefix + '.pdf';
$http.get(downloadPath,httpConfig).
success(function (data) {
var blob = new Blob([data], { type: "application/pdf" });
var objectUrl = URL.createObjectURL(blob);
$window.open(objectUrl);
}).
error(function (data, status, headers, config) {
// if there's an error you should see it here
});
};
Use FileSaver.js from here http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js
Then define your download method like this. Take it only as an inspiration, do not copy-paste-run :)
The original version can be found here - http://davidjs.com/2015/07/download-files-via-post-request-in-angularjs/
//Define method download() in your ng controller
$scope.download = () => {
//Indicates that download is in progress
$scope.isDownloading = true;
return $http.get(downloadPath,httpConfig).$promise.then((data: any) => {
//using saveAs.js (part of upcoming HTML5 API, but so far a polyfill)
var blob = data.response.blob;
var fileName: string = data.response.fileName || 'document.pdf';
//SaveAs is available at saveAs.js from http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js
(<any>$window).saveAs(blob, fileName);
})
.finally(() => {
$scope.isDownloading = false;
});
}