not a valid virtual path - when trying to return a file from a url - asp.net-mvc-3

We download a file from our CdN and then return a url to that downloaded file to the user. I'm trying to get this implemented so that when a user clicks the download buttton, it goes and test that url to that downloaded file then forces a save prompt based on that local url.
So for example if there is a button called download on the page for a specific .pdf, we ultimately have code in our controller going to the cdn and downloading the file, zipping it then returning a url such as: http://www.ourLocalAssetServer.com/assets/20120331002728.zip
I'm not sure if you you can use the File() method to return the resource to the user as to cause a save prompt when you have a url to the file, not a system directory virtual path.
So how can I get this working with the url? I need the download button to ultimately force a save prompt on their end given a url such as what is generated per this example above? Not I am using POST, not a GET, so not sure which I should use in this case either besides this not working overall to force a save prompt. It is hitting my GetFileDownloadUrl but ultimately errors saying it's not a virtual path.
Here's my code:
#foreach (CarFileContent fileContent in ModelCarFiles)
{
using (Html.BeginForm("GetFileDownloadUrl", "Car", FormMethod.Get, new { carId = Model.CarId, userId = Model.UserId, #fileCdnUrl = fileContent.CdnUrl }))
{
#Html.Hidden("userId", Model.UserId);
#Html.Hidden("carId", Model.CarId);
#Html.Hidden("fileCdnUrl", fileContent.CdnUrl);
<p><input type="submit" name="SubmitCommand" value="download" /> #fileContent.Name</p>
}
}
public ActionResult GetFileDownloadUrl(string fileCdnUrl, int carId, int userId)
{
string downloadUrl = string.Empty;
// take the passed Cdn Url and go and download that file to one of our other servers so the user can download that .zip file
downloadUrl = GetFileZipDownloadUrl(carId, userId, fileCdnUrl;
// now we have that url to the downloaded zip file e.g. http://www.ourLocalAssetServer.com/assets/20120331002728.zip
int i = downloadUrl.LastIndexOf("/");
string fileName = downloadUrl.Substring(i);
return File(downloadUrl, "application/zip", fileName);
}
error: not a valid virtual path

This won't work except the zip file is in your virtual path.
The File method you have used here File(string, string, string) expects a fileName which will be used to create a FilePathResult.
Another option would be to download it (using WebClient.DownloadData or DownloadFile methods) and passing either the byte array or the file path (depending on which you choose).
var webClient = new Webclient();
byte[] fileData = webClient.DownloadData(downloadUrl);
return File(fileData, "application/zip", fileName);
And the lines where you get the index of "/" just to get the filename is unnecessary as you could have used:
string fileName = System.IO.Path.GetFileName(downloadUrl);

Related

Downloads in Flutter web app fail on android Chrome

My flutter web app creates files (csv and pdf) that should be downloaded on user click. It works fine on PC Chrome but fails on Android Chrome. No downloaded file is shown and a file named ".com.google.Chrome.xxxxxx" is stored (where the suffix is random).
Here is my code:
import 'dart:html' as html;
void saveFile(String name, dynamic data, String type) {
final blob = html.Blob([data], type);
html.AnchorElement(href: html.Url.createObjectUrlFromBlob(blob))
..download = name
..click();
}
I pass either the result of pdf.save() or the csv String into the data parameter.
I also tried this and it works perfectly on the same android Chrome (but I can't set the file name in this case and the automatically generated file name looks awful):
import 'dart:html' as html;
void saveFile(String name, dynamic data, String type) {
final blob = html.Blob([data], type);
html.window.open(html.Url.createObjectUrlFromBlob(blob), '_blank');
}
Any suggestions how to fix this?

aws s3 delete object not working

I'm trying to upload/delete image to/from aws s3 bucket using spring boot.
public class AmazonClient {
private AmazonS3 s3client;
private void initializeAmazon() {
AWSCredentials credentials = new BasicAWSCredentials(this.accessKey, this.secretKey);
this.s3client = AmazonS3ClientBuilder.standard().withRegion(region).withCredentials(new AWSStaticCredentialsProvider(credentials)).build();
}
private void uploadFileTos3bucket(String fileName, File file) {
s3client.putObject(new PutObjectRequest(bucketName, fileName, file)
.withCannedAcl(CannedAccessControlList.PublicRead));
}
public void deleteFileFromS3Bucket(String fileUrl) {
String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
s3client.deleteObject(new DeleteObjectRequest(bucketName + "/", fileName));
}
}
The upload function works well, I can see the file has been uploaded to the s3 bucket, but the delete function seems malfunctioning, I get a successful message but the file is still in the bucket.
Thanks in advance if anyone could help me to figure out the problem.
From the javadoc of deleteObject (emphasis mine)
Deletes the specified object in the specified bucket. Once deleted, the object can only be restored if versioning was enabled when the object was deleted.
If attempting to delete an object that does not exist, Amazon S3 will return a success message instead of an error message.
So, most probably the path (fileName) you construct in deleteFileFromS3Bucket does not point to an S3 object.
EDIT
I'm updating my answer based on the comments:
The file name used has special characters (: in the provided example) which gets URL encoded (percent encoded). This encoded URL cannot be used to retrieve or delete the S3 object as the percent in the URL would get encoded again(% gets encoded to %25).
The encoded URL has to be decoded. One way is to use java.net.URLDecoder
URLDecoder.decode(encodedPath, "UTF-8")
public boolean deleteFileFromS3Bucket(String fileUrl) {
String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
try {
DeleteObjectsRequest delObjReq = new DeleteObjectsRequest(bucketName).withKeys(fileName);
s3client.deleteObjects(delObjReq);
return true;
} catch (SdkClientException s) {
return false;
}
}
For me, working here is an option.
Just found out that I added an additional slash in new DeleteObjectRequest.
The only thing that worked for me is deleting it through Cyberduck (I neither work for nor am promoting Cyberduck, I genuinely used it and it worked). Here are the steps of what I did:
Download and install Cyberduck.
Click on Open Connection
Select Amazon S3 from the dropdown (default would be FTP)
Enter your access key ID and secret Access key (if you don't have one then you need to create one on your s3 bucket through IAM on AWS).
You will see a list your S3 buckets. Select the file or folder or bucket you want to delete, right click and delete. Even files with 0kb show up here and can be deleted.

Fineupload on.complete recover id, name and execute a PHP

I'm very interested getting the path and name of the file uploaded, and if the upload is a success, execute a php using the name and path of the uploaded file.
I just checked that on.complete could be useful, but if someone has an example would be just great.
.on('complete', function (event, id, filename, responseJSON) {
uploadedFileCounter++;
if (filesToUpload == uploadedFileCounter)
{
$(':input[type=button],:input[type=submit],:input[type=reset]').removeAttr('disabled');
//$("#overlay").fadeOut();
$("#modal-box").fadeOut();
$("#modal-overlay").fadeOut();
}
I found this example on another thread, but I don't have any idea how could I get the path and name on a php to store in a database and launch a new process with the uploded files.
So here is an example of how to do some of these tasks in plain ol' PHP. Would not recommend for production!
To get the filename in PHP:
function getName(){
// First we check if the user has provided an edited version of the filename.
// see: http://docs.fineuploader.com/branch/master/features/filename-edit.html
if (isset($_REQUEST['qqfilename']))
return $_REQUEST['qqfilename'];
// Otherwise we return whatever the browser/fine-uploader has named the file.
// see: http://docs.fineuploader.com/endpoint_handlers/traditional.html
if (isset($_FILES[$this->inputName]))
return $_FILES['qqfile']['name'];
}
To get the UUID in PHP:
// see: http://docs.fineuploader.com/endpoint_handlers/traditional.html
$uuid = $_REQUEST['qquuid'];
One method of creating a path on disk is to use the uuid in combination with the filename like so:
$path = join(DIRECTORY_SEPARATOR, array($uuid, get_name()));
At this point you can do whatever you want with the path, uuid, filename, or other data from fine-uploader (e.g., save the data in a database, ...)
If there is some reason fine-uploader needs to know the path, then you can return it in the response and use it in the onComplete handler:
.on('complete', function (event, id, filename, responseJSON) {
var path = responseJSON.path;
// do something ...
}

route doesn't work at production environment

I have created following route
routes.MapRoute("ThumbnailRoute",// Route name
"Image/{action}/{session}/{parentId}/{fileName}/{ctype}/{thumbNailSize}", // URL with parameters
new { controller = "Image", action = "GenerateThumbnail", session = "", parentId = "", fileName = "", ctype = "", thumbNailSize = 70 }, // Parameter defaults
new { controller = #"[^\.]*", action = #"[^\.]*" });
and my extension method returns a string like following which will be the src attribute of the img tag:
return string.Format("/{0}/{1}/{2}/{3}/{4}/{5}/{6}", controller, action, session, parentId, fileName, ctype, thumbNailSize);
when I right click on the pages and choose properties for both dev and prod environments the src av img tag is same (http://localhost/Image/GenerateThumbnail/de-DE/121/0beac6da-7c09-4faf-ad4b-48326f9d337e.jpg/jpeg/70) only different is the domain name (localhost, www.domain.com) but the images de not appear on prod. thanks for your help
If the URLs look fine on the production version - perhaps the issue isn't with the routing, but rather with the code in the action method.
Have you checked what response you get from the browser when hitting the production URL?
What response do you get when your browse to http://www.domain.com/Image/GenerateThumbnail/de-DE/121/0beac6da-7c09-4faf-ad4b-48326f9d337e.jpg/jpeg/70?
Never hardcode urls as you did. Always use url helpers. The thing is that when you deploy your application in IIS there's a virtual directory name. So the correct url is the following:
http://foo.com/MyAppName/Image/GenerateThumbnail/de-DE/121/0beac6da-7c09-4faf-ad4b-48326f9d337e.jpg/jpeg/70
instead of:
http://foo.com/Image/GenerateThumbnail/de-DE/121/0beac6da-7c09-4faf-ad4b-48326f9d337e.jpg/jpeg/70
Since you have hardcoded the url you get 404.
So use the RouteUrl method to generate it which will take into account this virtual directory if any. Don't use any string formatting to build urls:
public ActionResult Index()
{
string url = Url.RouteUrl("ThumbnailRoute", new
{
action = "GenerateThumbnail",
controller = "Image",
session = session,
parentId = parentId,
fileName = fileName,
ctype = ctype,
thumbNailSize = thumbNailSize
});
...
}

Returning an MVC FileContentResult to download .pdf file from

Hi I've search around for this quite a bit but I didn't find a situation that really resembled mine..hope I didn't miss a duplicate somewhere
The Goal: Return a file from a UNC share to the client as a download/open option.
Info: The share is located on a different server than the one hosting the web site. When a corresponding folder name on the menu is clicked, I am able to successfully read from the share (I return the files as a JSON result) and in Jquery I then append list items for each file found in the folder and make the list item ID's the filename. This works great.
When these appended list items are clicked on I pass their ID's (which are the filename, like "thefile.pdf") to the following controller which returns a FileContentResult.
files[0].ToString() below is similar to "\server\folder\"
public ActionResult OpenTheFile(string id)
{
List<string> files = new List<string>();
files.AddRange(Directory.GetFiles(LNFiles.ThePath, id, SearchOption.AllDirectories));
Response.AppendHeader("Content-Disposition", "attachment; filename=" + id + ";");
return File(files[0].ToString(), System.Net.Mime.MediaTypeNames.Application.Pdf, id);
}
And yes the obligatory "it works on my local machine". When deployed to the IIS 7.5 server and I click on the list item I get this YSOD error:
The handle is invalid. (Exception from
HRESULT: 0x80070006 (E_HANDLE))
I'm impersonating a user with rights to the file share...I'm at a loss, i was thinking something with encoding or screwed up rights? I've tried using a virtual dir instead but alas same issue.
In my case
changing this:
public ActionResult Download(int id)
{
var item = ItemRepo.GetItemById(id);
string path = Path.Combine(Server.MapPath("~/App_Data/Items"), item.Path);
return File(path, "application/octetstream", item.Path);
}
to this:
public ActionResult Download(int id)
{
var item = ItemRepo.GetItemById(id);
string path = Path.Combine(Server.MapPath("~/App_Data/Items"), item.Path);
return File(new FileStream(path, FileMode.Open), "application/octetstream", item.Path);
}
has worked. I am putting this here just in case anyone needs.
Check out this for a workaround
You may want to try a packet capture to see if you are receiving the same issue as documented here:
http://forums.asp.net/t/1473379.aspx/1
For your unc path - are you directly referencing \servername\share or are you using a network mapped drive letter?
God Bless you : ProgRockCode.
and since that involved an ActionResult, I wrote a custom ActionResult that used the "WriteFile" method.
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.WriteFile(FilePath, true);
context.HttpContext.Response.End();
}

Resources