I'm trying to provide a browser user the ability to select a file from a list an download a file back to the user as a file download.
My JavaScript looks like this:
$scope.getFile = function (podUri, podName) {
$http.get('api/getDharmaPod', { params: { containerName: $scope.selectedContainer, podName: podName } })
.success(function (data, status, headers, config) {
$("#audio").text("Got file: ");
})
.error(function (data, status, headers, config) {
alert("got an error:" + status);
});
};
I've also tried the following that I found on stackOverflow
$scope.getFile = function (podUri, podName) {
$http({
method: 'GET',
params: { containerName: $scope.selectedContainer, podName: podName },
cache: false,
url: 'api/getDharmaPod',
headers: {
'Content-Type': 'audio/mpeg; charset=utf-8'
}
}).success(function (data, status) {
console.log(status);
}).error(function (data, status) {
alert("got an error:" + status);
});
};
But the result is the same: the browser silently receives the server's transmission and doesn't offer to save it anywhere.
My MVC controller method looks like this:
[HttpGet, Route("api/getDharmaPod")]
public async Task<HttpResponse> GetDharmaPod(string containerName, string podName)
{
var dharmaBlob = AzureStorageAccess.GetBlob(containerName, podName);
MemoryStream memStream = new MemoryStream();
dharmaBlob.DownloadToStream(memStream);
Response.ContentType = "audio/mpeg";
await Response.SendAsync(memStream.ToArray());
return null;
}
I've also tried:
[HttpGet, Route("api/getDharmaPod")]
public FileResult GetDharmaPod(string containerName, string podName)
{
var dharmaBlob = AzureStorageAccess.GetBlob(containerName, podName);
MemoryStream memStream = new MemoryStream();
dharmaBlob.DownloadToStream(memStream);
Response.ContentType = "audio/mpeg";
return File(memStream.ToArray(), "audio/mpeg", podName);
}
Again the browser receives the data but doesn't see it as a file to be stored. It just receives it into a variable. I'd want it to see it as a download and save it to the download file.
I'm not sure if I'm sending it incorrectly or receiving it incorrectly or both :-(
Thanks for any guidance.
I've decided to go another way since I can't seem to find a solution.
My solution is to just download the file directly from the container using the blob's url. I've made it somewhat secure by generating a shared access key in my controller as follows:
public static string GetSharedAccessKey(string containerName)
{
CloudStorageAccount storageAccount = GetAccount(_useDev);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
SharedAccessBlobPolicy blobPolicy = new SharedAccessBlobPolicy
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1)
};
return container.GetSharedAccessSignature(blobPolicy);
}
this returns an access key that can be appended to the 'a' tag's href link for the blob file that allows access for one hour.
I'm now getting a file that the browser is storing in the downloads directory as expected.
The result of allowing direct access to the storage account is also more efficient for the server-side app.
Related
I have a UI written in JavaScript with a .net core backend. My ajax call in JS looks like this:
const data = { users: userArray, message: sendMessage, url: optUrl };
$.ajax({
type: "POST",
url: `${App_Url}/ui/Notifications/send`,
dataType: "application/json",
data: JSON.stringify(data),
success: (response) => {
// if (spinner)
// spinner.stop();
//
notifySuccess("Users imported successfully!");
$("#user_table").html(response);
},
error: (error) => {
//if (spinner)
// spinner.stop();
//
notifyErrors(error.responseJSON.errors);
}
});
Now the problem that I'm having is that when my userArray is bigger than some number (not sure what the number is) then my server seems to just drop the call. For example when my userArray is size 15 I can set a break point in the .NET controller and get to it just fine. However when my userArray is 1000 I don't even get to the break point and my server returns a 500. What is causing this and how do I go about fixing it?
My controller:
[HttpPost("send")]
[DisableRequestSizeLimit]
public async Task<IActionResult> SendNotificationsAsync(CustomNotificationRq request)
{
var token = await _service.GetMiddlewareToken();
var users = request.users;
var message = request.message;
var url = request.url;
var response = await _service.SendNotificationAsync(users.ToList(), message, url, token.token);
return response;
}
You need to increase this value in your web.config in your .net core api application
<appSettings>
<add key="aspnet:MaxJsonDeserializerMembers" value="150000" />
</appSettings>
I'm trying to download a file that was generated from the database base64 String field. I see that file is created successfully but download fails...
This is my Spring MVC controller method:
#RequestMapping(value = "/download", method = RequestMethod.POST, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Response download(#RequestBody DocumentCaseFile documentCaseFile) throws ServiceLogicException {
return documentCaseFileService.prepareFile(documentCaseFile);
}
Here is the service method:
#Override
public Response prepareFile(DocumentCaseFile documentCaseFile) throws ServiceLogicException {
final String contents = documentCaseFile.getContent();
final String pathAndFileName = "files/" + documentCaseFile.getFilename();
File file = new File(pathAndFileName);
byte[] decodedImg = Base64.getDecoder().decode(contents.getBytes(StandardCharsets.UTF_8));
Path destinationFile = Paths.get(file.getAbsolutePath());
try {
Files.write(destinationFile, decodedImg);
file = destinationFile.getFileName().toFile();
} catch (IOException e) {
e.printStackTrace();
file = null;
}
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM_VALUE)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
}
And here is the frontend part for the download function:
$scope.downloadFile = function(documentCaseFile) {
$http.post(webserviceUrl + documentCaseFileDownload, documentCaseFile, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/octet-stream'
}
}).then(function successCallback(response) {
console.log('file download response');
console.log(response);
}, function errorCallback(response) {
console.error('file download error');
console.log(response);
});
};
Any help greatly appreciated!
Generally speaking, when you have response.getOutputStream(), you can write anything there. You can pass this output stream as a place to put generated PDF to your generator. Also, if you know what file type you are sending, you can set
response.setContentType("application/pdf");
and you are use into you angular code, you need to change it with fie type
headers: {
'Content-Type': 'application/json',
'Accept': 'application/octet-stream'
}
Turns out produces = MediaType.APPLICATION_OCTET_STREAM_VALUE was causing the problem in the controller, I had to remove it to make the error go away:
#RequestMapping(value = "/download", method = RequestMethod.POST)
everyone, have a trouble with sending files
I have angularjs client:
var fd = new FormData();
var myEl = angular.element( document.querySelector( '#someId' ) );
fd.append('file', myEl[0].files[0]);
fd.append('test', 'value');
var vv = $resource('api/:domen/:url', { url: "", domen: 'Options' }, {
'saveF': {
headers: {
'Authorization': 'Bearer ' + currentUser.getProfile().token,
'Content-Type': false
},
method: 'POST'
}
});
vv.saveF({ url: "UploadData", domen: 'Info' }, fd, function (el) {
console.log(el);
});
The client code send fields, I can check it via Fiddler, the file is in body
and backend code on ASP.NET Web Api:
public async Task<IHttpActionResult> UploadData()
{
// var a = HttpContext.Current.Request;
// var f = a.Files.Get(0);
if (!Request.Content.IsMimeMultipartContent())
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var file in provider.Contents)
{
var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
var buffer = await file.ReadAsByteArrayAsync();
and so on
The request always fails, because of "Request.Content.IsMimeMultipartContent()" or var f = a.Files.Get(0);
and I cannot get the file, server never see a content in request, but can see content-length
Already try to white content type 'multipart/form-data' but id didn`t help
Please, if somebody knows how to fix it - answer
See back-end implementation of Web API 2: https://www.asp.net/web-api/overview/advanced/sending-html-form-data-part-2
Also, you can use ng-file-upload for AngularJS
And example: https://github.com/stewartm83/angular-fileupload-sample
If you upload unknown MIME type and host your application on IIS,
it would be good add MIME type to IIS.
I want to upload javascript fileor basically transmit a javascript file to post function, on client side I've used angularjs $http service to send data to client as shown below:
$http({
method: "POST",
url: "/api/fileupload",
data: JSON.stringify(scope.c.model),//scope.c.model is javascript File
contentType: "application/json"
}).then(successResponse => {
this.scope["text"] = "Succes...";
}, errorResponse=> {
this.scope["text"] = "Error...";
});
and here is web-api controller
public void Post(HttpPostedFile file)
{
//do stuff...
}
file is null but scope.c.model is filled with correct data. if I change the Type of data is transmitted to an array (for example), everything is fine..It seems that the post method does not recognize the file.
seocnd below way also does not work, file.count is zero.
public void Post()//HttpPostedFile file)
{
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
//do stuff...
}
}
Here is a solution for the problem..with code below I am totally able to save any file locally or on server.
client side
scope.c.model is the type of Javascript FILE API. behind the scene is the model which is like this ng-model = model , c is controller and becasue this code is in link function of my directive I can access the model trough scope.c.model . model here could be any name.
as I want to read the File I should use FileReader.
scope.$watch('c.model', () => {
if (scope.c.model != null) {
var reader = new FileReader();
reader.onload = () => {
var base64 = reader.result.split("base64,")[1];
var file =
{
content: base64,
name: scope.c.model.name,
type: scope.c.model.type,
size: scope.c.model.size
};
var t = file.content;
$http({
method: "POST",
url: "/api/fileupload",//web-api contorller
data: file,// scope.c.model is javascript File
contentType: "application/octet-stream"
}).then(successResponse => {
this.scope["text"] = "Succes...";
}, errorResponse=> {
this.scope["text"] = "Error...";
});
};
reader.readAsDataURL(scope.c.model);
}
});
server side
public class File
{
public string Content;
public string Name;
public string Type;
public string Size;
}
public class FileUploadController : ApiController
{
public void Post(File file)
{
var bytes = Convert.FromBase64String(file.Content);
using (var imageFile = new FileStream(#"C:\fileupload\"+file.Name + ".jpg", FileMode.Create))
{
imageFile.Write(bytes, 0, bytes.Length);
imageFile.Flush();
}
}
}
I have the following angularjs code sending http post to a webmethod, but I get the following error with no more info. Can someone help?
If I do not send any data to webmethod and only get data from it, it works just fine !
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
angular.js:11442 POST http://localhost:54461/GetData.aspx/getData 500 (Internal Server Error)
Javascript:
var request = "{'name':'" + "Nariman" + "'age':'" + 12 + "'}";
$scope.retData = {};
var config = {
headers: {
'Content-Type': '"application/json; charset=utf-8";',
'dataType': '"json"'
}
}
$scope.retData.getResult = function (item, event) {
$http.post('GetData.aspx/getData', request, config)
.success(function (data, status, headers, config) {
$scope.retData.result = data.d;
})
.error(function (data, status, headers, config) {
$scope.status = status;
});
}
ASPX webmethod (C#):
public static string getData(string name, int age)
{
string.Format("Name: {0}{2}Age: {1}", name, age, Environment.NewLine);
}
EDIT --------------------------------------
If I do not send any json data to the webmethod, it works just fine. for example the below code works and if I put break point inside the webmethod, it shows that it goes there. but if I send json data, it does not go inside webmethod:
Javaacript (not sending any json data):
var config = {
headers: {
'Content-Type': '"application/json; charset=utf-8";',
'dataType': '"json"'
}
}
$scope.retData.getResult = function(item, event) {
$http.post('GetData.aspx/getData', data, config)
.success(function(data, status, headers, config) {
$scope.retData.result = data.d;
})
.error(function(data, status, headers, config) {
$scope.status = status;
});
}
ASPX (When no input param)
public static string getData()
{
// just having a breakpoint shows it comes inside the
// webmethod when no data is passed.
}
your issue seems to be as pointed by Emmanual Durai in first comment of your question: var request = "{'name':'" + "Nariman" + "'age':'" + 12 + "'}"; is not a valid json object.
request will give you {'name':'Nariman'age':'12'} as String which won't parse to JSON (there are issues with format).
You should try something like below to get a valid string
var request = {
name: "Nariman",
age: 12
}
var requestString = JSON.stringify(request)
also please have a look here How to pass json POST data to Web API method as object. your issue is not typically specific to angularjs $http but in general to XHR request.
Simply change:
var request = "{'name':'" + "Nariman" + "'age':'" + 12 + "'}";
To:
var request = { name: "Nariman", age: 12 };
You don't have to use JSON.stringify()
var request = { name: "Nariman", age: 12 };
var config = {
headers: {
"Content-Type": "application/json; charset=utf-8"
}
}
$http.post('GetData.aspx/getData', request, config)
.success(function(data, status, headers, config) {
$scope.retData.result = data.d;
})
.error(function(data, status, headers, config) {
$scope.status = status;
});