UnauthorizedAccessException was unhandled - c#

I'm trying to take input and convert that to a .csv file then create a directory for the folder and save that file within the directory. Once I run my code, I'm able to create the directory and file. However, this is supposed to happen after I click the button and does so before. The exception is thrown right after I click the button. I'm using WPF and coding in C#. What would cause this exception?
Here is a snippet
private void updateBANKEevent(object sender, RoutedEventArgs e)
{
//Convert input to CSV format
string userInput = tellerID.Text + "," + vaultSerial.Text + "," + QR.Text;
var bnkDir = #"C:\Program Files\Bank_Data";
//generate headers for CSV file
if (!Directory.Exists(bnkDir))
{
string bnkHeader = "tellerID" + "," + "Vault Serial Number" + "," + "QR Code" + Environment.NewLine;
Directory.CreateDirectory(bnkDir); <--Exception is thrown here
File.WriteAllText(System.IO.Path.Combine(bnkDir,"Bank_Data.csv"), bnkHeader + userInput);
}
// Append new input to existing file
File.AppendAllText(System.IO.Path.Combine(bnkDir),userInput + Environment.NewLine);
}

The exception is quite clear. The user is not authorised to create the specified directory.
Given that the folder is "C:\Program Files\Bank_Data" it will be the case that a regular user won't have the rights to create files or directories whereas an admin user (which you probably are) will.
You need to choose a folder that all users have rights to to store your data, which by default will be %APPDATA%\<your app>.

Related

How can I fix my code to move files that already exist to another directory?

