Click Once Deployment and Solution Configuration - c#

Is there an easy way to configure different configuration files for publishing with click once in a WinForms application? I'm looking to create a Settings/app.config depending on the solution configuration, ie: Debug/Release, and have the same setting keys, but pointing to different machines/db's for development/production connections for each solution configuration.
Thanks,
Mark

Sadly, unlike ASP.Net VS2010 does not support different config files for Debug/Release. Its frustrating that the various VS teams don't co-ordinate a little better as the feature in ASP is very useful.
Really, the only place to change the app.config for your debug vs release is in your build process after running msbuild.
I wrote and sell a piece of software called ClickOnceMore that supports different environments (debug, staging, QA, production etc) using a macro approach. You can define a different value for each macro depending on the build type (which can be passed in on the command line). You can then use the value of those macros to either pick up a different config file or to replace values in a config file template.
A simpler approach in ClickOnceMore lets you use the built in macro [DebugOrRelease] to pick up a different config file for Debug or Release builds.
You can download a free trial of ClickOnceMore here: www.clickoncemore.net if you have any problem making your scenario work just let me know, it should be able to do exactly what you want to do.

Related

Build/Release flow on VSTS with MSI deployed desktop app using configuration transforms

We are in the process of implementing a DevOps strategy for our client deployed desktop app (winforms). Until now, we used SlowCheetah to do our config transforms (ex: select QA from config manager, app.QA.config is automatically swapped in, do the build, deploy MSI to QA machines with SCCM).
We are trying to leverage Azure DevOps to automate this process and I have run into a roadblock. I want to do 1 build, and a release pipeline of Dev --> QA --> UA --> Prod, but since the config transform is only run on build Im not sure how to do this.
The MSI would only be generated for the current selected config, so the drop in the release step would only have 1 MSI (with the config already packaged and no way to change it).
I know having the build step build the solution 4 times (one for each config) would work - the drop would contain all 4 MSIs, but that seems silly.
I can't just build the setup project on the release pipeline either as only the DLLs are available in the Drop, not the project files. How can I accomplish this?
Thanks!
We had exactly the same problem building MSIs from a Visual Studio solution that contained a WiX Installer project, using config transforms on the app.config to replace the configuration.
As you suggested, we originally went down the route of running an Azure DevOps build pipeline with multiple builds for every configuration in the solution, but this quickly became inelegant and wasteful as not only did we require builds for (dev/stage/qa/live) but also had configurations that applied to multiple customers, which ended up in 12 + configurations in the solution and really long build times.
Replace config within the MSI
The solution we ended up with, as alluded to in a previous answer, was to build the MSI only once in a build pipeline, copy the MSI along with all our replacement app.config files to the drop folder, and then run a custom application within the release pipelines to forcibly replace the Application.exe.config inside the MSI. Unfortunately, this isn't as simple as just 'unzipping the MSI', replacing the config and then 're-zipping' within a release task because the MSI uses a custom file format and maintains an internal database that needs to be modified properly.
We ended up creating a custom C# .NET console application using the method posted in this stack overflow answer, which we then hosted on our on-premises build agent so that we could run a simple powershell task within our release pipeline that called our custom console application with some relevant parameters:
"C:\BuildTools\msi_replace_file.exe" -workingfolder "$(System.DefaultWorkingDirectory)/_BuildOutput/drop/Application.Installer/bin/Release/" -msi "Application.Installer.msi" -config "Application.exe.config"
We then had a release pipeline stage for each 'configuration' that performed these basic steps:
There are various other methods for replacing a file in an MSI, as described in this question, but we chose to create a C# application using the utilities within the Microsoft.Deployment.* namespace that are provided as part of the WiX Toolset. This would guarantee compatibility with the version of WiX we were using to build our installer in the first place and gave us full control of the process. However, I appreciate that this approach is quite brittle (which I'm not happy about) and not especially scalable as its relying on a custom tool to be hosted on our on-premises build agent. I intend to improve this in the future.
You should also be aware that hacking the MSI in this way could cause problems in the future, especially if you change your tool-chain or upgrade to a later version of WiX.
Building the MSI from the release pipeline
I do not personally like the idea of copying the required dlls/assets to the drop location and then 'building' the MSIs within the release pipeline, because for us the act of building the WiX project was very much part of our 'build process' and was integrated into our visual studio solution, so it felt like moving the creation of the MSI to the release pipelines was counter intuitive and would also potentially require us to create custom tasks on the build agents to run the WiX CLI tools (heat.exe, light.exe, candle.exe) against a version of our WXS file or have build steps that just built the wixproj file instead of the whole solution. However, I can see how this alternative approach may be suitable for others and I think is equally valid depending on your circumstances.
What we did a few years back is maintaining a sub-folder that contains all the environment config files. Using a Custom Action at install time and supplying that particular environment on the command line the custom action would extracts the config file from the environment matching folder in the configFils.zip.
Folder structure similar to this in the ConfigFiles.zip file.
/Dev1/app.config
/Dev2/app.config
/Prod/app.config
MsiExec.exe /i YourMSI.msi /TargetDir=C:\Yourfolder /Config=Prod
Custom action would extract and place the app.config from the Prod folder.
To do this in the release pipeline you've really only got a couple of choices:
Break the MSI apart and re-import the right config and repackage (don't know how easy this would be as I don't know MSI, but have taken this approach with other packages which are effectively .zip)
Build the package in the release pipeline. You say the files aren't available in the drop but you are in control of this from your build pipeline (assuming this was done with Azure Pipelines also). You can either change your pipeline therefore to copy the needed files (with a copy task) into the place you create your drop from which is usually $(build.artifactstagingdirectory). Alternatively if you don't want to mix these files into your drop you can create a second artifact drop (just put in another publish artifact task in for this). If I took this route I would copy the files that are in $(build.artifactstagingdirectory) today into $(build.artifactstagingdirectory)/packagefiles and the project files needed to package up the MSI into $(build.artifactstagingdirectory)/projectfiles and point the two publish artifacts tasks to either one of these directories.
Once you have the drops including the files to build your MSI you'll need tasks to replace in the right config and then an MSI packaging task and you should be done.
Another way of doing this:
Instead of placing environment dependent settings in the App.config or any of its transforms, you could configure your app dynamically at runtime.
This would however require your app to get some clue from the target system so that it knows in which environment or on which host it is running.
Example:
ASP.NET Core applications assume the existence of a „ASPNETCORE_ENVIRONMENT“ environment variable. If it is not present, the applications assumes it runs in production.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-5.0
Providing such an environment variable should‘t pose a problem when you have access to the hosts anyway.
Simply add a step at the beginning of your release pipeline to set up the environment variable and set its value to the name of the stage you’re trying to deploy to (development/testing/etc).
That way you can build your MSI once in the build pipeline and deploy on as much environments as you like.
Of course, this requires you to prepare your app for that target environment ahead of time.

