Sharing information between C# project and WiX - c#

I have an application that starts and stops a specific service. However that service is named differently depending on what configuration I build the project in. In my WiX setup I have
<ServiceInstall
<!-- etc... -->
Name='$(var.ServiceName)'
DisplayName='$(var.ServiceDisplayName)' />
where var.ServiceName comes from an include file specified during the build process. I have to use the same service name in my C# code, but my problem with this approach is that the service names are written in two different places. How can I get the service name into one place?

Consider putting the service name into a registry key, where your C# code can easily access it. Since you install a service, your product is not copy-deployable anyway so using the registry could be an option.

How is the C# code getting the service name? If it is picking up from config, then you can edit the config during install and get the installer to write the service name in to the config file, that way you keep the code in step with the value you specified in the WiX include.
EDIT.
In response to the question; by edit I mean configure the installer to edit the config for you at install time. I agree that doing it "by hand" (or requesting the user do it) is a bad idea. You can set this up in WiX. You need to use the XML File custom action, the WiX would look something like this snippet:
<Component ...>
<UTIL:XmlConfig>
Id=...
On="install"
Action="create"
File=[.. config file ID goes here ...]
ElementPath="//myElement/livesHere
Node="value"
Name="someNodeName"
Value="some value to set"
...
Sorry I can't paste a real snippet, our WiX config is proprietary:( Hopefully that doc link will see you right.

If you are naming it based on the configuration, why don't you use the $(var.ProjectName.Configuration) (where ProjectName is the name of your C# project) in the name of the service?

Related

Deploy on premise web app with transformed release configs