This is my first C# script and first non-SQL based script in general.I'm really proud of it (and I couldn't have done it this quickly without help from this community, thanks!), but I know it's going to be all kinds of messy.
The script loops through all files in a single directory, removes special characters from the file names, and renames the files to a standard, user-friendly, name. The script is looking for a specific set of files in the directory. If it finds a file that isn't supposed to be in the directory, it moves the file to a safe folder and renames it. If the folder
I'm working with 4 files that have dynamic names that will include numbers and special characters. The renaming process happens in two steps:
Remove special characters and numbers from the name. Ex: From "EOY 12.21.2018 - 12.28.2018 PRF.xls" to "EOYPRF.xls"
Rename the file to clearly label what the file is. Ex: From "EOYPRF.xls" to "EOY_CompanyName.xls"
There may be files added to this directory by accident, and since they are payroll files, they are highly confidential and cannot be moved unless they need to be moved (only if they are one of the 4 files), so I move them to a subdirectory in the same directory the files are stored in and rename them.
I am also trying to account for if my script or process messes up midway. This script is part of a larger automation process run in SSIS, so there are many failure points. It may be possible that the script fails and leaves one or all of the 4 files in the directory. If this is the case, I need to move the file out of the main directory before the user adds new, unaltered master files to be processed. If the directory contains files of the same final name ("EOY_CompanyName.xls") then it will not work properly.
I'm testing the script by placing the three scenario in the directory.
2 files that are not in any way associated with the 4 master files.
4 unaltered master files formatted with numbers and special characters: "EOY 12.21.2018 - 12.28.2018 PRF.xls"
4 master files already in their final state (simulating a failure before the files are moved to their final directory). Ex: "EOY_CompanyName.xls"
The problem I'm facing is in the rare scenario where there are both unaltered master files and final master files in the directory, the script runs up until the first unaltered file, removes the special characters, then fails at the final renaming step because a file already exists with the same name (Scenario 3 from the 3 points above). It'll then continue to run the script and will move one of the master files into the unexpected file directory and stop processing any other files for some reason. I really need some help from someone with experience.
I've tried so many things, but I think it's a matter of the order in which the files are processed. I have two files named "a.xls" and "b.xls" which are placeholders for unexpected files. They are the first two files in the directory and always get processed first. The 3rd file in the directory is the file named above in its unaltered form ("EOY 12.21.2018 - 12.28.2018 PRF.xls"). It gets renamed and moved into the unexpected files folder, but really it should be passed over to move the master files containing the final name ("EOY_CompanyName.xls") into the unexpected folder. I want to make sure that the script only processes new files whenever it's run, so I want to move any already processed files that failed to get moved via the script into another directory.
public void Main()
{
///Define paths and vars
string fileDirectory_Source = Dts.Variables["User::PayrollSourceFilePath"].Value.ToString();
string fileDirectory_Dest = Dts.Variables["User::PayrollDestFilePath"].Value.ToString();
string errorText = Dts.Variables["User::errorText"].Value.ToString();
DirectoryInfo dirInfo_Source = new DirectoryInfo(fileDirectory_Source);
DirectoryInfo dirInfo_Dest = new DirectoryInfo(fileDirectory_Dest);
string finalFileName = "";
List<string> files = new List<string>(new string[]
{
fileDirectory_Source + "EOY_PRF.xls",
fileDirectory_Source + "EOY_SU.xls",
fileDirectory_Source + "FS_PRF.xls",
fileDirectory_Source + "FS_SU.xls"
});
Dictionary<string, string> fileNameChanges = new Dictionary<string, string>();
fileNameChanges.Add("EOYReportPRF.xls", "EOY_PRF.xls");
fileNameChanges.Add("PayrollEOY.xls", "EOY_SU.xls");
fileNameChanges.Add("PRFFundingStatement.xls", "FS_PRF.xls");
fileNameChanges.Add("SUFundingStatement.xls", "FS_SU.xls");
///Determine if all files present
int count = dirInfo_Source.GetFiles().Length;
int i = 0;
///Loop through directory to standardize file names
try
{
foreach (FileInfo fi in dirInfo_Source.EnumerateFiles())
{
string cleanFileName = Regex.Replace(Path.GetFileNameWithoutExtension(fi.Name), "[0-9]|[.,/ -]", "").TrimEnd() + fi.Extension;
File.Move(fileDirectory_Source + Path.GetFileName(fi.Name), fileDirectory_Source + cleanFileName);
///Move unexpectd files in source directory
if (!fileNameChanges.ContainsKey(cleanFileName))
{
errorText = errorText + "Unexpected File: " + cleanFileName.ToString() + " moved into the Unexpected File folder.\r\n";
File.Move(dirInfo_Source + cleanFileName, dirInfo_Source + "Unexpected Files\\" + Path.GetFileNameWithoutExtension(cleanFileName) + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + fi.Extension);
}
if (fileNameChanges.ContainsKey(cleanFileName))
{
///Final Friendly File Name from Dict
var friendlyName = fileNameChanges[cleanFileName];
///Handle errors produced by files that already exist
if (files.Contains(fileDirectory_Source + friendlyName))//File.Exists(fileDirectory_Source + friendlyName))
{
MessageBox.Show("File.Exists(dirInfo_Source + friendlyName)" + File.Exists(dirInfo_Source + friendlyName).ToString() + " cleanFileName " + cleanFileName);
errorText = errorText + "File already exists: " + friendlyName.ToString() + " moved into the Unexpected File folder.\r\n";
File.Move(dirInfo_Source + friendlyName, dirInfo_Source + "Unexpected Files\\" + Path.GetFileNameWithoutExtension(friendlyName) + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + Path.GetExtension(friendlyName));
return;
}
///Rename files to friendly name
File.Move(dirInfo_Source + cleanFileName, dirInfo_Source + friendlyName);
finalFileName = friendlyName.ToString();
}
///Count valid PR files
if (files.Contains(dirInfo_Source + finalFileName))
{
i++;
}
}
///Pass number of files in source folder to SSIS
Dts.Variables["User::FilesInSourceDir"].Value = i;
}
catch (Exception ex)
{
errorText = errorText + ("\r\nError at Name Standardization step: " + ex.Message.ToString()) + $"Filename: {finalFileName}\r\n";
}
///Search for missing files and store paths
try
{
if (i != 4)
{
var errors = files.Where(x => !File.Exists(x)).Select(x => x);
if (errors.Any())
errorText = (errorText + $" Missing neccessary files in PR Shared drive. Currently {i} valid files in directory.\r\n\n" + "Files missing\r\n" + string.Join(Environment.NewLine, errors) + "\r\n");
}
}
catch (Exception ex)
{
errorText = errorText + ("Error at Finding Missing PR Files step: " + ex.Message.ToString()) + "\r\n\n";
throw;
}
///Loop through directory to move files to encrypted location
try
{
if (i == 4)
foreach (FileInfo fi in dirInfo_Source.EnumerateFiles())
{
fi.MoveTo(fileDirectory_Dest + Path.GetFileName(fi.FullName));
}
}
catch (Exception ex)
{
errorText = errorText + ("Error at Move Files to Encrypted Directory step: " + ex.Message.ToString()) + "\r\n";
}
Dts.TaskResult = (int)ScriptResults.Success;
Dts.Variables["User::errorText"].Value = errorText;
}
#region ScriptResults declaration
/// <summary>
/// This enum provides a convenient shorthand within the scope of this class for setting the
/// result of the script.
///
/// This code was generated automatically.
/// </summary>
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
}
}
I would ideally like to move all files that are in the folder before the files need to be cleaned and renamed so I dont receive errors or commit records to the database that already exist.
If you made it this far, thank you for your time and I appreciate you taking the hour it probably took to read this. You are a hero.
As I understand you want to move out any of the "4 short names" if they already exist before doing anything else. I would go with below, please note, I did not run the code..
I hope I understood you correct
///Loop through directory to standardize file names
try
{
//Cleanup source folder
foreach (string fileShortName in files)
{
if (File.Exists(fileDirectory_Source + fileShortName))
{
//Time to move the file, its old
errorText = errorText + "Old File: " + fileShortName + " moved into the Old File folder.\r\n";
File.Move(dirInfo_Source + fileShortName, dirInfo_Source + "Old Files\\" + Path.GetFileNameWithoutExtension(fileShortName) + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + Path.GetExtension(fileShortName));
}
}
foreach (FileInfo fi in dirInfo_Source.GetFiles())

How do I get the folder for the currently open file in c#

I am writing a wizard that pulls information from a database like file. This wizard doesn't get compiled, it just runs on command. I am not sure the correct term for that.
The issue is, I need to enter more information which will manipulate the database, and I want to store the values into a csv file that I use to manipulate the database.
So the question is: How do I get the folder for the currently open file in a c# application so that I can save a csv file to that folder?
edit: The path needs to be dynamic. Each database file is stored in a separate folder. I need the wizard to save to which ever folder I just opened the file from.
edit2 :
I am not opening the file programmatically. The file is being open by the user in the application. So, the user opens a file, and a bunch of database information is displayed. He then runs a wizard on that data where he can enter some coefficients, etc .. and that will change the information in the database file. I need to be able to store the coefficients he enters into the folder that contains the database file that he opened. I cannot access / change the application code, only the wizard code.
Thanks
Something like this?
var file = "C:\\Users\\Me\\Desktop\\Test.txt";
var fileLocation = file.Substring(0, file.LastIndexOf("\\"));
You can use this:
string path = Path.GetFullPath(Directory.GetCurrentDirectory()).TrimEnd(Path.DirectorySeparatorChar);
string directoryName = Path.GetFileName(path);
I found this solution in this thread
Get the (last part of) current directory name in C#
Try
//Or where ever the database returns the file is stored
var filename = "C:\\Temp\\File\\Test.txt";
var path = System.IO.Path.GetDirectoryName(filename);
Should return C:\Temp\File
Source : https://msdn.microsoft.com/en-us/library/system.io.path.getdirectoryname(v=vs.110).aspx
Try using DirectoryInfo to get information about any directory:
using System;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
if (di != null)
{
FileInfo[] subFiles = di.GetFiles();
if (subFiles.Length > 0)
{
Console.WriteLine("Files:");
foreach (FileInfo subFile in subFiles)
{
Console.WriteLine(" " + subFile.Name + " (" + subFile.Length + " bytes) " + "Directory name: "
+ di.Name + " Directory full name: " + di.FullName);
}
}
Console.ReadKey();
}
}
}
}