Visual Studio 2008 C# Deployment Variables

I inherited a project, that was just a modified sample project from Honeywell.
Whenever you make a build, you have to uncomment lines for variables setting the client, the server url, and the device the build is being made for. Then, you need to go into the solution's Cab project, and change the application name (based on client / server), and change the shortcut's name to match. After the build, I then need to rename the CAB file it created. And usually I have to do this for a combination of 5 servers, 3 clients and 2 devices.
It's all very redundant. My absolute ideal would be to pick each ( or the combination "Client Server Device" ) from a dropdown ( such as the configuration ), then simply make the build. Most of my googling around suggests I can make this much more streamlined using "Configurations", but I can't seem to find instructions on how to actually set it up.
I am limited to Visual Studio 2008 due to .NET restrictions (v3.5) on the Honeywell SDK.
Any help would be greatly appreciated.
You need to separate out build-time parameters (baked into the code at build time), from install-time parameters (determined when the software is installed), from run-time parameters (configurable at run-time, e.g., after installation). Typically things like server urls are environment specific and are should therefore be determined at install-time, not at build-time as this project you inherited seems to be doing. You need some sort of installer to enable the configuration of the install-time parameters, and possibly an administration utility to enable the configuration of any run-time parameters after installation.
The goal is to be able to build once, but install many times (into different environments with different configurations).
There are a lot of tools available to help with this. This is a list of build automation tools: https://en.wikipedia.org/wiki/List_of_build_automation_software#Continuous_integration_tools. And here is a list of tools for writing installers: https://en.wikipedia.org/wiki/List_of_installation_software.

Simple Update Tool

