XML file couldn't be detected after windows service setup - c#

I have created a windows service. I do the setup of the service using the windows installer.
I have one XML file like a config file. Whenever i debug windows service with attaching the debug project it works fine. But after the installation i can see the event saying couldn't find the example.xml file in C:\Windows\system32. It's a repeating problem. Can anyone tell me whats going on with this. Or any suggestions?

This isn't an installer problem. Windows Services are always started with System32 as the current directory. Add this line to the Main() method in your Program.cs prior to firing up any services.
Environment.CurrentDirectory = new FileInfo(Assembly.GetExecutingAssembly().FullName).DirectoryName;

Most likely file is just not where you are looking for it.
Chances are that your code looks in "current working folder" which during debugging in VS is the same as application, but in case of starting as service/from command line is different.
Make sure your code loads file from location you expect the file to be (i.e. next to the application), but not from some relative path (like "myfile.xml").

Why are you saving stuff in the Windows folders? Unless there's a really good reason to do so, this is bad. Install your config in the same place that your app is running and get the file path with:
var folderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var configPath = Path.Combine(folderPath, configFileName);

The issue is that your service is not running as Administrator. If the service is not running as Administrator, then it won't be able to read the files under system32 folder.
Change the service properties to run as Administrator. That should fix the issue.

Related

How to attach file to windows service?

Is it possible to attach a flat file to windows-service?
My windows-service uses few flat file (for data purposes). Usually, if it's a normal executable I would place those files in the same directory as exe. How can I achieve that with windows-service?
I've done some research on this, but all I found was:
1. Pass a path to those files as a parameter to windows-service.
2. Make a fixed path and just require those files there
But I don't like those solutions. I was wondering if it's possible to attach those files to the windows service while installing it?
How about adding these files inside the project as Embedded Resources? They won't show up on the disk, but you could still properly read them from inside the assembly itself.
Here's some reference: https://support.microsoft.com/en-ie/kb/319292
You can look up the directory that your application is installed in at runtime, using the Application.StartupPath property from System.Windows.Forms. This works for both applications and services. You should avoid hard-coding the path that you think your application is installed in, because the end user may have installed it somewhere else. You should also avoid using the current directory (i.e., opening the file by name only, without a specific path) because the user may be running your application with a different current directory.
Note that installutil does not make a copy of your service executable. So the service runs from the same directory that it was in when you installed it, and any files you place in that directory should still be there when the service is running.

Visual Studio Installer with to set path of script file

I have a Visual Studio installer that installs a Windows Service hosting a Web Service.
What I am trying to resolve is to give users during installation a choice of where a particular script is located on the box and once they have set the location to then update the location to the app.config file which the application can then use.
At the moment during install I have added a custom folder and added to that the folder the file. This all gets installed. I want to keep this as a default, but to be able to overwrite it with the users new choice.
I have added a user interface and a text box to capture the user's choice, and a installer class, but this is failing when I try it. Where it is failing is when it is try to find my App.Config file. It says that it cannot find it. In my code, I have written:
string path = Assembly.GetExecutingAssembly().Location;
So, to me my app.config has not been installed into this location when the installation is running at that moment in time.
So, can someone please advise how I can override and save the new location.
Thanks
What you're doing won't work for a number of reasons.
Custom actions in VS setup projects run after all the files have been installed, so it's too late to choose a folder where files can be installed. UI is supposed to be at the front where the normal wizard UI forms run, but VS setups don't support custom dialogs.
Installer classes with UI tend to do strange things because they are called from the execute sequence in the MSI, and the apartment threading won't work.
You're not running in an interactive user environment. Your installer class is being called from an msiexec process running with the system context. If you need to load files, name the path explicitly.
If you're going to stick with Visual Studio setups, your best bet is to install the script to a normal default location and have your app offer a way to copy it somewhere. Then the user can copy it somewhere new whenever they want and you're running in a normal user environment.
You can not get the directory full path where the MSI is being installed using,
string path = Assembly.GetExecutingAssembly().Location;
above code will probably return a path C:\Windows\System32 which has the msiexec.exe location which handles the MSI installation. Use the following code within installer class to get the installation path.
string installationPath = Context.Parameters["assemblypath"];
Rest of your questions are not clear.
Folks
Managed to resolve this myself.
I added an afterinstall event to the Installer class. In this event I added this line of code
string assembley = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(assembley);
string path = Uri.UnescapeDataString(uri.Path);
string directory = Path.GetDirectoryName(path);
To get the config file - I did this
Configuration config = ConfigurationManager.OpenExeConfiguration(Assembly.GetAssembly(typeof(ProjectInstaller)).Location);
This gives me what I want and it works

