Directory.Move fails while copying files 1 by 1 works - c#

I have an ASP.NET MVC application, hosted on IIS 8, windows server 2012 and I upload some files to a temporary directory. After doing some other work, all these files are moved to a concrete directory. My question is why doesn't Directory.Move work while FileInfo.CopyTo works.
Directory.Move fails with
"Access to the path 'serverPath...' is denied."
Code I'm using to move entire directory:
var pathFrom = Server.MapPath("~/Uploads/Objects/" + tempFolderName); //tempFolderName is a random generated GUID.
var pathTo = Server.MapPath("~/Uploads/Objects/" + ObjectId); //ObjectId is an integer
if (Directory.Exists(pathFrom))
{
Directory.Move(pathFrom, pathTo);
}
To create a temporary directory I'm simply calling: Directory.CreateDirectory(path) which works and creates the temporary directory, and files are saved inside it.
Method I use to copy files, one by one, which works:
public static void DirectoryCopy(string strSource, string Copy_dest)
{
DirectoryInfo dirInfo = new DirectoryInfo(strSource);
DirectoryInfo[] directories = dirInfo.GetDirectories();
FileInfo[] files = dirInfo.GetFiles();
foreach (DirectoryInfo tempdir in directories)
{
Console.WriteLine(strSource + "/" + tempdir);
Directory.CreateDirectory(Copy_dest + "/" + tempdir.Name);// creating the Directory
var ext = System.IO.Path.GetExtension(tempdir.Name);
if (System.IO.Path.HasExtension(ext))
{
foreach (FileInfo tempfile in files)
{
tempfile.CopyTo(Path.Combine(strSource + "/" + tempfile.Name, Copy_dest + "/" + tempfile.Name));
}
}
DirectoryCopy(strSource + "/" + tempdir.Name, Copy_dest + "/" + tempdir.Name);
}
FileInfo[] files1 = dirInfo.GetFiles();
foreach (FileInfo tempfile in files1)
{
tempfile.CopyTo(Path.Combine(Copy_dest, tempfile.Name));
}
}
What I tried to make Directory.Move work:
Checked to see if directory pathTo doesn't exist
Checked to see if IIS has required permissions: IISAppPool/DefaultAppPool has full access to the Uploads folder.
Tried to check with Process monitor if any other error comes up but it seems that this doesn't even get logged.
Closed every explorer.
Can anyone explain why Directory.Move doesn't work (with the access deny error) while moving the files one by one works?
Does Directory.Move require more privileges than just copying files 1 by 1?
Please be aware that the application is not under wwwroot... but on other drive.
Pages I already read:
Why am I still getting "Access to the path 'C:\...\...' is denied" even after granting IIS_IUSRS write permission on the directory?
Access to path denied on IIS
IOException access denied when Directory.Move subfolder and parent folder
EDIT
After copying the files using FileInfo.Copy I delete the tempFolder with Directory.Delete(pathFrom, true); which also works.

Related

Application: Application Launcher, can't Move directory, it's being used by another process

