Blazor Server-Side download issues in IIS - c#

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.

Related

Download files from server asp.net core 404 response

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

Copying a file from one location into a folder in Solutions Explorer using asp.net

I am working on an asp.net project using c# and I need to copy a file from an arbitrary location which is determined by the file upload dialog box.
I need to make an exact copy of the file in a folder that is located in the Solutions Explorer. Below is the code I am using.
string filename = txt_lesson_title.text;
string sourcepath = _Uploadedfile.PostedFile.FileName.ToString();
string targetPath = HttpContext.Current.Server.MapPath("/destFolder/");
File.Copy(sourcePath, targetPath + fileName);
The above code runs without reporting any errors but I cannot see the copied files in the destination folder. Any help will be deeply appreciated.
Thanks
You don't need to copy the file, you need to save a copy of it.
You can do this
if the file is coming to your controller, you controller should have arguments like HttpPostedFileBase or HttpPostedFileBase[] depending on if you are saving one or more
if you are saving one,
public ActionResult Step(FormCollection collection, HttpPostedFileBase file) {
//HttpPostedFileBase file; //this comes from you controller argument
var directory = "~/Uploads/";
//this if statement can be optional
if(!Directory.Exists(System.Web.HttpContext.Current.Server.MapPath(directory)))
{
Directory.CreateDirectory(System.Web.HttpContext.Current.Server.MapPath(directory));
var virtualPath = directory + "/" + <your file name here>;
var filePath = System.Web.HttpContext.Current.Server.MapPath(virtualPath);
//if the file exists already, delete and replace it with the new one
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}
file.SaveAs(filePath);
}
else {
//do as above without the create directory
}
}

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

Categories