I am looking for a very simple update tool that can be sent out to various sites and update their applications and database.
I need the tool to be configurable by non developers. I.e. support staff.
The tool will need to be able to copy DLL files into the program location.
It should be able to find the program location, and read in the configuration file to find the database location and connection details.
It should be able to update the configuration files.
If this tool can support roll back it would be an added extra.
I am not looking for a tool like install sheild etc. as this will require a developer to use.
Open source projects, freeware or commerical applications are all acceptable.
If you have any idea, tips or suggestions they are all welcome.
This is the classic use case for having an installer for your application. The installer will copy your DLLs etc into a folder. You can then author updates or patches which can do an update of your application with newer files.
I'm not sure what you mean by "developer use". Do you mean a developer would have to create the installer project? If so, that is not really true. but yes, they would have to learn the tool is it is support you want authoring your install/updates.
There are some free tools to build windows installers. Wix is one and Inno Setup is another.
As far as updating SQL databases, Red Gate's packager is pretty simplistic. It does nothing more than wrap an update script into an executable. You can do this on your own of course if you have a tool to create a change script. The problem here is that the target database must always match the one you generated the change script on.
We use DbGhost PackagerPlus. This tool actually bundles the compare engine so that the target database can be any previous version and it will still be updated. The packager call also be called from the command line so you can run it from your installer.

Visual Studio 2008 - Issues with publishing C# Console Application

I have a C# console application written in Visual Studio 2008.
Usually I just build the application and then copy the files from the 'Release' folder but this time trying to do it 'properly' by publishing the application.
I went through the 'Publish Wizard' and end up with a 'Setup.exe' file in the specified folder. When running this setup file on another computer the install fails and indicates via a error message that:
Cannot download the application. The Application is missing required files...
When I select the 'details' button the error log shows that the program was trying to download files from the last version directory (ie 1_0_0_4).
What am I doing wrong? (aside from being tired...)
Show I de-activate the version auto-incrementing?
Unless you have a valid reason to do so, I would abandon the publishing and just go back to the XCopy installation. (And by Valid, I mean something other than someone told you that it's the "proper" way to do it.) I base this advice on the following arguments:
We used ClickOnce for all our WinForms apps for a while, but eventually it got to be more trouble than it was worth. For one thing, you need to deal with the security certificates. We had issues when we replaced a server with a new one with a different name, then we had issues when we replaced our development machines, etc.
You said this is a console application. ClickOnce publication seems to be overkill for a simple console application unless there are third party dependencies that you need to include in your install.
Don't get me wrong, I liked using ClickOnce for the ease of putting updates out there, and we use it still when it's the best option. However, in your situation, it looks to me like XCopy deployment should be sufficient for a simple console application.
Not knowing what you choose in the wizard, web or CD, the setup.exe file needs to be able to reference it's installation files. If using the CD method, you will notice in the output directory you revision directories, e.g. 1_0_0_4, where each revision of your app is kept. I agree with #David_Stratton, and unless you really need to use one-click publishing, don't. Just use xcopy (robocopy), zipfiles, etc. It will greatly reduce your stress levels down the road.
Everything David Stratton has stated is correct. ClickOnce is overkill for what you're trying to do, and publishing through Visual Studio has always given me headaches.
I might recommend taking a look at NSIS if you're looking for generating an installer for others. It's relatively simple to generate full installers that merely grab files from your /Release/ directory, with plenty of sample code for getting an installer working quickly. Once you have your working script, making your installers are as simple as a right-click and clicking compile.

Is there a clean way to set a VS 2008 setup project's properties at build time?

I have an Office add-in project with a setup project for deployment (using VS 2008), and I need to build the same product in a few different flavours.
I'm looking for a good way to make the installer resources dependent on the build configuration. The product name, manufacturer, manufacturer url, author, etc., etc. properties should be different for each of the builds. Also, the images shown in the installer UI will be different as well.
If possible, I'd like to do this without creating a new project for each different UI.
I believe this could be done using the ORCAS tool and build events, but this approach seems overly complex and fragile.
Does anyone have any ideas on a clean way to go about doing this?
Another option, although it is a bit more work up front, is to throw the setup project out the window and use e.g. WiX instead (http://wix.sf.net)
You could manually make copies of the vddproj file and edit them with a text editor. I admit, this is not a very robust solution and you would have to repeat this step every time the content of your setup changes.
I think the best way is to create hand-made NAnt script.
Explaination:
NAnt is a build tool that besides building can execute scripts. By creating scripts and targets you can modify files that are checked out from your SCM, and then order them to build. Check out official NAnt site for more informations.

Categories

Resources