I'm writing application launcher as a Window Application in C#, VS 2017. Currently, having problem with this piece of code:
if (System.IO.Directory.Exists(extractPath))
{
string[] files = System.IO.Directory.GetFiles(extractPath);
string[] dirs = Directory.GetDirectories(extractPath);
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
// Use static Path methods to extract only the file name from the path.
var fileName = System.IO.Path.GetFileName(s);
var destFile = System.IO.Path.Combine(oldPath, fileName);
System.IO.File.Move(s, destFile);
}
foreach (string dir in dirs)
{
//var dirSplit = dir.Split('\\');
//var last = dirSplit.Last();
//if (last != "Resources")
//{
var fileName = System.IO.Path.GetFileName(dir);
var destFile = System.IO.Path.Combine(oldPath, fileName);
System.IO.Directory.Move(dir, destFile);
//}
}
}
I'm getting well known error
"The process cannot access the file 'XXX' because it is being used by another process."
I was looking for solution to fix it, found several on MSDN and StackOvervflow, but my problem is quite specific. I cannot move only 1 directory to another, which is Resources folder of my main application:
Here is my explanation why problem is specific:
I'm not having any issues with moving other files from parent directory. Error occurs only when loop reaches /Resources directory.
At first, I was thinking that it's beeing used by VS instantion, in which I've had main app opened. Nothing have changed after closing VS and killing process.
I've copied and moved whole project to another directory. Never opened it in VS nor started via *.exe file, to make sure that none of files in new, copied directory, is used by any process.
Finally, I've restarted PC.
I know that this error is pretty common when you try to Del/Move files, but in my case, I'm sure that it's being used only by my launcher app. Here is a little longer sample code to show what files operation I'm actually doing:
private void RozpakujRepo()
{
string oldPath = #"path\Debug Kopia\Old";
string extractPath = #"path\Debug Kopia";
var tempPath = #"path\ZipRepo\RexTempRepo.zip";
if (System.IO.File.Exists(tempPath) == true)
{
System.IO.File.Delete(tempPath);
}
System.IO.Compression.ZipFile.CreateFromDirectory(extractPath, tempPath);
if (System.IO.Directory.Exists(oldPath))
{
DeleteDirectory(oldPath);
}
if (!System.IO.Directory.Exists(oldPath))
{
System.IO.Directory.CreateDirectory(oldPath);
}
if (System.IO.Directory.Exists(extractPath))
{
string[] files = System.IO.Directory.GetFiles(extractPath);
string[] dirs = Directory.GetDirectories(extractPath);
// Copy the files and overwrite destination files if they already exist.
foreach (string s in files)
{
// Use static Path methods to extract only the file name from the path.
var fileName = System.IO.Path.GetFileName(s);
var destFile = System.IO.Path.Combine(oldPath, fileName);
System.IO.File.Move(s, destFile);
}
foreach (string dir in dirs)
{
//var dirSplit = dir.Split('\\');
//var last = dirSplit.Last();
//if (last != "Resources")
//{
var fileName = System.IO.Path.GetFileName(dir);
var destFile = System.IO.Path.Combine(oldPath, fileName);
System.IO.Directory.Move(dir, destFile);
//}
}
}
string zipPath = #"path\ZipRepo\RexRepo.zip";
ZipFile.ExtractToDirectory(zipPath, extractPath);
}
And now, my questions:
Can it be related to file types (.png, .ico, .bmp) ?
Can it be related to fact, that those resources files are being used like, as, for example .exe file icon in my main application? Or just because those are resources files?
Is there anything else what I'm missing and what can cause the error?
EDIT:
To clarify:
There are 2 apps:
Main Application
Launcher Application (to launch Main Application)
And Resources folder is Main Application/Resources, I'm moving it while I'm doing application version update.
It appeared that problem is in different place than in /Resources directory. Actually problem was with /Old directory, because it caused inifinite recurrence.

How to copy dll file dependency to Temp compilation folder for Azure Function App?

