HttpPostedFile.SaveAs access denied - c#

I'm trying to save a file that I upload from my page but I'm getting an access denied error:
public void SaveFile(Item item, HttpPostedFileBase file)
{
var dir = string.Format(#"{0}\NSN\{1}", ConfigurationManager.AppSettings["ContentLocation"].ToString(), item.Id.ToString());
if (!System.IO.Directory.Exists(dir))
System.IO.Directory.CreateDirectory(dir);
Array.ForEach(Directory.GetFiles(dir), File.Delete);
file.SaveAs(dir);
}
I'm running this site from the local host from visual studio so no app pool is involved. I've given the Network Service (and Everyone as a test) full control of the folder and it's subfolders. Strange thing is it creates the folder if it needs to and also deletes any files in an existing folder. Only when I call the SaveAs function do I get the error.

You call file.SaveAs with path to directory instead of path to file

Here, give this a try:
string saveAsPath = Path.Combine(dir, file);
file.SaveAs(saveAsPath);
Replace file.SaveAs(dir) with the above.

Related

Download files with absolute path outside of wwwroot with Razor Page

We are building a Razor Page WebApp that we need our users to be able to download files stored on our server.
File path looks like this
//server_name/Databases/PDF_Files/2022-01-01-Invoice.pdf
All the files are on our server. When I put the path in the browser, I am able to view it in the browser.
With the absolute path available, what would be the best way to implement this?
A simple code snippet would be much appreciated.
You can use File.ReadAllBytes to get a byte array, and then return that as a FileResult:
public async Task<FileResult> OnGetFile(string filename)
{
var path = #"\\server_name\Databases\PDF_Files";
var file = Path.Combine(path, filename);
return File(await File.ReadAllBytesAsync(file), "application/pdf", filename);
}
The URL for the named handler method above would need to include a query string that has the handler name ("file") and the file name e.g.:
?handler=file&filename=2022-01-01-Invoice.pdf
Obviously, you will need to validate the file name to ensure that it exists and doesn't attempt to access other directories on the server, and you will need to ensure that the account that the web app process runs under has sufficient privileges to access the network resource.

Create file during mstest - System.UnauthorizedAccessException

I have a UWP C# app, with a unit testing project. In these unit test, I want to be able to write to a text file in order to make something like snapshots in Jest.
Directory.GetCurrentDirectory() returns C:\path\to\project\bin\x64\Debug\AppX, so I made a folder in the project directory and am navigating to it, then attempting to create a file there.
[TestMethod]
public void Test()
{
var folder = Path.Combine(Directory.GetCurrentDirectory(), "../../../../Snapshots");
string data = "example data";
string filename = Path.Combine(folder, "Test.snap");
File.WriteAllText(filename, json);
}
However, this test produces a System.UnauthorizedAccessException. I went into the folder in windows and gave Everyone read/write permissions, but that didn't make any difference.
I don't want to have to run Visual Studio as an administrator. Is this possible?
I use Path.GetTempPath() to create temporary directories and files in unit tests that require physical disk access. The unit tests can run from an unknown context/location, so I found using the temp directory as a guaranteed way to create disposable files.
[TestMethod]
public void Test()
{
var folder = Path.Combine(Path.GetTempPath(), "Snapshots");
string data = "example data";
string filename = Path.Combine(folder, "Test.snap");
File.WriteAllText(filename, json);
}
Please have a look at Rob's blog here:
https://blogs.msdn.microsoft.com/wsdevsol/2012/12/04/skip-the-path-stick-to-the-storagefile/
Here is the answer from Rob:
Windows Store apps run sandboxed and have very limited access to the
file system. For the most part, they can directly access only their
install folder and their application data folder. They do not have
permission to access the file system elsewhere (see File access and
permissions for more details).
Access to other locations is available only through a broker process.
This broker process runs with the user’s full privileges, and it can
use these privileges on the app’s behalf for locations the app has
requested via capabilities, locations requested by the user via file
pickers, etc. The StorageItem encapsulates this brokerage procedure so
the app doesn’t need to deal with it directly."
In a UWP app we do not recommend path anymore. There are permission problems so broker is required when access some paths. I'm not familar with Unit Test. But if you are still using UWP function you should consider using StorageFile related API instead.
How about checking if you gave permissions to the right folder?
var folder = Path.Combine(Directory.GetCurrentDirectory(), "../../../../Snapshots");
string data = "example data";
// this variable will contain the actual folder; add a watch
// or bookmark it to check it
var actualPath = Path.GetFullPath(folder);
string filename = Path.Combine(folder, "Test.snap");
File.WriteAllText(filename, data);
Just in case, add the line below too (before File.WriteAllText); perhaps your file already exists as, I don't know, read-only:
File.SetAttributes(filename, FileAttributes.Temporary);

UWP - Get path to user download folder

I have been looking for a little while now and am not finding much help via MSDN resources and others.
My predicament is simple: my app needs a base directory to the Downloads folder. I am aware of the DownloadsFolder class however that is not suiting my needs currently.
How do I get the current user's Download folder path in a Windows Universal App?
Use Windows.Storage.UserDataPaths to get the path of user's download folder.
string downloadsPath = UserDataPaths.GetDefault().Downloads;
This method is introduced in build 16232, so clients with RS3(1709) or later will be able to run it.
You shouldn't obtain downloads folder path using LocalFolder, which might result in wrong folder when the user changed the default location for it.
System.Environment.ExpandEnvironmentVariables("%userprofile%/downloads/")
Is that what you need?
string localfolder = ApplicationData.Current.LocalFolder.Path;
var array = localfolder.Split('\\');
var username = array[2];
string downloads = #"C:\Users\" + username + #"\Downloads";
This will result
C:\Users\username\Downloads
The DownloadsFolder for an app now defaults to a folder withing the user's Downloads directory named after the app name (in actual fact the app name folder is simply a link to a folder named after the Package Family Name)
To get the folder name, I used the following hack (vb) to first create a dummy file in the UWP app's DownloadsFolder then using .NET code to get the directory name, and finally deleting the dummy file.
Dim o As StorageFile = Await DownloadsFolder.CreateFileAsync("dummy.txt", CreationCollisionOption.GenerateUniqueName)
Dim dirName Ss String = Path.GetDirectoryName(o.Path)
Await o.DeleteAsync(StorageDeleteOption.PermanentDelete)

winform not creating file in read-only folders

I am trying to create a file in a directory using the code below
if (File.Exists(myDir))
{
return myDir;
}
System.IO.Directory.CreateDirectory(myDir);
File.SetAttributes(myDir, FileAttributes.Normal);
//string name = myDir + "/" + filename;
File.Create(myDir).Dispose();
return myDir;
When I run it on a Mac it works since the directory have write permission, however, I have noticed that on windows 10 all folders are automatically read only, so the access to write in the path is denied.
What would be the solution for me to write a file in this path?
Btw if I use this path which is my MacBook directory (read&write permission) : "//Mac/Home/Movies" it will just work as it should, it will create the subdirectories and the file in it, however if I choose the windows one which is "C:\CSVtest" it would just show "access denied as it is read-only, i can't find a way to bypass this read-only thing, i tried on other windows 10 machines as well and all folders on windows 10 are read-only so it is the same case
//path = #"C:\Temp\Bar\Foo\Test.txt";
Directory.CreateDirectory(Path.GetDirectoryName(path));
Directory.CreateDirectory will create the directories recursively and if the directory already exist it will return without an error.
You then would create the file
File.Create(path).Dispose();

WinSCP .NET assembly - How to set folder permissions after creating directory?

I'm building a web site and I want that when a user registers, to create a directory on the SFTP server and put in that directory a new file
I'm using WinSCP .NET assembly, and writing C#.
I noticed that you are able to set permissions only in the method: Session.PutFiles
and not in the method: Session.CreateDirectory
Snd so after I create the directory and put the file in it, I cannot access the file because I don't have permissions - I'm accessing the file with the full URL
How can I access the file?
PS.
When I change the directory permissions manually, I am able to access the file.
Note that this answers your question how to set permissions when creating a directory. But a root cause of your problem is that a default permissions your server sets are wrong. The server should not use default permissions such that you cannot access a directory/file you have just created yourself!
It's currently not possible to directly set permissions, when a creating directory or modify them afterwards with WinSCP .NET assembly.
See https://winscp.net/tracker/1075
You can hack it though as follows:
Create a local empty temporary directory
Upload it using the Session.PutFiles, setting permissions you need in TransferOptions.FilePermissions
string directoryName = "mydir";
string directoryPath = "/home/username/" + directoryName;
string tempPath = Path.Combine(Path.GetTempPath(), directoryName);
Directory.CreateDirectory(tempPath);
try
{
TransferOptions options = new TransferOptions();
options.FilePermissions = new FilePermissions { Octal = "755" };
session.PutFiles(tempPath, directoryPath, false, options).Check();
}
finally
{
Directory.Delete(tempPath);
}
You can even do without creating an empty temporary directory. Just pick any directory, e.g. directory of your account profile folder, and use a file mask to include only this one directory, preventing files in the directory and sub-directories from being uploaded. Also use an explicit name of desired remote directory in the target path to "rename" the uploaded directory to the name you want.

Categories