Creating a new directory in c#

I would like to first create a new dir and then save a file into the following location C:\Users\Paul\Documents + \newfolder\nameOffile.xml.
Can this be achieved in C#. I currently have the following code but i cant seem to get it to work
XDocument doc = new XDocument(rootNode);
var dateAndTime = DateTime.Now;
var date = dateAndTime.Date.ToString("dd-MM-yyyy");
var patWithoutExtension = Path.GetFileNameWithoutExtension(openFileDialog1.FileName);
string savedFilePah = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
var savedFile = savedFilePah + "/" + Directory.CreateDirectory("newFolder") + "/" + patWithoutExtension + "_" + date + ".xml";
//var savedFile = "C:/tmp/" + patWithoutExtension + "_" + date + ".xml";
doc.Save(savedFile);
lblFileUploaded.Text = "Success!";
it keeps failing on the doc.save with the following error
An unhandled exception of type 'System.IO.DirectoryNotFoundException'
occurred in System.Xml.dll
Additional information: Could not find a part of the path
'C:\Users\Paul\Documents\newFolder\test2_29-03-2015.xml'.
The problem seems to be with Directory.CreateDirectory("newFolder") which will create the folder under the working directory rather than under C:\Users\Paul\Documents.
Also, as a good practice I would advice to store the newly created folder in a dedicated folder. The advantages of this are twofold - you'll be able to watch this variable easily during debugging thus find out the exact location of the created folder and also, if an exception will be thrown you'll know the exact location of it.
Also, some Windows APIs might not accept a forward slash ('/') but will except a backslash ('\').
You must specify the full path to the directory you want to create, otherwise it's created at the working (running) folder:
string myDocs = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var myDir = Path.Combine(myDocs, "newFolder");
Directory.CreateDirectory(myDir);
var savedFile = Path.Combine(myDir, patWithoutExtension + "_" + date + ".xml");
This Directory.CreateDirectory("newFolder") is not creating the directory inside your Users folder: you're just passing it "newFolder", so it doesn't know that's where you want the folder. It will be creating it in your current working folder (e.g. bin/Debug).
Try passing the entire path to CreateDirectory:
string savedFilePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"newFolder");
Directory.CreateDirectory(savedFilePath);

