Download files from server asp.net core 404 response - c#

I'm trying to download a set of files from the server as zip file. Locally I can do it with no problem, but now that I deployed the app in a windows server 2019 (IIS), when I try to download the files I get the 404 - File or directory not found.
To download the set of files as zip I'm using the SharpZipLib library. The file paths are all correct and I can access them thru the file system in the server.
First I'm uploading the files in a folder inside the wwwroot where I published the app. The structure of my folders inside wwwroot is:
wwwroot
docs
contracts
My method to download the files as zip:
public async Task<FileResult> DownloadZipAsync() {
List<string> filePaths = //linq query to get the file paths.
//Example of file path: C:\inetpub\wwwroot\SRO\wwwroot\docs\contracts\testing.pdf
var name = "contracts";
var webRoot = _hostingEnvironment.WebRootPath;
var fileName = name + ".zip";
var tempOutput = webRoot + "\\docs\\contracts\\" + fileName;
using (ZipOutputStream zipOutputStream = new ZipOutputStream(System.IO.File.Create(tempOutput))) {
zipOutputStream.SetLevel(9);
byte[] buffer = new byte[4096];
for (int index = 0; index < filePaths.Count; index++) {
ZipEntry entry = new ZipEntry(name + "\\" + Path.GetFileName(filePaths[index]));
entry.DateTime = DateTime.Now;
entry.IsUnicodeText = true;
zipOutputStream.PutNextEntry(entry);
using (FileStream fileStream = System.IO.File.OpenRead(filePaths[index])) {
int sourceBytes;
do {
sourceBytes = fileStream.Read(buffer, 0, buffer.Length);
zipOutputStream.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
zipOutputStream.Finish();
zipOutputStream.Flush();
zipOutputStream.Close();
}
byte[] finalReuslt = System.IO.File.ReadAllBytes(tempOutput);
if (System.IO.File.Exists(tempOutput)) {
System.IO.File.Delete(tempOutput);
}
if (finalReuslt == null && !finalReuslt.Any()) {
throw new Exception(String.Format("Nothing found"));
}
return File(finalReuslt, "application/zip", fileName);
}
Things I've tried to fix the issue:
In the server I gave my deployment folder permissions (full control) for IIS_IUSRS user
For my deployment folder I created the user DefaultAppPool and gave full permissions as well.
In IIS -> Application Pools -> myappPoolforNetCore -> Advanced Settings -> Identity - changed between ApplicationPoolIdentity and LocalSystem.
Maybe my download method is not working properly when deployed. I suspect the issue can be in the using statement, specifically in the System.IO.File.Create() method.
I 'deployed' the app on my local development machine thru Development-time IIS support in Visual Studio for ASP.NET Core. Link
I did the same three steps I mentioned above, and in this case it works, with one difference being that the paths of files are different (since my app is 'deployed' locally) and they point to my C:/.... directory.
Any help would be appreciated because I'm stuck in this problem for quite a while.
Thanks

Did you check the MIME Types ?
Try to add
.zip - application/zip
or
.zip - application/x-zip

Related

Blazor Server-Side download issues in IIS

I am trying to download a List of files (user has the option to select multiple). My current code below works fine in localhost (writing and opening the downloads folder). However, when I upload to IIS it gives an error saying that the system configuration is not found.
Please see below:
if (SelectDownloadFiles.Count > 0)
{
//Downloads folder (User profile)
string DownloadFolder = Environment.ExpandEnvironmentVariables("%userprofile%/downloads/");
//This is a little hack to get the literal path for the Downloads folder without too much of back-and-forth and ellaboration
string FolderForward = DownloadFolder.Replace(#"/", #"\");
string Folder = FolderForward.Replace(#"\\", #"\");
foreach (var items in SelectDownloadFiles)
{
//Get Date
var GetDate = items.Substring(0, 6);
//Add 2 days to be consistent to what is displayed to the user (when files were generated)
var FileDate = DateTime.ParseExact(GetDate, "yyMMdd", CultureInfo.InvariantCulture).AddDays(2);
//Get Files
string Pathname = #"D:\";
string FullPathName = Path.Combine(Pathname, items);
byte[] FileBytes = System.IO.File.ReadAllBytes(FullPathName);
MemoryStream Ms = new MemoryStream(FileBytes);
//Rename the file to become user friendly
string DownloadPath = Path.Combine(DownloadFolder, "My Files " + FileDate.ToString("MM-dd-yyyy") + ".zip");
//Write file(s) to folder
FileStream File = new FileStream(DownloadPath, FileMode.Create, FileAccess.Write);
Ms.WriteTo(File);
File.Close();
Ms.Close();
}
//Open Downloads Folder with files
Process.Start("explorer.exe", Folder);
navigationManager.NavigateTo("/default", true);
//DisplayMessage.Show("File(s) successfully downloaded. Please check your “Downloads” folder to access your file(s).", "OK", "check");
}
else
{
Toaster.Add("Please select at least one file to download.", MatToastType.Warning);
}
I've also tried to use the solution below to no avail:
private readonly IWebHostEnvironment _webHostEnvironment;
public YourController (IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment= webHostEnvironment;
}
If I use the "folderoptionpath" and choose "MyDocuments" for instance, the files download to the root path of the files inside IIS.
Is there anything else I need to be doing to get to this to work?
Thanks in advance!
Well, after spending some time researching this, I was finally able to get it going. I ended up using a Nuget Package called BlazorFileSaver and it works just fine. Here's the repo: https://github.com/IvanJosipovic/BlazorFileSaver/blob/master/src/BlazorFileSaver.Sample/Pages/Index.razor
I hope this can help someone else in the future.

Cannot see existing files on Android phone

Consider the following code:
string folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string file = Path.Combine(folder, "test.txt");
File.WriteAllText(file, "test");
string content = File.ReadAllText(file);
Running this on my phone I confirmed that the string content has the value "test", so the file has definitely been created and written to in internal storage.
Next I commented the WriteAllText-line and verified on a second run of the program that the file was still there because the value of content again was "test".
But when I look into the folder returned by GetFolderPath using the file manager of my phone, it is empty. There is no file test.txt.
So the question is, why can't I see the file?
Unless the phone is rooted and the file manager as root permissions you cannot see those files (usually under /data/data/package.name/files)
If you want to see them using your code, consider using this:
String path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
Log.d("Files", "Path: " + path);
File directory = new File(path);
File[] files = directory.listFiles();
Log.d("Files", "Size: "+ files.length);
for (int i = 0; i < files.length; i++)
{
Log.d("Files", "FileName:" + files[i].getName());
}
Your app should log them with no problem.
If the files are needed outside the app, consider using external storage.

Not opening IDE as Admin causes FileStream throw access to the path is denied exception

As the title says, if I open Visual Studio IDE as Admin, FileStream works just fine. But if I don't run as admin, it gives Access to the path 'C:\\ABCD.ddthp' is denied. But if I select a folder inside the C directory it works fine. For example if the path is 'C:\ABCFolder\ABCD.ddthp' it works fine. Here is my code. Is there any work around for this or should the IDE be opened as Admin.
try
{
if (File.Exists(path))
{
File.Delete(path);
}
//The following line causes an exception.
using (var stream = new FileStream(path,
FileMode.CreateNew, FileAccess.Write).Encrypt())
{
using (StreamWriter streamWriter = new StreamWriter(stream))
{
JsonTextWriter jsonWriter = new JsonTextWriter(streamWriter);
jsonWriter.Formatting = Formatting.Indented;
protocolJObject.WriteTo(jsonWriter);
}
}
return ReturnCodes.Success;
}
catch (UnauthorizedAccessException ex)
{
SystemDebugLogLogger.LogError(ex, "Protocol: WriteJson");
returnValue = ReturnCodes.FileAccessDenied;
}
The workaround would be to not write directly to the C: drive, or any other location that requires administrative access. Depending on the purpose of the file, there are usually three candidate locations:
The temp folder, for files that you don't need to save
The AppData folder, for files that your application will need and which may be different for different users
The install location for your application
You can get these folders like:
private static void Main()
{
// Create your own file name
var fileName = "MyAppData.txt";
// Get temp path
var tempPath = Path.GetTempPath();
// Get AppData path and add a directory for your .exe
// To use Assembly.GetExecutingAssembly, you need to add: using System.Reflection
var appDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var exeName = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
var appDataForThisExe = Path.Combine(appDataFolder, exeName);
Directory.CreateDirectory(appDataForThisExe);
// Get the path where this .exe lives
var exePath = Path.GetDirectoryName(
new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
// Now you can join your file name with one of the above paths
// to construct the full path to the file you want to write
var tempFile = Path.Combine(tempPath, fileName);
var appDatFile = Path.Combine(appDataForThisExe, fileName);
var exePathFile = Path.Combine(exePath, fileName);
Console.WriteLine($"Temp file path:\n {tempFile}\n");
Console.WriteLine($"AppData file path:\n {appDatFile}\n");
Console.WriteLine($"Exe location file path:\n {exePathFile}");
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
Output
Your user account doesn't have permission to write to the C:\ drive of your computer but admin does.
You can give yourself permission by right clicking on the C:\ drive in windows explorer, select properties and then the security tab and give your account write access.
Alternatively, use a better location

Download File from DataTable

I'm trying to develop some kind of FTP program in school. The service they provided me to download files from their server only downloads one file at a time and if I try to download a folder it returns a blank file. How is it possible to create some kind of system to download the whole directory (even the files inside the directory of the selected directory)?
This is what I use to get the files:
foreach (ListViewItem cadaItem in listView2.SelectedItems)
{
string type = listView2.SelectedItems[0].SubItems[2].Text;
MessageBox.Show(type);
byte[] fileBytes = new byte[666666];
byte[] hash = new byte[666666];
if (type != "")
{
servDin.GetFileMD5Async("", "", Vars.pastaLocal + #"\" + cadaItem.Text, hash, fileBytes);
using (Stream file = File.OpenWrite(Vars.pastaLocal + #"\" + Convert.ToString(cadaItem.Text)))
{
file.Write(fileBytes, 0, fileBytes.Length);
}
}
I wanted to use a datatable to get the filenames and download the files from there. is it possible?
Thank You

Mime-type .tif/pdf files are corrupted and will not open .NET V2.0

Web systems (exact same site) has been migrated to new servers. The mime-type tif file attachments worked on the previous servers in production and no code has been changed, but since the migration we cannot open specifically, .tif file. PDF files spin to a blank page in the browser.
The code calls a webservice(which works fine) to get a Cache Document from a JDE environment
object[] file = docA.CacheDocument("/" + path, filename, doctype, xxx.Global.JDEEnvironment);
fileSize = (int)file[0];
mimeType = (string)file[1];
There is no issue returning the mime-type, which is a "image/tiff". Settings have been set on the server level to accept both .tif and .tiff in MIME-TYPE properties.
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.ContentType = mimeType;
string tempPath = "/" + path;
string tempFile = filename;
int i = 0;
while (i < fileSize)
{
int[] byteRangeAry = new int[2];
byteRangeAry[0] = i;
if ((i + _chunkSize) < fileSize)
{
byteRangeAry[1] = i + _chunkSize;
}
else
{
byteRangeAry[1] = fileSize;
}
var docdata = docA.GetByteRange(tempPath, tempFile, byteRangeAry);
HttpContext.Current.Response.BinaryWrite(docdata);
HttpContext.Current.Response.Flush();
//Move the index to the next chunk
i = byteRangeAry[1] + 1;
}
HttpContext.Current.Response.Flush();
this snipit is untouched code that worked in production and now errors out with an object reference error.
var docdata = docA.GetByteRange(tempPath, tempFile, byteRangeAry);
However when I add a .mime extention to the tempFile, it no longer errors out and gets the byteRange.
var docdata = docA.GetByteRange(tempPath, tempFile + ".mime", byteRangeAry);
The dialog box appears - downloads the file - but opens to a blank or an error saying the file appears to be damages, corrupted or is too large. I have tried opening in several other formats to no avail. This happens with the .tif file. The PDF just leaves a blank page in the brower without an option download dialog box.
This is the same code that worked in production and is a .NET V2 app. Any suggestions would be much appreciated.
This was resolved, it was a cacheing issue. We re-wrote the Get CacheDocument method that was corrupting the header. Now its a GetDocument method and we are now able to grab documents, and load them. The problem was the code, it is still strange that it worked in the previous production.

Categories