I am working with an azure function app that uses a third-party DLL, that has a dependency on an XML mapping file being present in a folder relative to the current execution. When I publish and run my function on my Azure stack, I run into an exception that the dll cannot load the XML file. I have the XML present in my bin directory with the dll, but Azure appears to be moving the compiled dlls to a temporary folder without the required XML, and proceeds to be looking for the XML relative to that temporary path based on the following exception message:
"Could not find a part of the path 'D:\\local\\Temporary ASP.NET Files\\root\\da2a6178\\25f43073\\assembly\\dl3\\28a13679\\d3614284_4078d301\\Resources\\RepresentationSystem.xml'."
Is there any way I can make sure these additional files are also copied to the temporary folder that Azure is running? Alternatively, can I just force it to run from bin rather than temp?
Update: Unfortunately I am not permitted to share any info on the dll. What I can say is that everything is published to my wwwroot folder, however when outputing some debug info, I can see that the execution is happening from the "Temporary ASP.NET Files" folder. Each dll is copied to its own seperate folder. D:\local\Temporary ASP.NET Files\root\da2a6178\25f43073\assembly\dl3\28a13679\d3614284_4078d301\ThirdParty.dll is that path were the dll in question is, and it lines up with where it expects the xml to be.
While this isn't a true answer to the issue, a workaround for this problem was to have a function in code before the dll functions run, that searches for the dll in question in the Temp ASP.Net folder, and then copies the xml files from a known location to that directory.
// Work Around Begin Here
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
// Check if we are in temp dir
if (assemblyFolder.Contains("Temporary ASP.NET Files"))
{
DirectoryInfo dir = new DirectoryInfo(assemblyFolder);
// Go up 2 dirs
DirectoryInfo top = dir.Parent.Parent;
DirectoryInfo[] dirs = top.GetDirectories();
foreach (DirectoryInfo child in dirs)
{
DirectoryInfo[] dirs2 = child.GetDirectories();
foreach (DirectoryInfo child2 in dirs2)
{
// Find out if this is the Rep
if (File.Exists(child2.FullName + "\\ThirdParty.Representation.dll"))
{
// Look to see if resource folder is there
if (!Directory.Exists(child2.FullName + "\\Resources"))
{
child2.CreateSubdirectory("Resources");
}
DirectoryInfo resDir = new DirectoryInfo(child2.FullName + "\\Resources");
if (File.Exists(resourceDir + "RepresentationSystem.xml"))
{
if(!File.Exists(resDir.FullName + "\\RepresentationSystem.xml"))
{
File.Copy(resourceDir + "RepresentationSystem.xml", resDir.FullName + "\\RepresentationSystem.xml");
}
}
if (File.Exists(resourceDir + "UnitSystem.xml"))
{
if (!File.Exists(resDir.FullName + "\\UnitSystem.xml"))
{
File.Copy(resourceDir + "UnitSystem.xml", resDir.FullName + "\\UnitSystem.xml");
}
}
}
}
}
}
Thank you DoubleHolo for this workaround. It run fine.
I have changed the code adding only Path.Combine to simplify the code.
private void CopyResourcesToTemporaryFolder()
{
// Work Around Begin Here
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string resourceDir = Path.Combine(FileUtils.WebProjectFolder, "Resources");
// Check if we are in temp dir
if (assemblyFolder.Contains("Temporary ASP.NET Files"))
{
DirectoryInfo dir = new DirectoryInfo(assemblyFolder);
// Go up 2 dirs
DirectoryInfo top = dir.Parent.Parent;
DirectoryInfo[] dirs = top.GetDirectories();
foreach (DirectoryInfo child in dirs)
{
DirectoryInfo[] dirs2 = child.GetDirectories();
foreach (DirectoryInfo child2 in dirs2)
{
// Find out if this is the Rep
if (File.Exists(Path.Combine(child2.FullName, "AgGateway.ADAPT.Representation.DLL")))
{
// Look to see if resource folder is there
if (!Directory.Exists(Path.Combine(child2.FullName, "Resources")))
{
child2.CreateSubdirectory("Resources");
}
DirectoryInfo resDir = new DirectoryInfo(Path.Combine(child2.FullName, "Resources"));
if (File.Exists(Path.Combine(resourceDir, "RepresentationSystem.xml")))
{
if (!File.Exists(Path.Combine(resDir.FullName, "RepresentationSystem.xml")))
{
File.Copy(Path.Combine(resourceDir, "RepresentationSystem.xml"), Path.Combine(resDir.FullName, "RepresentationSystem.xml"));
}
}
if (File.Exists(Path.Combine(resourceDir, "UnitSystem.xml")))
{
if (!File.Exists(Path.Combine(resDir.FullName, "UnitSystem.xml")))
{
File.Copy(Path.Combine(resourceDir, "UnitSystem.xml"), Path.Combine(resDir.FullName, "UnitSystem.xml"));
}
}
}
}
}
}
}

creating nested folder in c# shows access denied error

