Razor MVC Controller Download file - c#

I have a controller like the code below and I would like to know how to call this using Razor
because #Url.Action("GetFileFromDisk") does not work as expected it just crashes. If it is possible could you point out my mistake here? Or maybe suggest a better way to force on click to download the file
public FilePathResult GetFileFromDisk()
{
string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/";
string fileName = "test.txt";
return File(path + fileName, "text/plain", "test.txt");
}
Thanks in advance.
Update
the Error message I get is
The webpage at http://mypage/Support/GetFileFromDisk might be temporarily down or it may have moved permanently to a new web address.
Error code: ERR_INVALID_RESPONSE`

To force a file download, you should probably use octet-stream. It's up to the client (browser) to determine whether to download or display content, but octet-stream is normally downloaded, no matter what. You should also use Path.Combine instead of manually concatenating the filename with the path.
public FilePathResult GetFileFromDisk()
{
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "uploads/");
string fileName = "test.txt";
return File(Path.Combine(path,fileName), "application/octet-stream", "test.txt");
}
edit, now that you've given the actual error:
This "might be temporarily down" message means no route could be found in your application that matches the given URL. There's probably something wrong with your URL.
Tips:
Check if you can reach actions that are sibling to "GetFileFromDisk" using the same URL pattern.
Review your routes.
Install Glimpse so you can debug your routes.

i think you should be using FileResult if you return File insted of FilePathResult
or use the FilePathResult as return
public FilePathResult GetFileFromDisk()
{
string path = AppDomain.CurrentDomain.BaseDirectory + "uploads/";
string fileName = "test.txt";
return new FilePathResult(Path.Combine(path, fileName), System.Net.Mime.MediaTypeNames.Application.Octet);
}

Related

Download a file with ServiceStack HttpResult: how to specify a file name for downloaded content?

I am using ServiceStack for a simple web application. The main purpose is to let a user download a file. I am using an HttpResult as follows:
public class FileDownloadService : Service
{
public object Any()
{
string fileFullPath = "...";
string mimeType = "application/pdf";
FileInfo fi = new FileInfo(fileFullPath);
byte[] reportBytes = File.ReadAllBytes(fi.FullName);
result = new HttpResult(reportBytes, mimeType);
return result;
}
}
This opens a dialog in the user's browser and the user can specify where to save the file. A default name is specified, which is the name of the restPath of ServiceStack.
My question is: is it possible to specify a custom file name for when the user chooses to save (changing the default one)? I tried to work with HttpResult properties, but no luck.
Thanks in advance!
You should set the 'Content-Disposition' header on the HTTP result. That allows to set the filename:
public object Any()
{
string fileFullPath = "...";
string mimeType = "application/pdf";
FileInfo fi = new FileInfo(fileFullPath);
byte[] reportBytes = File.ReadAllBytes(fi.FullName);
result = new HttpResult(reportBytes, mimeType);
result.Headers.Add("Content-Disposition", "attachment;filename=YOUR_NAME_HERE.pdf;");
return result;
}
I have found the solution. I was deceived by the readonly properties of the HttpResult.
In order to change the default file name, I discovered that I have to add the following line, that treats the content-disposition:
result.Headers[HttpHeaders.ContentDisposition] = "attachment; filename=\"UserSurname_UserName.pdf\"";
Thank you all for your time!
If I understood your question correctly, what you want is the user wants to rename the file. This is nothing to do with the server. The user has to do some changes in the brwoser he is uses.
e.g Firefox - Tools > Options > General
Then check the "Always ask me where to save files"
Chrome - Settings > Downloads
Then check the "Ask where to save each file before "
Then it will open file browser where to save, you may change your file name what ever your wanted

How to return a file in ASP MVC?

I am trying to return a file (.jpg) that is stored inside the /images folder of my ASP MVC application.
For some reason, the file downloaded is broken/corrupted and none of the photo viewers are recognising the file. I'm certain that the correct file is reachable as the file size is exactly the same and I have specified the contentType in the File() function.
Please can someone help me out? Thanks.
public ActionResult order(int? id)
{
// Logic to get the file path and file name from database
// var ImageName = "file"
// var filepath = will be something like ~/images/file.jpg
byte[] filedata = System.IO.File.ReadAllBytes(filepath);
string contentType = MimeMapping.GetMimeMapping(filepath);
return File(filepath, contentType, ImageName+".jpg");
}
I think you have a file path problem since the root path in aspnet applications are not the same as the physical path
try adding Server.MapPath
System.IO.File.ReadAllBytes(Server.MapPath(#"~/images/file.jpg"));

SSH.NET library encode the file name

I must download a file using SSH.NET library. After I download a file I must delete the remote file.
Everything works but the file name is encoded. I mean that for example, if I have a file named New file, I download/upload a file named New%20file. Now, if I download/upload the new file I obtain New%25%20file and again New%252520file... and so on...
This is very problematic. How can I avoid to change the file name after I download it?
Here the code I am using to download:
string fileName = base.Uri.GetFileName();
string fullPath = Path.Combine(pathFolder, fileName);
using (SftpClient client = new SftpClient(
new PasswordConnectionInfo(
base.Uri.Host, SftpFlowGateway.CONST_PORT_NUMBER,
base.Credential.UserName,
base.Credential.Password))
)
{
client.Connect();
using (FileStream fileStreamToDownload = new FileStream(fullPath, FileMode.Create))
{
client.DownloadFile(base.Uri.LocalPath, fileStreamToDownload);
}
client.Disconnect();
}
EDIT:
base.Uri is just defined as follow:
private Uri _uri;
public Uri Uri
{
get { return _uri; }
protected set { _uri = value; }
}
And the GetFileName method is:
public static string GetFileName(this Uri path)
{
return path.Segments.Last();
}
When I debug, I can see that the properties of the class Uri have the correct value... It is not encoded
Thank you
You are passing a stream you have created yourself (new FileStream) to the SSH.NET. The library does not even know it's a file it is writing to, nor its name. So it's not the library that URL-encodes the file name. It has to be URL-encoded in the fullPath variable already.
It's the Uri.AbsolutePath and Uri.Segments that return URL-encoded path. That's how the System.Uri class works. I assume you use the constructor overload Uri(string uriString).
Use the static method Uri.UnescapeDataString to reverse encoding done by the Uri constructor.
Note the obsoleted constructor overload Uri(string uriString, bool dontEscape).
It looks like the SSH.Net library simply URL encodes the file names.
I suppose you could rename the file after you've downloaded it using the System.Web.UrlDecode method?
Or UrlEncode the filename when you upload.
Unfortunately, I haven't used the library myself but you could help further by letting us know if the name change occurs on download or upload or both.
EDIT:
As martin mentioned, its not the library doing any encoding.
I've just tried it myself.
string fileName = "file with spaces.txt";
using (Stream outputFile = File.OpenWrite(localDir + "\\" + fileName))
{
sftpClient.DownloadFile(fileName, outputFile);
}
The created file is also named "file with spaces.txt" though that would've been the case anyway since it was created via the stream.

How to protect a controller from accessing parent and root directories from user input

I have an ASP.Net MVC controller action that is designed to give access to specific files in select directories and sub-directories in my App_Data folder.
Will someone tell me how to lock this down so that users cannot access root or parent directories and only the files in the directory and sub-directories?
Here's the insecure version of the controller action:
public string GetFile(string fileName)
{
string dataDir = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
string specialFiles = "SpecialFiles";
string finalPath = Path.Combine(dataDir, specialFiles, fileName);
string text = System.IO.File.ReadAllText(finalPath);
return text;
}
The naive solution would be to check fileName for string combinations like ..\, and then throw an exception or something. And while I can implement this solution, I would prefer to follow a best practice if one exists.
Before combining the strings into a finalPath, extract the FileName from fileName as below:
fileName = System.IO.Path.GetFileName(fileName)

Is there a .NET Framework method for converting file URIs to paths with drive letters?

I was looking for something like Server.MapPath in the ASP.NET realm to convert the output of Assembly.GetExecutingAssembly().CodeBase into a file path with drive letter.
The following code works for the test cases I've tried:
private static string ConvertUriToPath(string fileName)
{
fileName = fileName.Replace("file:///", "");
fileName = fileName.Replace("/", "\\");
return fileName;
}
It seems like there should be something in the .NET Framework that would be much better--I just haven't been able to find it.
Try looking at the Uri.LocalPath property.
private static string ConvertUriToPath(string fileName)
{
Uri uri = new Uri(fileName);
return uri.LocalPath;
// Some people have indicated that uri.LocalPath doesn't
// always return the corret path. If that's the case, use
// the following line:
// return uri.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped);
}
I looked for an answer a lot, and the most popular answer is using Uri.LocalPath. But System.Uri fails to give correct LocalPath if the Path contains “#”. Details are here.
My solution is:
private static string ConvertUriToPath(string fileName)
{
Uri uri = new Uri(fileName);
return uri.LocalPath + Uri.UnescapeDataString(uri.Fragment).Replace('/', '\\');
}
Can you just use Assembly.Location?
Location can be different to CodeBase.
E.g. for files in ASP.NET it likely to be resolved under c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET.
See "Assembly.CodeBase vs. Assembly.Location"
http://blogs.msdn.com/suzcook/archive/2003/06/26/57198.aspx

Categories

Resources