How come my Windows Service cannot access a folder with files in them?

I have setup a Console, Library, and Service project. The Library project loads up files in a folder and stores the text in variables.
The console project will then manipulate those variables. I am able to run the Console project successfully and it loads the files without a problem. The files are set to Copy Always in the DLL and are specified as Content for the Build Action.
When I try to run the exact same code in the service.
File.ReadAllText(#"MyFolder\SomeFile.txt");
It throws the following exception.
The type initializer for 'MyLibrary.Data.ReadFiles' threw an exception.
I am using the Setup Project type to create the installer. After the service installs the folder MyFolder does exist in the Application Folder of the service, as well as the files. What else could be causing my problem for the service not being able to read those files?
EDIT 1
public class ReadFiles {
public static string DataFile = File.ReadAllText(#"MyFolder\SomeFile.txt");
}
The service account that you're running the Windows service under, doesn't have rights to read from the location you're trying to access. The error you're seeing has to do with the fact that the code you showed likely exists in the construction of the type ReadFiles.
Was facing similar issue in one of the windows service for running node js application, for sending emails.
It was running fine when we run from the same directory, but running same application as windows service was having issues and couldn't send emails. Comment from #meanbunny did help, so adding it as an answer.
Windows service can't access the directory/files if they are mentioned in the code as relative path, better use the absolute path or be more flexible as #Mike mentioned in his comment to use app.config for each service.

Run program from windows service

I have a program that is stored in program files folder.
I created windows service to run it, but when I do, it doesn't start.
I used process monitor to see what happens, and realized that it's looking for all dependencies in system32 folder.
If I take the program, with all referenced dependencies and paste them into the root of system32 folder, it works! But I don't like it that way, I want to run it from specific folder.
Add your program's folder to PATH environment variable and your service will find it there...
The PATH trick didn't work. It gave me error about some depended file software were trying to locate. But I found the solution. You can provide working directory:
process.StartInfo.WorkingDirectory
That did the trick. Thanks anyway!

How to get to app-relative subdirectory in .net windows app?

I have an application that contains a sub folder that contain xml file ,that is use as a database now i want take the path of the xml file at run time ,how can i achieve this in window application?
I know how it does in asp.net using Server.MapPath but i want this is same in windows application
please help
thanks in advance .
Use Aplication.ExecutablePath property when am XML document and executable are reside in the same directory.
I think the recommended way in Windows is to use the Application.StartupPath property.
And with Path.Combine you can have your xml file path Server.MapPath-style like this:
var appPath = Application.StartupPath;
var xmlPath = Path.Combine(appPath, "data/my_db.xml");
// xmlPath now points to app-relative data/my_db.xml file
...
A nuanced answer:
The best way to access data would be to put it in Application.CommonAppDataPath or Application.UserAppDataPath so that it does not depend on the application's installed path. However, there are many reasons why you might need to avoid this.
To answer your question:
If the application is a standard forms application deployed to the client's machine by an installer or XCopy deployment, then the path to the executable is Application.ExecutablePath
If the application is Click-Once deployed, then I would not recommend using the above since the app's path is obscured, shadow-copied and put in the sandbox. You can use ApplicationDeployment.IsNetworkDeployed to test for click-once deployment then ApplicationDeployment.CurrentDeployment.ActivationUri to get the URI that the application was launched from. Your app-relative file will be on that web server; you will always be able to download it.
of course in click-once deployent it would be better to tag the file as Data in which case it would be accessible through ApplicationDeployment.CurrentDeployment.DataDirectory
if the application is a web app, then the Application class is useless. In this case you should use Assembly.GetExecutingAssembly().Location This works because currently executing assembly for a web app is almost always in the web app's /bin directory.
For a "portable" assembly where you don't have an installer, and for rare cases where you don't want to use the Application class, use Assembly.GetEntryAssembly().Location This works because it figures out what the entry point assembly is (your application) and uses that location. This is reliable because assemblies that your entry assembly load don't have to be in the same directory as the entry assembly.
You can get the directory of the currently executing assembly using
System.Runtime.Reflection.Assembly.GetExecutingAssembly().Location
from there you can get to your subdirectory.

Categories

Resources