Wix and file search in installdir - windows

I try to create installer for postgresql zip with binaries. On first installation I run initdb and it initializes postgresql cluster and create data folder. On removing my app this data directory doesn't remove. On next installation in the same dir initdb fails because directory is not empty.
I want to search file [INSTALLFOLDER]/PostgreSql/postgresql.conf and if it exists than ignore initdb custom action.
I can't use DirectorySearch because it is before INSTALLFOLDER exists. I read that there is a way to call directory search via custom action but I can't find any info about it.
How I can check that postgresql cluster has initialized already and skip init db custom action.

One solution would be to create an immediate execution custom action to check for the existence of the file. If so, set a property and use that property in a condition in your initialization custom action.
In the C# managed custom action example below, it takes the value of "SOMEPROPERTY" and if the corresponding directory exists, sets the property RUNINITDB=1. You could then use RUNINITDB in a condition in your initialization custom action. If the property RUNINITDB exists, then run your custom action.
[CustomAction]
public static ActionResult CheckInitDb(Session session)
{
session.Log("Begin CheckInitDb");
string dir = session["SOMEPROPERTY"]; //or you could figure this out programmatically
if(!Directory.Exists(dir))
{
session["RUNINITDB"] = "1";
session.Log("Setting RUNINITDB bit.");
}
return ActionResult.Success;
}
To create the custom action project above, create a new Visual Studio project and under the Windows Installer XML templates, select C# Custom Action Project.
To reference the custom action in your installer XML source code, assuming the custom action is in a dll named InstallHelper.CA.dll, you may have something similar to the code below. Note the custom action CallToRunInitDB will only run if the property RUNINITDB is set.
<Binary Id="InstallHelper" SourceFile="InstallHelper.CA.dll"/>
<CustomAction Id="CheckInitDb" BinaryKey="InstallHelper" DllEntry="CheckInitDb" Execute="immediate" Return="check"/>
<InstallExecuteSequence>
<Custom Action="CheckInitDb" Before="InstallInitialize">NOT (REMOVE ~= "ALL")</Custom>
<Custom Action="YourCallToRunInitDB" After="InstallInitialize">RUNINITDB</Custom>
</InstallExecuteSequence>
If you are unfamiliar with WiX managed custom actions you may be able to find some other sample code on SO: https://stackoverflow.com/search?q=wix+managed+custom+action

Related

Application_BeginRequest Event in global.asax in sharepoint

First, I need to know where I can find global.asax file. I have already build Sharepoint Site, Now I need to create New Project in Visual Studio and then I need to trigger Application_BeginRequest so that I can get the User's Properties when Application Runs. So, how to find this file and how to inherit this to get Application_BeginRequest Event to run.
SharePoint default global.asax file path:
To custom http module in SharePoint, create a class inherit from IHttpModule and register it into SharePoint config file.
Demos:
https://www.c-sharpcorner.com/UploadFile/40e97e/sharepoint-and-http-module/
https://blogs.technet.microsoft.com/sharepointdevelopersupport/2015/02/18/when-using-a-custom-http-module-and-you-create-a-view-for-a-list-you-get-an-error-saying-cannot-complete-this-action-please-try-again/

attaching unit test data to unit tests in visual studio