Ghostscript.NET - no output file when run as Windows service

I'm writing a Windows Service to scan a set of directories for new PDF files and convert them to TIFF with Ghostscript.NET. When I'd compiled and ran the code as a normal program it functioned perfectly, but when I used the same code as a Service the output TIFF never appears. I've set the destination directory to allow writing for Everyone, and the original PDF is being removed as it's supposed to, so it shouldn't be a permissions issue for the "Local System" user. Auditing the directory for access Failures and Successes just shows a list of Successes.
There is a function that reads the color population of the PDF to determine if it's a color document, or B&W scanned as color. That part works, so there isn't an issue accessing and reading the PDF.
I've also tried removing '-q' from the Ghostscript switches and I don't have any errors reported, and "-dDEBUG" outputs so much garbage I don't know what it's saying - but nothing is tagged as an error.
public static void ConvertPDF(string file, GSvalues gsVals)
{
gsProc = new Ghostscript.NET.Processor.GhostscriptProcessor();
System.Collections.Generic.List<string> switches = new System.Collections.Generic.List<string>();
switches.Add("-empty"); // GS.NET ignores the first switch
switches.Add("-r" + gsVals.Resolution); // dpi
switches.Add("-dDownScaleFactor=" + gsVals.ScaleFactor); // Scale the image back down
switches.Add("-sCompression=lzw"); // Compression
switches.Add("-dNumRenderingThreads=" + Environment.ProcessorCount);
switches.Add("-c \"30000000 setvmthreshold\"");
switches.Add("-dNOGC");
string device;
if (_checkPdf(file, gsVals.InkColorLevels, gsVals))
{
gsVals.WriteLog("Color PDF");
device = "-sDEVICE=tiffscaled24"; // 24bit Color TIFF
}
else
{
gsVals.WriteLog("Grayscale PDF");
device = "-sDEVICE=tiffgray"; // grayscale TIFF
}
switches.Add(device);
// Strip the filename out of the full path to the file
string filename = System.IO.Path.GetFileNameWithoutExtension(file);
// Set the output file tag
string oFileName = _setFileName(oPath + "\\" + filename.Trim(), GSvalues.Extension);
string oFileTag = "-sOutputFile=" + oFileName;
switches.Add(oFileTag);
switches.Add(file);
// Process the PDF file
try
{
string s = string.Empty;
foreach (string sw in switches) s += sw + ' ';
gsVals.DebugLog("Switches:\n\t" + s);
gsProc.StartProcessing(switches.ToArray(), new GsStdio());
while (gsProc.IsRunning) System.Threading.Thread.Sleep(1000);
}
catch (Exception e)
{
gsVals.WriteLog("Exception caught: " + e.Message);
Console.Read();
}
gsVals.DebugLog("Archiving PDF");
try
{
System.IO.File.Move(file, _setFileName(gsVals.ArchiveDir + "\\" + filename, ".pdf"));
}
catch (Exception e)
{
gsVals.WriteLog("Error moving PDF: " + e.Message);
}
}
private static string _setFileName(string path, string tifExt)
{
if (System.IO.File.Exists(path + tifExt)) return _setFileName(path, 1, tifExt);
else return path + tifExt;
}
private static string _setFileName(string path, int ctr, string tifExt)
{
// Test the proposed altered filename. It it exists, move to the next iteration
if(System.IO.File.Exists(path + '(' + ctr.ToString() + ')' + tifExt)) return _setFileName(path, ++ctr, tifExt);
else return path + '(' + ctr.ToString() + ')' + tifExt;
}
This is a sample output of the generated switches (pulled from the output log):
Switches: -empty -r220 -dDownScaleFactor=1 -sCompression=lzw -dNumRenderingThreads=4 -c "30000000 setvmthreshold" -dNOGC -sDEVICE=tiffscaled24 -sOutputFile=\\[servername]\amb_ops_scanning$\Test.tiff \\[servername]\amb_ops_scanning$\Test.pdf
Settings are read in an XML file and stored in a class, GSVals. The class also handles writing to the System log for output, or to a text file in the normal Program version. GSSTDIO is a class for handling GS input and output, which just redirects all the output to the same logs as GSVals. The only code changes between the Program version and the Service version is the Service handling code, and the output is changed from a text file to the system logs. Nothing about the Ghostscript processing was changed.
This is being compiled as x86 for portability, but is being run on x64. GS 9.15 is installed, both x86 and x64 versions. GS.NET is version 4.0.30319 installed via NuGet into VS 2012. ILMerge 2.13.0307 is being used to package the GS.NET dll into the exe, also for portability. None of these things changed between the normal EXE and the Windows Service versions, and as I said the normal EXE works without any issues.
I got it working by using CreateProcessAsUser() from advapi32.dll, using code from this article.
I also had to restructure the order of the switches:
switches.Add("-c 30000000 setvmthreshold -f\"" + file + "\"")
The original source I'd used for speeding up the conversion left out the '-f' part, and the fact that the -f was the tag marking the file. I don't know why this worked in GS.NET, but with normal gswin32c.exe I got an error saying that it was an invalid file, until I set the switch this way.
Oddly, the processes this method creates are still Session 0, but it actually works. I'll keep tinkering, but for now it's working.

Temp Files Asp.net

Is it possilbe to create temp files and images in asp.net applications using something like this:
If no, how can i do it?
(ImagePB is a previously treated Bitmap)
if (System.IO.File.Exists(System.IO.Path.GetTempPath() + #"img" + imgID.ToString() + "PB" + extencao) == true)
{
try
{
System.IO.File.Delete(System.IO.Path.GetTempPath() + #"img" + imgID.ToString() + "PB" + extencao);
imagePB.Save(System.IO.Path.GetTempPath() + #"img" + imgID.ToString() + "PB" + extencao, imgFormat);
}
catch (Exception)
{ }
}
Yes, GetTempPath() should return a temporary file path, and the code you have posted should work. http://msdn.microsoft.com/en-us/library/system.io.path.gettemppath.aspx has more information about how GetTempPath() get's the path.
Though, it does not verify if the Temp Path directory exists, or is writeable by the application. I haven't run into a situation where GetTempPath() does return an inaccessible path. You'd probably want to account for this in your application to handle this situation.
Also be mindful, this is very possibly C:\Windows\Temp. It could have limited disk space, or deleted at any time by someone else when disk space is needed. You may want to create a temp path within your application, and delete it when you no longer need it.

Categories

Resources