.NET console application relative path - c#

How can we get a file in another folder of a console application?
I have an image file in a folder relative to the.cs file which is trying to access it.
For now I am using the exact path to the file, but when I ship this application to the client, it may not work as the path would not be valid on the client's machine.
Here's the code I am using right now:
workSheetIntroduction.Pictures.Add(5,1, #"C:\Users\Charu\Documents\Visual Studio 2013\Projects\AsmEpmReports\EmpReports.DomainLayer\Resources\Images\EpmLogo.png");

The Microsoft ideal is to install the application and then use the user path.
The files are then saved to the user's tree. If you cannot do an install, you can check if the directory exists before saving and then create it. You can also have the application ask for the directory and then create it where the user desires it. Or set it up as a configuration variable.
Lots of options. I would choose the first, if possible, as that is the preferred Microsoft method.

As Gregory said, relative paths would be the ideal, but you could ensure that the file is in the relative path by performing a FILE.Exists(<path>) where <path> is the relative path of the file to be used.
See Naming Files, Paths, and Namespaces for more information on relative vs. absolute paths.

Related

How do I make paths relative to a target project rather than a Unit Test project?

I have two projects .NET Web API 2 projects, MyProject and MyProject.Tests. MyProject has a settings.json file which I use to store database credentials. I used a custom external settings file because the database credentials includes a username and password that shouldn't be bundled in with other settings and are user-specific.
I wrote a ConfigManager() class with a GetDbConnectionString() method that reads the DB credentials from an external file and generates a connection string. It uses a relative path to the config file that lives in the project directory. This works fine during normal execution, because the path is relative to MyProject. However when running units tests, all relative paths are relative to MyProject.Tests, and fail to find the proper file. I can use an absolute path, but I would prefer for all settings files to be bundled in the project directory.
Is there a way I can have the unit tests fine the settings file properly without duplicating it in the unit test project and without using absolute paths>
You may want to use Directory.GetCurrentDirectory() or System.Reflection.Assembly.GetExecutingAssembly().Location to get to the path.
Directory.GetCurrentDirectory() will give you the current folder (which is more of a context, as you can create a shortcut and pass a completely different folder as your current directory than the one where your exe is present).
System.Reflection.Assembly.GetExecutingAssembly().Location will give you the path of the dll (or exe depending on compilation option).
System.Reflection.Assembly.GetAssembly(typeof(ConfigManager)).Location; should give what you are looking for.
Refer to suggestions in
How do I get the path of the assembly the code is in?

Writing to File in C# with/without relative paths

I am currently trying to get user input from commandline OutputPath
using (outfile = new StreamWriter(OutputPath))
{
outfile.Write(result);
}
This writes to absolute path if given or writes the file under c:\windows\system32
How can I make it either absolute path or depending on the current directory. Is there a way to get the current working directory from command line or is there a better API that can figure it out.
Thanks
Use Path.IsPathRooted to figure out whether the input is absolute or not, and Environment.CurrentDirectory to get the current Directory. With this information you should be all set.
C# does know how to use relative paths based on the current directory.
If you're seeing files created in C:\Windows\System32, then probably that IS your current working directory.
A shortcut can set the working directory of the program it is launching. Open/Save common file dialogs also mess with the current working directory.
If you launch an application without using a shortcut, it will inherit the current directory from the parent process. explorer.exe usually has C:\Windows\System32 as the working directory, which make it pretty common for applications launched by double-clicking an icon in Explorer.
You can use Directory.GetCurrentDirectory to get the current working directory on OS.

Deploying c# application issues

I have a application with one folder which i added by right clicking the project, selecting add folder. Inside this folder i have xml files which are set to build action:content, copy to output directory: copy if newer (i have tried setting to embedded resource) As well as this i have a few text files and so on.
In my bin/debug output directory i have the exe, the folder with the xml, the stand alone .txt files and so on. My problem is, if i send the exe to my friend to try he always gets an exception thrown.
Say he puts the exe on the desktop, my programme at some point reads the filenames of the xml files in the folder. It uses the following code to do so
String[] filePaths = Directory.GetFiles(#"DataSources\");
I assume that because of this, when the exe runs from the desktop, it expect the folder of .xml files to be in the same place? I have the same type of exception when trying to read the .txt files too. What am i doing wrong here?
Thanks for your time
When reading from files using relative paths you get the one relative to the applications current directory. tip: In C# you can see what directory that is using Environment.CurrentDirectory.
So if you create a shortcut on your desktop, you need to make sure you right click the shortcut and set its "Start in"-folder to the directory of your application. That way its current directory will be set when its started and relative paths will be relative to that path and not the path of the shortcut.
If you actually moved the exe file to the desktop you also need to move any resources that it needs, so if it wants a folder named "datasources" you would have to move that folder as well, or set the current directory when you start the application.
Have you tried something like: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.executablepath.aspx or http://msdn.microsoft.com/en-us/library/system.environment.currentdirectory.aspx ?
So
Directory.GetFiles(environment.currentdirectory + #"\DataSources\");

Hard Coded Paths in a .NET Program

I am developing an application in C#. I have a folder called myfolder it contains a file called mypoints.bmp. The folder myfolder is in my project folder it is in D drive. The path is D:\Myproject\myfolder\mypoints.bmp.
Now, in my program, whereever I need mypoints.bmp I have hardcoded the whole path. When my project is copied in to a different system under C drive, I am not able to run my project because of the hardcoded path. How can I give the path so that there will not be any problem even if it is loaded in to a different system under a different drive.
The best would be to store the path in a configuration file.
Add -> New Item -> Application Configuration File
Then you can use the following class to pull the value you're looking for:
System.Configuration.ConfigurationManager
Have a look here on the usage.
If the images you are referring to are non-changing and are simply acting as a resource for your application then you could consider embedding them in resource files which are compiled as part of your assembly. That way you need never worry about paths or copying them.
If the BMP file is used in the code and is accessed in runtime, there is no point in keeping it just in the project directory. it should be also present in the outputdirectory.
i.e you could write a post-build command to copy your folder to the output directory.
like copy "$(ProjectDir)\MyFolder\*.*" "$(OutDir)"
then in the code you could just write the relative path i.e "MyFolder\MyPoints.bmp"
But please remember one thing. If this BMP file is not going to change through out your program execution, it is better that you put it as a resource.
You can use something like GetCurrentPath(), which will return your .exe file path, then add to this path your \myfolder\mypoints.bmp. This will not be depend on C or D or ... drive and folder
There is one path that you can always reliably find, no matter how your program got deployed to the target machine: the directory in which your .exe is stored.
Take advantage of this, put the .bmp file in the same directory. Or a subdirectory of the install directory. You didn't say what kind of program you wrote, it is easy with Application.ExecutablePath in Windows Forms. But the generic solution that works everywhere:
public static string GetImagePath(string filename) {
string exeFile = System.Reflection.Assembly.GetEntryAssembly().Location;
string exePath = System.IO.Path.GetDirectoryName(exeFile);
string imgPath = System.IO.Path.Combine(exePath, #"images");
string imgFile = System.IO.Path.Combine(imgPath, filename);
return imgFile;
}
Which assumes the images are stored in a subdirectory named "images". Tweak as necessary.
Last but not least: don't forget that you can add images to your program's resources so it is baked in the .exe file. Project + Properties, Resources tab. Highly recommended.
You can also use predefined or existed system variable. Anyway you must decide when the user (or you) have to define that path (in config file or wherever) - during instalaltion, first run, before first run or in any time when app is running.
Personally I would use the Environment class in C#. Then I will locate the local app settings folder using the Environment.SpecialFolder enum.
I will then store all my applications specific files inside a folder in the local app settings folder.
This way you are also UAC safe, since UAC will complain if you want to store files in Program Files if you are not Administrator.

How does default/relative path resolution work in .NET?

So... I used to think that when you accessed a file but specified the name without a path (CAISLog.csv in my case) that .NET would expect the file to reside at the same path as the running .exe.
This works when I'm stepping through a solution (C# .NET2.* VS2K5) but when I run the app in normal mode (Started by a Websphere MQ Trigger monitor & running in the background as a network service) instead of accessing the file at the path where the .exe is it's being looked for at C:\WINDOWS\system32. If it matters The parent task's .exe is in almost the same folder structure/path as my app
I get a matching error: "System.UnauthorizedAccessException: Access to the path 'C:\WINDOWS\system32\CAISLog.csv' is denied."
My workaround is to just fully qualify the location of my file. What I want to understand, however is "What is the .NET rule that governs how a path is resolved when only the file name is specified during IO?" I feel I'm missing some basic concept and it's bugging me bad.
edit - I'm not sure it's a.NET rule per se but Schmuli seems to be explaining the concept a little clearer. I will definitely try Rob Prouse's suggestions in the future so +1 on that too.
If anyone has some re-wording suggestions that emphasize I don't really care about finding the path to my .exe - rather just didn't understand what was going on with relative path resolution (and I may still have my terminlogy screwed up)...
When an application (WinForms) starts up, the Environment.CurrentDirectory contains the path to the application folder (i.e. the folder that contains the .exe assembly). Using any of the File Dialogs, ex. OpenFileDialog, SaveFileDialog, etc. will cause the current directory to change (if a different folder was selected).
When running a Windows Service, its containing folder is C:\Windows\System32, as that is the System folder and it is the System (i.e. the Operation System) that is actually running your Windows Service.
Note that specifying a relative path in most of the System.IO objects, will fall back to using the Environment.CurrentDirectory property.
As mentioned, there are several ways to obtain the path of the service executable, using Assembly.GetEntryAssembly() or Assembly.GetExecutingAssembly() and then using either the Location property or the CodeBase property (be aware that this is the file path, not directory, of the executable).
Another option is to use:
`System.IO.Directory.SetCurrentDirectory( System.AppDomain.CurrentDomain.BaseDirectory );`
Make the call in the Service's OnStart method, applying it to the whole application.
It is based on the current working directory which may or may not be the same as where your application resides, especially if started from a different program or a shortcut with a different working directory.
Rather than hard code the path, get the path to your program and use it. You can do this with something like this
Assembly ass = Assembly.GetEntryAssembly();
string dir = Path.GetDirectoryName(ass.Location);
string filename = Path.Combine( dir, "CAISLog.csv" );
This assumes that the entry assembly is where your file is. If not, you can change up getting the assembly for something like;
Assembly ass = Assembly.GetAssembly( typeof( AClassInYourAssembly ) );
Relative Path resolution never works against the path of the launching executable. It always works against the process' Current Directory, and you can't really expect that to always be set to the directory the .exe lives in.
If you need that behavior, then take care to find out the right path on your own and provide a fully qualified path to the file operations.
You can use this to specify a path that resides at the same path of your exe #"..\CAISLog.csv". Please note that the double dots refer to the parent directory of where ever your .exe lies.
RWendi

Categories