I am trying to create folders in nested manner.
if (file.ContentLength > 0 && file != null)
{
string path = "~/Videos/" + Session["username"] + "_" + Session["userid"];
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filename = path + file.FileName;
filepath = "/Videos/" + Session["username"] + "_" + Session["userid"];
file.SaveAs(filename);
If you see here- /Videos/ folder is what I have currently on disk. Where another folder with user's name and id is what I want to create inside this Videos folder. How Would I be creating this folder inside this folder?
Because currently it is showing me this error -
Access to the path '~/Videos/shaun_2' is denied.
I tried restarting visual studio with administrator's credentials. But it still remains here.
I'm assuming that you are using ASP.NET: try to use Server.MapPath("~/...") to get the physical path
See MSDN

Check for Sub directory in C#

I am storing the files extracted from a rar/zip file in a folder.
After that I am storing the files inside that folder to a database. The problem is it stores only the files in the folder not the sub directories and its files.
How to find if the folder has any sub directories.
I am using the code below
Directory.CreateDirectory(StorageRoot + path + New_folder);
decom(StorageRoot + path + New_folder, StorageRoot + path + file.FileName);
foreach (var access_file in Directory.GetFiles(StorageRoot + path + New_folder))
{
string new_name=System.IO.Path.GetFileName(access_file);
FileInfo f = new FileInfo(StorageRoot + path + New_folder+ "/" + new_name);
int new_size = unchecked((int)f.Length);
string new_path = path + New_folder;
statuses.Add(new FilesStatus(new_name, new_size, new_path, StorageRoot, data));
}
How to get the list of files and directories in a folder. and save them in db?
To get the files and directories in a folder you can use Directory.GetFiles() and Directory.GetDirectories()
Use recursion or Queue to recursively traverse directories.
Example with recursion:
void Traverse(string directory)
{
foreach(var dir in Directories.GetDirectories(directory))
{
Traverse(directory);
}
// Your code here
}
This may helps:
System.IO.DirectoryInfo info = new System.IO.DirectoryInfo("YOUR PATH");
//List of directories
var result = info.GetDirectories().Select(i => i.FullName);
You can use GetDirectories to get sub folder DirectoryInfo's and iterate through them untill Getdirectories returns nothing.
You can use Directory.GetFileSystemEntries() to get a list of both files and directories.
http://msdn.microsoft.com/en-us/library/system.io.directory.getfilesystementries.aspx

Process.Start is not working after hosting asp.net web application in IIS

I have a return a c# code to save a file in the server folder and to retrieve the saved file from the location. But this code is working fine in local machine. But after hosting the application in IIS, I can save the file in the desired location. But I can't retrieve the file from that location using
Process.Start
What would be the problem? I have searched in google and i came to know it may be due to access rights. But I don't know what would be exact problem and how to solve this? Any one please help me about how to solve this problem?
To Save the file:
string hfBrowsePath = fuplGridDocs.PostedFile.FileName;
if (hfBrowsePath != string.Empty)
{
string destfile = string.Empty;
string FilePath = ConfigurationManager.AppSettings.Get("SharedPath") + ConfigurationManager.AppSettings.Get("PODocPath") + PONumber + "\\\\";
if (!Directory.Exists(FilePath.Substring(0, FilePath.LastIndexOf("\\") - 1)))
Directory.CreateDirectory(FilePath.Substring(0, FilePath.LastIndexOf("\\") - 1));
FileInfo FP = new FileInfo(hfBrowsePath);
if (hfFileNameAutoGen.Value != string.Empty)
{
string[] folderfiles = Directory.GetFiles(FilePath);
foreach (string fi in folderfiles)
File.Delete(fi);
//File.Delete(FilePath + hfFileNameAutoGen.Value);
}
hfFileNameAutoGen.Value = PONumber + FP.Extension;
destfile = FilePath + hfFileNameAutoGen.Value;
//File.Copy(hfBrowsePath, destfile, true);
fuplGridDocs.PostedFile.SaveAs(destfile);
}
To retrieve the file:
String filename = lnkFileName.Text;
string FilePath = ConfigurationManager.AppSettings.Get("SharedPath") + ConfigurationManager.AppSettings.Get("PODocPath") + PONumber + "\\";
FileInfo fileToDownload = new FileInfo(FilePath + "\\" + filename);
if (fileToDownload.Exists)
Process.Start(fileToDownload.FullName);
It looks like folder security issue. The folder in which you are storing the files, Users group must have Modify access. Basically there is user(not sure but it is IIS_WPG) under which IIS Process run, that user belongs to Users group, this user must have Modify access on the folder where you are doing read writes.
Suggestions
Use Path.Combine to create folder or file path.
You can use String.Format to create strings.
Create local variables if you have same expression repeating itself like FilePath.Substring(0, FilePath.LastIndexOf("\\") - 1)
Hope this works for you.
You may have to give permissions to the application pool that you are running. see this link http://learn.iis.net/page.aspx/624/application-pool-identities/
You can also use one of the built-in account's "LocalSystem" as application pool identity but it has some security issue's.

Categories