views:

1521

answers:

4

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)...

+1  A: 

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.

tomasr
+6  A: 

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 = 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 ) );
Rob Prouse
If I remember correctly, Assembly.Location returns the full path to the assembly, i.e. including the file name. So you would have to call Path.GetDirectoryName(ass.Location) to actually get the directory. Apart from that, +1 for the answer.
OregonGhost
Thank you, Rob - helpful stuff but I think Schmuli's answer gave more insight to the general concept of what was bugging me. +1
Dan Malkinski
A: 

Hi,

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

RWendi
+4  A: 

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.

Schmuli
Thanks - I think this helps the most
Dan Malkinski