We are in the process of setting up our release definitions to finally finish the last piece of our CD/CI setup in VSTS and are running into an issue where we are unable to transform our configs.
Currently we are following Scott Hanselman's approach of keeping connection strings and secrets out of our web.config via a secrets.config because we don't want any of that information committed to source control. If there is a better practice for this scenario we are open to switching but currently unsure of how this would integrate with VSTS CD/CI.
We've tried using the XDT Transform Extension to transform our web.base.config to web.config to remove the file and the configsource references but it doesn't seem to be transforming.
We've also used the IIS Web App Deploy task with the XML transformation and XML variable substitution but the transformation isn't working because the web.base.config doesn't exist in the artifacts. I'm not sure why that is not being pulled in on build.
We'd like to know what best practice is for any or all of these different steps and how we can accomplish an on premise deployment successfully without committing config settings to source control. We'd also like to know how to execute this methodology for console apps as well.
Since the web.base.config file isn’t uploaded to source control and no in build agent machine, so you can’t use XDT Transform or XML transformation task/feature.
You can store the data in secret variable or Azure Key Vault and link it to release definition.
For example:
Add a new variable (click lock icon) or link Azure key Vault in release definition (e.g. connectionStrings)
Way 1: Check XML variable substitution option (Variables defined in the Build or Release Definition will be matched against the 'key' or 'name' entries in the appSettings, applicationSettings, and connectionStrings sections of any config file and parameters.xml. Variable Substitution is run after config transforms.), then the variable value will be replaced to the config files
Way 2: If the web app published as the web deployment package: override web deploy parameters (SetParameters.xml )by specifying value in Override Parameters input in release task. (You can add parameters.xml file to the project, then the related parameters will be added to SetParameters.xml file when generate web deployment package) Configuring Parameters for Web Package Deployment
Way 3: Using Replace Token task to replace the token in a file (e.g. #{mypassword}#) to the variable value (mypassword)

Config file for publishing web service

I have a Visual Studio web service application with the following solution structure (using VS2013 Community):
- [Solution] S
- [Project] S_Service
- S.amsx
- [Project] S_Lib
- File1.cs
- File2.cs
- app.config
The S_Service project is a simple web service project, with just a single asmx file with one WebService method. The project contains a reference to the S_Lib project, a class library to do all the work in terms of the business logic (the request processing).
In S_Lib I have an app.config file in which I store things like directories and file names for stuff which is used by the various components in S_Lib. When I am developing, changes to that file are picked up by the code ok.
Here's the problem: When I publish the S_Service project, the publish directory doesn't contain my app.config - only S_Service.dll and S_Lib.dll. After reading some other posts on StackOverflow (can't seem to find them now), I tried setting the build action on app.config to Content and to Copy Always. Great, this gets the file across to the publish directory, so it looks ok. But, once I deploy the whole lot onto IIS, any changes to the app.config file do not get reflected when the service is run. In fact I can delete the file completely from the IIS directory and it runs just fine. It's as though S_Lib.dll contains a compiled version of the configuration settings. This is no use, as I want to modify the config depending on the machine it's deployed on.
What do I need to do so that app.config is actually used at runtime and that changes are read on the fly?
Just as you wrote, S_Lib.dll contains compiles settings from the time when you set them in VS settings designer. Therefore it is still working (more or less).
You have a web service so you need a web.config. Add one to S_Service project. Then merge app.config content to web.config. Every time you change some setting in S_Lib project you will have to merge changes to web.config as well.
Or you could add app.config to S_Service project as a link by name web.config (not sure if it is possible to create a link with different name). Then when you change settings in S_Lib project they will be referenced in S_Service project automatically.
After failing to find a simple Visual Studio-based solution to do what I want, I implemented a more customised solution. In the library project, I replaced the config lookup method:
internal static string GetConfig(string key) {
return ConfigurationManager.AppSettings[key] as string;
}
with a new method that reads my own settings file (custom format), stored in the solution. It's not perfectly ideal as it means that each project in the solution has to have its own settings file, but it's simpler overall. If anyone is interested please leave a comment and I will elaborate on this solution.

Windows service cannot read parameters from the App.config

I created a Windows service used to execute automated procedures (.Net code) for multiple periodic operations, like backups, sanity checks, reports generation, etc. After building the project, I installed the service with installutil. Everything worked great.
I decided to move various "static" parameters for these automated procedures in the App.config file. I uninstalled the previous version of the service with installutil /u and built the new version of the project. In my build output folder, there's a AppName.exe file and a AppName.exe.config file, as I would expect. I installed the new version of the service, again with installutil from the VS 2012 Developer Command Prompt as an administrator.
The problem is that the service doesn't seem to be able to read the configuration file from the ConfigurationManager. The call for ConfigurationManager.AppSettings("paramname") doesn't fail, but the resulting parameter value is an empty string. As far as I know, the problem occurs for all parameters and not only for specific ones. The parameters are located in the <appSettings> section, under <configuration>, like I've done multiple times before in various projects.
I don't know if it can help, but my service runs on the LocalSystem account and starts automatically after installation and with Windows.
What did I do wrong?
Edit: I already tried uninstalling/re-installing the service (multiple times), like some stackoverflow answers suggests. Also, I'm not looking to update/refresh the file at runtime.
I solved this by setting the location of the config file in runtime. This enables me to place and name the config file where ever I want. I fetch the executing assembly path and then checks if the config file is there. Check the answer on this thread how to dynamically set the config file
This is how I fetch the executing assembly:
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var configFilePath = Path.Combine(path, "service.config");
Hope this helps!
Turns out I was getting the configuration value in a variable declared with the same name as the property I was using to store the value. For an unknown reason, I had no warning from the compiler. Since a Windows service cannot be debugged, the solution was to review the code/rewrite this part from scratch, and that's when I saw the error.

Windows service installer not reading App.Config file

I have added App.Config in my project.
I have a installer class(ProjectInstaller.cs) which needs to read values from App.config.
I am providing the keys .
Below is the sample Code :
ConfigurationManager.AppSettings["CONFIG_FILE"]
I am getting null values as per above code ,when invoked in Installer class.
But in App.Config file the value for the above key exists.
Try:
public string GetServiceNameAppConfig(string serviceName)
{
var config = ConfigurationManager.OpenExeConfiguration(Assembly.GetAssembly(typeof(MyServiceInstaller)).Location);
return config.AppSettings.Settings[serviceName].Value;
}
Google helps: http://social.msdn.microsoft.com/Forums/ar/winformssetup/thread/896e110e-692d-4934-b120-ecc99b01c562
the point is that your installer is NOT running as exe alone and an app.config called whatever you imagine will not be loaded by default as the exe running your installer is InstallUtil.exe and it would eventually search appSettings from the file InstallUtil.exe.config which is not yours and is not what you want, read the following and check the links...
If you invoke it through InstallUtil then the configuration file is
defined as InstallUtil.exe.config which is not what you want. You
could manually load the config file using Configuration but it will
probably be a little messy
The trick is in the execution context of the installer classes. If you
install your app using InstallUtil all code will be executed in the
same process as InstallUtil.exe. If you need to pass some data to the
Installer class during deployment you should use install parameters.
They are passed to the installer during execution of Install, Commit,
Rollback and Uninstall methods by the execution enviroment
(installutil, windows instller...). You can access there parameters
using InstallContex property ot the installer class.
There is a excellent artiicle on CodeProject regarding Setup projects
and parameters:
http://www.codeproject.com/dotnet/SetupAndDeployment.asp
Check out
http://msdn2.microsoft.com/en-us/library/system.configuration.install.installcontext.aspx
Davide Piras explained very well, why you can't use your app.config and suggests to pass your values as parameters.
I found a nice and helpful article on how to pass parameters to the installutil.exe and use them in the serviceInstaller or projectInstaller:
Part 1: Using Parameters with InstallUtil
Part 2: Configuring Windows Services with Parameters from InstallUtil
It explains very shortly how to pass arguments and how to read them.
For me the easiest solution was to create InstallUtil.exe.config file, and fill it up with content from application config file. Service installer successfully read from this config file.
I created my service by following steps described in: Host a WCF Service in a Managed Windows Service

Manage multiple app config files during development

I'm building an application that is used by several different customers. Each customer has a fair amount of custom business logic, which I have cleverly refactored out into an assembly that gets loaded at runtime. The name of that assembly, along with a number of other customer-specific settings, are stored in the application's configuration file.
Right now, here's what I have to do in order to debug the application for customer foo:
Go to the filesystem in my project directory and delete app.config
Copy app.config.foo to app.config.foo - Copy.
Rename app.config.foo - Copy as app.config.
Tell Windows that yes, I want to change the file's extension.
Switch back to Visual Studio.
Open the Settings.settings item in my project.
Click "Yes" 13 or 14 times as VS asks me if I want to use the new settings that have been changed in app.config.
Close Settings.settings.
Okay! Now I'm ready to debug!
It seems to me that the rigamarole of opening Settings.settings is, or ought to be, unnecessary: I don't need the default values in Settings.cs to be regenerated, because I don't use them. But it's the only way I know of to make VS aware of the fact that the app.config file has changed, so that the build will copy it to the output directory.
There's got to be an easier way of doing this. What is it?
You can also let Visual Studio automate Robert`s approach by:
Define a Build Configuration for each client
In the post build event, simply xcopy app.config.xxx to your bin folder. Where XXX is the name of a Build Config accessible in VS. Something like: xcopy app.config.$(ConfigurationName) $(OutDir)/app.config
VS will drop a distinct build for your clients in separate folders, aolong with the proper config file.
bin/Client1/
bin/Client2/
You can refer this post for some good practices : Managing Multiple Configuration File Environments with Pre-Build Events
Thinking about the mess of managing multiple configuration files I made this tool: http://envride.codeplex.com/
Its purpose its exactly to make it easier to manage multiple configuration files in an automated way. I would be very pleased if you would take a look at it.
A couple of people suggested using multiple VS configurations, which I think would have worked, except that it would require me to rebuild the solution every time I switched between configurations.
What I did instead seemed a little stupid while I was doing it, but I've been using it for nearly a year now and it works extremely smoothly. In my project directly, I create a separate app.config.XXX file for each customer. The actual app.config file is used solely to generate Settings.cs - it has all of the correct setting names and their default values. It doesn't get copied to the build directories, ever.
Then I wrote a little program that lets me select a customer, and that simply goes through the directories for each project and, if I selected customer XXX, copies app.config.XXX to bin\debug\myprogram.exe.config and bin\release\myprogram.exe.config. As long as this program knows where the root of the solution is (I have to be a little careful whenever I branch the code), it works like a charm.
This thread is too old to represent current tools in VS.
You can use an addon that acts similar to web.debug.config but for app.config.
https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform
And for the same app.config transformations without addon.
https://www.linkedin.com/pulse/multi-appconfig-visual-studio-2017-benjamin-davis/
You may opt to define multiple Visual Studio solution configurations, one for each customer, and have customised MSBuild targets for your Windows app project.
I have documented the steps of how I handled this here. Multiple app.config files for deploying to different environments
After a little digging and work around I got my Test project working with multiple configurations,
In the Configuration Manager, create the configurations you need
Copy paste your app.config and add the name of the configuration, in my case is AHI, FIV, MGC, so my config files look like: App.AHI.config, App.MGC.config, App.FIV.Config. You can name it how ever you wanted, but keep the same convention
Add a Post-Build event. In my case it would look like: xcopy $(ProjectDir)app.$(ConfigurationName).config $(TargetDir)$(TargetName).dll.config /y
here is my post, so you can read it with more details
Running a Test Project with Multiple Configurations

Categories