I heavily make use of unit tests for my developer needs (POCs, unit tests, etc). For one particular test method there was a line that went...
var file = #"D:\data\file.eml";
So I am referencing some file on my file system.
Now in a team when other people are trying to run my "personal" tests (POCs or whatever) they don't have a reference to that file in that path...hence the tests fails. How we'd have to normally make this work is to provide the test data, and allow the user to modify the test code so that it runs on his computer.
Any visual studio way to manage this particular problem?
Whats the benefit in this? Well, people can review the test data (email in my case) as well as the method I wrote for testing, and can raise defects in TFS (the source control system) relating to it if need be.
One way I often handle data files for unit test projects are to set the data files as Resources. (* Note that this link is for vs2010 but I have used this approach through vs2015RC).
In the project with the data file: Project -> Properties -> Resources and choose to add a resource file if you the project doesn't already have one. Select Files in the resource pane and click Add Resource or just drag and drop your data files onto the resource manager. By default resources are marked internal, so to access the resources from another project you have several ways:
In the assembly with the data files, add the following to your AssemblyInfo.cs file and this will allow only specified assemblies to access the internal resources
[assembly: InternalsVisibleTo("NameSpace.Of.Other.Assembly.To.Access.Resources")]
Create a simple provider class to abstract away the entire Resource mechanism, such as:
public static class DataProvider
{
public static string GetDataFile(int dataScenarioId)
{
return Properties.Resources.ResourceManager.GetString(
string.Format("resource_file_name_{0}", id));
}
}
Change the resource management to public (not an approach I have used)You can then access the data file (now a resource) from a unit test such as:
[TestCase(1)]
public void X_Does_Y(int id)
{
//Arrange
var dataAsAString = Assembly_With_DataFile.DataProvider.GetScenario(id);
//Act
var result = classUnderTest.X(dataAsAString);
//Assert
Assert.NotNull(result);
}
Note that using data files as resources, the ResourceManager handles the file I/O and returns strings of the file contents.
Update: The test method in the example above is from an NUnit project and is not meant to imply process, but a mechanism by which a data file can be accessed from another project.
What you'd normally do is add the file to your project and check it into TFS. Then make sure the item's settings are:
Build action: Content
Copy to output: If newer
Then put an attribute on your Test method or Test class:
[DeploymentItem("file.eml")]
You can optionally specify an output dircetory:
[DeploymentItem("file.eml", "Directory to place the item")]
If you put the files in subdirectories of your test project, then adjust the attribute accordingly:
[DeploymentItem(#"testdata\file.eml")]
The file will be copied to the working directory of your test project and that makes it easy to access from your test code. Either load the file directly, or pass the path to any method that needs it.
If you tests expect the files in a specific location you can use a simple System.IO.File.Copy() or System.IO.File.Move() to put the item in the place you need it to be.
The process is explained here on MSDN.
I suppose the most straight forward way is to simply add whatever to the project, and set the correct value for Copy To Output Directory. In other words, say your data is in a text file.
Add text file to your test project
Right-click to access properties window
Set copy to output directory field as Always or Copy if newer.
Now if you build the test project, the file gets copied to your output directly. This enables to write unit test code of the fashion:
var dataFile = File.OpenRead("data.txt");

How can I validate custom dialog input in a .NET Installer class?

I have a VS 2010 Setup project.
In the setup project I have a custom dialog, and a custom action.
Both work, I can even debug my custom action and it receives correctly the input the user provides in the custom dialog.
I would like to validate user input and only allow user go to next step if the input is valid.
I can show a messagebox with MessageBox.Show, but how can I prevent to go to the next step until the user corrects the input?
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
string myInput = Context.Parameters["MY_INPUT"]; // Value from custom dialog
if (myInput ..... )
{
// Not a valid input, we do not want to proceed to the next step
MessageBox.Show("Not a valid input, please correct it");
// What to do here?
// How can I tell the Installer do not accept this input?
}
else
{
// Valid input...
}
}
Thx for answers
The simplest method of achieving this is set a property from your custom action and use that property to condition the NewDialog event that is called when the user press the "Next" button, so the event does not get executed if the condition is not true.
A .NET Installer class custom action cannot set the property directly from its code, but you could use your C# code to write another type of custom action that can get/set properties, as in this example: http://www.advancedinstaller.com/user-guide/qa-c-sharp-ca.html
EDIT: You can do that by editing the MSI generated from VS with Orca, however, this is quite painful I would say as you need to edit multiple tables manually, like Binary, CustomActions, ControlEvent. Here is something to get you started with that:http://support.microsoft.com/kb/255905
Another method would be to switch creating the setup package with a more advanced setup authoring tool. If you want to go with a free and powerful one I recommend WiX (http://wix.sourceforge.net/), it will take you some time to get started with it but its way faster than editing in Orca. The commercial alternative, which will allow you to edit your project even faster and much easier is Advanced Installer (http://www.advancedinstaller.com), but you will need an Enterprise license for what you require to accomplish.

WIX: persist session data between C# CustomActions and subsequently displayed WIX Dialog

I am new to WIX and have been tasked with creating an installer that does
the following:
*Deploys a build of our application without overwriting the App.Config file
for the application
*Loads the key/values in the App.Config file and prompts the user with the
"defaults" (existing values) and allows them to modify them before finishing
*SAVES the values the user provided (or defaults if the user made no
changes) back to the App.Config file for use with the application.
I've got the WIX dilalogs and custom actions laid out successfully where
after InstallFinalize, my "LoadDefaultOptions" CustomAction is executed,
which successfully takes the installation directory and the app config file
name, loads it in an XML reader, and parses the key/value pairs, setting
them into the session variable in this manner:
session[key.toUpper()] = value;
My custom action(s) are defined as:
<CustomAction Id="LoadDefaultOptions" Return="asyncWait" Execute="immediate" BinaryKey="aeserverDbDialogPackage.dll" DllEntry="LoadDefaultOptions"/>
<CustomAction Id="SetConfigOptions" Return="check" Execute="immediate" BinaryKey="aeserverDbDialogPackage.dll" DllEntry="SetConfigOptions"/>
The LoadDefaultOptions executes as such:
<Custom Action="LoadDefaultOptions" After="InstallFinalize" />
I have the custom dialog edit properties set like this:
<Control Id="CCPDbConnString" Type="Edit" X="20" Y="62" Width="150" Height="18" Property="CCPCONNECTIONSTRING" Indirect="no" />
There's a matching Property tag earlier in the WXS file like this:
<Property Id="CCPCONNECTIONSTRING" Secure="yes" ></Property>
...And the LoadDefaultOptions customAction overwrites the session var like
this:
session["CCPCONNECTIONSTRING"] = <value parsed from file>;
According to session logs, this works as expected, the xml parse works, and
the session vars are set.
My problem is when my custom dialog comes around to prompt the user with
those stored defaults AFTER the LoadDefaultOptions CustomAction has run.
The ORIGINAL property values of the session variables seem to have "stuck"
instead of being overwritten by the custom action that loaded the defaults
via the xml file and stored them in the session. (they are blank as their
original properties are defined, or in the case I define them otherwise,
they show those values instead of the session written values)
How do you get Dialogs to "read" overridden session variables by
CustomActions?
Ultimately I want to load those values from the app config, prompt them back
to the user in an optional dialog prompt off the exit screen (which works so
far, aside from not getting updated session vars), and then on command from
that prompt dialog, run another custom action to re-write the App.Config
file with the settings provided from the custom dialog...
I just can't get the session vars to PERSIST!!!
Any ideas? am I completely off base attempting to use the session in this manner? how else could I parse the app.config file, and allow an installation user to change app settings if not by session?
Apparently, part of what I'm trying to do is more or less impossible... You cannot modify the session vars in the InstallExecuteSequence for use in dialogs... this can only be done in the InstallUISequence...
Therefore, I cannot READ AND PROMPT USERS FROM my App.Config on first installs as the file will never have been deployed during the period of time that it would be possible to do.... Seems the only time this would work is during an UPGRADE where the App.Config file exists from a prior install in the same location from which the original install occurred.
I'm going to go at it from this point of view, with NO (or hard-coded) default settings during a fresh installation, with an attempt to parse and use as defaults EXISTING app.config settings during upgrade installations... That should take care of my requirements!
If you schedule your custom action after InstallFinalize it won't run elevated during a managed installation / UAC type story. I also have a question, have you considered moving this configuration data to the application where it's easier to manage it as a first-run pattern?

VS2010, MSDeploy and declaration of parameters

I'm trying to deploy an ASP.NET MVC 2 app using MsDeploy. I use VS2010 to generate the package as a ZIP. Inside that ZIP is a parameters.xml file that declares the parameters that I can set.
I want to be able to set more parameters, using the auto-generated deploy.cmd file like this:
MySite.deploy.cmd
"-setParam:name='IIS Web Application Name',value=MySite"
"-setParam:name=IisVirtualDirectoryPhysicalPath,value=C:\inetpub\MySite"
"-setParam:name=httpBinding,value=*:80:www.mysite.dk"
That works fine, except for the httpBinding param. That is because that parameter is not declared inside the parameters.xml file that is added to the ZIP container.
I could go and add that parameter declaration manually, but isn't there a way to do it from the command line and have it declare parameters I have in another XML file?
Are you saying that the value param was not declared when the package was created? If so then I think you would have to add it. Either manually or you can use the -setParam switch and sync the package from and to itself. If you use -setParam with a name which was never declared as a param to begin with I'm pretty sure that value is just ignored.
I'm only just looking at this, but is the section on MSDN about the matching of declareParam with setParam the way to go ?
I'm using MsDeploy to update my deployment zip following the idea in this stackoverflow post
Apologies if I'm completely off on this

Resources