21

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.

Amitabh
  • 59,111
  • 42
  • 110
  • 159

3 Answers3

38

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

http://haacked.com/archive/2004/06/29/current-directory-for-windows-service-is-not-what-you-expect.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();
            }
        }
JG in SD
  • 5,427
  • 3
  • 34
  • 46
Amitabh
  • 59,111
  • 42
  • 110
  • 159
5

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
  • 144,213
  • 56
  • 264
  • 302
4

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
  • 868,454
  • 176
  • 1,908
  • 1,964
  • It is more reliable to use `Location` in this case rather than `CodeBase`... see the MSDN docs for info. – Noldorin Apr 26 '10 at 14:37
  • 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 Apr 26 '10 at 14:39
  • @Noldorin#2: On the contrary. His code should work no matter who called his assembly. – SLaks Apr 26 '10 at 14:40
  • 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 Apr 26 '10 at 14:43
  • 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 Apr 26 '10 at 14:47