Find the path of the folder containing the executable of a service - c#

I'm having some issues with a library that cannot find the path of its config file.
The reason beeing that my program is deployed in a directory and installed as a service using sc.exe.
When trying to locate the file in this case, it looks in System32 and cannot find it.
I can provide a full path to this library to solve the issue, however, how can I reference the folder of the executable called by the service in c# ?

I think that is what you're looking for:
System.AppDomain.CurrentDomain.BaseDirectory;
Ref: Should I use AppDomain.CurrentDomain.BaseDirectory or System.Environment.CurrentDirectory?

Related

Programmatically get Folder location for assembly

Shadow copying is a feature in the .NET framework to allow assemblies used in an app domain to be updated without unloading the app domain. Very useful in web site binary updates update/release for example.
Is there a programmatic way to read the formal location assembly folder i.e. the website \bin folder instead of the shadow copy folder?
For example when GetExecutingAssembly like this:
System.Reflection.Assembly.GetExecutingAssembly().Location
It returns ShadowCopy location folder:
C:\Windows\system32\config\systemprofile\AppData\Local\assembly\dl3\4LPBW244.CR4\DZO34RQG.YAW\caa6207b
I want to obtain the the \bin folder as per my example...
4 years without a response!
And I needed a response to this exact question!
I finally found a possible answer. This is what I did when trying to obtain the Location of an assembly. The assembly file name was "IKVM.Runtime.DLL"
System.Reflection.Assembly.ReflectionOnlyLoad("IKVM.Runtime").Location
Note the the file extension had to be removed!

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?

Defining where files are installed

I am trying to deploy a .NET application as a ClickOnce Application, but I am having trouble defining where the application is installed. I need to know this because I have to include support files. I have already added the support files as "existing items". I had assumed that the program would install in Program Files, but it does not exist there. Instead, there is just a shortcut on the desktop. Can someone explain how/where the install path is defined using VS2012?
One solution I found was to use some of the Application class properties to determine where ClicOnce installed an instance of my program. But be aware that some those are deleted on uninstall of the program.
// To get the path for the executable file that started the application, not including the executable name.
PATH_RESOURCES = Application.StartupPath ;
For persistant data I created references to specific paths like :
PATH_USERDATA = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + #"\myAppName\";
if (!System.IO.Directory.Exists((string)PATH_USERDATA))
{
System.IO.Directory.CreateDirectory((string)PATH_USERDATA);
}
PATH_REPORTS = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + #"\myAppName\";
if (!System.IO.Directory.Exists((string)PATH_REPORTS ))
{
System.IO.Directory.CreateDirectory((string)PATH_REPORTS );
}
Clickonce application gets installed under the user profile, not the Program Files path.
On windows Vista and Windows 7, clickonce application path will be somewhere in c:\users\username\AppData\Local\Apps\2.0\
On Windows XP, clickonce application path will be somewhere in c:\document and Settings\username\LocalSettings\Apps\2.0\
Note that Clickonce application path is different everytime upon installation, I found the best way is to make your app to write its own app path to the reg key, this way you know exactly where the app path is by looking at the reg.
So as user831062 pointed out, ClickOnce apps get installed under the user profile, not the Program Files path. Because of this, the install directory is different on every machine and almost impossible to access directly.
The part that I was hung-up on, was where are the files that I have included in the project located, and more importantly - how do I access them?
Well, as mentioned IN THIS LINK, if you mark the file as a "data file", under:
Project Properties > Publish > Application Files > Publish Status
you'll be able to access them using something like:
textBox = File.ReadAllLines(ApplicationDeployment.CurrentDeployment.DataDirectory + #"\myFile.txt")).ToList();
If you don't mark it as a "data file", but rather as just an "Include (Auto)", it will just be located in the install directory itself, which can be accessed by calling the file directly using something like:
textBox = File.ReadAllLines(#"myFile.txt")).ToList();
Anyway, took me an hour or so to find this, so hopefully it helps someone else out.
If you have added your files to your project, set the property for "build action" to "content" and set "copy to output directory" to "copy always". This way, the files will be included in your deployment. When the application is run, retrieve the location of the assembly and look in the same relative folder as where they were included in the project. For example, if they are in the top folder of the build output directory (/bin/debug/ or /bin/release/), they will be included in the same folder as the executable, which you can discover using this:
System.Reflection.Assembly.GetExecutingAssembly().Location

C# service location

I have a service in C#, it uses a config.xml file for configuration.
I want to deplay the xml along side with the service executable. But I can't seem to understand where to find the service exe installed location at runtime so that I could find/load the config.
Help please.
The static method Assembly.GetEntryAssembly() will give you a reference to the entry assembly (the .exe file), and the Location property will give you the location of the file:
Assembly.GetEntryAssembly().Location
Another way around, if you know of a type in the entry assembly, is to use the Type.Assembly to get a reference to the assembly:
typeof(Program).Assembly.Location
If you need just the directory path, use the static Path.GetDirectoryName() method.
Off topic: have you considered the configuration API built into .NET? I am not saying this will be better in your specific case, but I guess it is worth considering before rolling your own configuration framework.
Do you mean that you are building a project in visual studio and you want to know where your compiled EXE is saved to? You will find this in "[project folder]\bin\debug".
Or do you mean you already have a service installed on your computer and you want to know where its running from? To do this you can right click on the service and choose properties. This will show the path of the file.
Your executable is located in AppDomain.CurrentDomain.BaseDirectory.
Some of my service projects load a custom log4net configuration like this.
var file = new FileInfo( AppDomain.CurrentDomain.BaseDirectory + "/" + filename );
if (file.Exists) {
XmlConfigurator.ConfigureAndWatch( file );
}
The same service uses an normal app.config file for standard configuration.

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