views:

36

answers:

3

I have a windows service which is trying to access an xml file from the Application directory.

Windows Service Installed directory : C:\Services\MyService\MyService.exe
Path of the xml file : C:\Services\MyService\MyService.xml

I am trying to access the file using the following code.

using (FileStream stream = new FileStream("MyService.xml", FileMode.Open, FileAccess.Read))
  {
         //Read file           
  }

I get the following error.

"Can not find file : C:\WINDOWS\system32\MyService.xml"

My service is running with local system account and I don't want to use absolute path.

Edit: I got something related to this here.

http://haacked.com/archive/2004/06/29/706.aspx

+2  A: 

You need to find the path to your service's assembly, like this:

static readonly string assemblyPath = 
    Path.GetDirectoryName(typeof(MyClass).Assembly.Location);

using (FileStream stream = File.OpenRead(Path.Combine(assemblyPath, "MyService.xml"))
SLaks
It is more reliable to use `Location` in this case rather than `CodeBase`... see the MSDN docs for info.
Noldorin
Another problem is that you are using `typeof(MyClass).Assembly` to get the main assembly of the program. `Assembly.GetEntryAssembly()` is more reliable, again.
Noldorin
@Noldorin#2: On the contrary. His code should work no matter who called his assembly.
SLaks
I think you miss the point. You don't know where that code is going to be defined. Semantically, it is not where the class is defined that we're interested in, but rather what assembly the OS first loaded for the program.
Noldorin
I don't think so. His code is in an assembly that has been installed to a specific location. He wants to look in that location, no matter how his assembly was executed.
SLaks
+1  A: 

When a Windows Service is launched, the current directory is the system directory, as you indeed seem to be finding. It is the current directory that is used to resolve relative paths into absolute paths, not your application (service) directory. (Check the Environment.CurrentDirectory variable if you want to confirm this.)

The following helper method may come in handy here:

public static string GetAppRelativePath(string path)
{
    return Path.Combine(Path.GetDirectoryName(
        Assembly.GetEntryAssembly().Location), path);
}

Which you can then use as:

using (FileStream stream = new FileStream(Utilities.GetAppRelativePath(
    "MyService.xml"), FileMode.Open, FileAccess.Read))
{
    // Read file
}

The path will then resolve to C:\Services\MyService\MyService.xml, as you want.

Noldorin
Won't the path resolve to C:\Services\MyService\MyService.xml, which is what is required? I think it is just a typo.
Waleed Al-Balooshi
@Waleed: Sorry, you're right. It resolves to the correct path, I just wrote the wrong 'correct path'. ;)
Noldorin
A: 

There is an elegant solution for this from the following link.

http://haacked.com/archive/2004/06/29/706.aspx

As my service is running both as console/service I just called

Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory) 

before running it as Service E.g.

static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
                RunAsService();
            }
            else
            {
                RunAsConsole();
            }
        }
Amitabh