Friday, October 28, 2011

Data driven custom actions require two custom actions. The first custom action queries custom tables and evaluates business rules and then passes CustomActionData to the second custom action which then performs the operations needed. Windows Installer calls this script generation and script execution but I call it "brains" and "brawn". That is the first action has access to all the information needed and can think about what needs to be done yet it doesn't have the access rights to do the work. The second action has all the rights to do the work but doesn't have enough access to teh MSI handle to be able to decide what needs to be done.

So just how does the brain communicate with the muscle? Through the CustomActionData property.

Today I want to demonstrate a lightweight technique of transporting complex instructions through this property using JavaScript Object Notation aka JSON.

Let's say I wanted a custom action that could create local user groups and I wanted it to be data driven. First I'd start off with defining custom tables that can express the
requirements:

<ColumnId="Description"Type="string"Width="255"Description="Description of Group"/>

<Row>

<DataColumn="Group">groupRockers</Data>

<DataColumn="Component_">SomeComponent</Data>

<DataColumn="Name">Rockers</Data>

<DataColumn="Description">People who rock!</Data>

</Row>

</CustomTable>

This table basically says let's create a group called Rockers when SomeComponent is being installed. Now let's write some code. The brain needs to be able to communicate with the bronze so let's start with creating something they can both understand. A POCO class ( Plain Old C# Object ) that describes a Group:

We query the Groups table and then iterate through the rows. During this we evaluate if the component is being installed and if it is we generate a Group class and add it to the Groups list. Finally we serialize the List of Groups to JSON and put it in the CustomActionData collection as the Groups KeyValuePair.

So what does this CustomActionData string end up looking like? Let's look at the Windows Installer log:

We grab the value of the Groups KeyValuePair from the CustomActionData property and then deserialize it back into a List of Group. Then we iterate through the list and call the API needed to create the group(s).

So there you have it. Beam me up! A simple contextual example of how to use JSON in your installer. It turns out JSON isn't just for the web guys.

Disclaimer: This code was thrown together in about 30 minutes and has not been thoroughly tested. I'll be improving it over time and if you'd like a copy you can contact me via email.