Skip to content

Code Contributions Guideline

Oleg Shilo edited this page Nov 28, 2017 · 7 revisions

If you want to contribute to the project then grab the latest code from Git and after you are happy with your implementation create the PullRequest.

As an architectural guide line there are few points that are not necessarily obvious:

Avoid bluntly implementing WiX schema
Wix# isn't a C# binding for WiX. It is a new API interface (an adapter) that is an attempt to shield user from the need to deal with the complicated WiX XML schema.

  • WiX maps (and works) with MSI tables (e.g. "need to add entry in the CreateFolders table").
  • Wix# maps deployment requirements (e.g. "need to deploy file into Program Files"). Wix# and WiX are ultimately related but they are working on completely different levels and serving very different purpose. This is the reason why Wix# does not deal with many WiX entities (e.g. Component). You can read more about the Wix# fundamental purpose on InfoQ

Push XML generation into Wix# entities
When possible place XML emitting routines in the corresponding entities. Initial Wix# code architecture was revolving around Compiler class. Today, when the volume of the codebase is much higher the Compiler.BuildWxs is becoming a heavy weight routine. Thus, it's desirable not to overload it with new XML emitting functionality. All recently added types contain ToXml() method that Compiler is using to obtain the XML. Thus Compiler is mainly responsible for the placement of this XML but not for its generation. The Compiler.ProcessCertificates and Certificate.ToXml is a good example for illustrating the point. The following is the Certificate.ToXml implementation:

public XContainer[] ToXml()
{
    var element = new XElement(WixExtension.IIs.ToXNamespace() + "Certificate");

    element.SetAttribute("Id", Id)
           .SetAttribute("BinaryKey", BinaryKey)
           .SetAttribute("CertificatePath", CertificatePath)
           .SetAttribute("Name", Name)
           .SetAttribute("Overwrite", Overwrite)
           .SetAttribute("PFXPassword", PFXPassword)
           .SetAttribute("Request", Request)
           .SetAttribute("StoreLocation", Enum.GetName(typeof(StoreLocation), StoreLocation))
           .SetAttribute("StoreName", Enum.GetName(typeof(StoreName), StoreName));

    return new[] { element };
}

"EventSource" element support is another good example of extending WixSharp with the support for new WiX elements.

This example is particularly useful as it demonstrates an alternative technique for automatic generation of the required XM based on class members marked with the XML attribute. Thus you don't need to call SetAttribute for all your class members:

public class IniFileElement : WixEntity
{
    [Xml]
    public IniFileAction? Action;
    [Xml]
    public string Directory;
    [Xml]
    public string Key;
    ...
    public XElement ToXml()
    {
        var retval = this.ToXElement("IniFile")
                         .SetAttribute("Id", this.Id);
   
        return retval;
    }
}

Take advantage from an extensive XML manipulation Wix# API
The Wix# XML fluent method extensions allow simple XML manipulations without dealing with namespaces. Thus all lookup operations are based on the matching LocalNames instead of Names. For all practical reasons it is more convenient than specifying the namespaces all the time. The extensions map all major lookup operations:

//XContainer.Single equivalent
document.FindSingle("Package");
 
//XContainer.Descendants equivalent
document.FindAll("Package");
 
//XPath equivalent
document.Select("Wix/Product/Package");

The SetAttribute extension is smart enough to decide if the attribute needs to be created, updated or not changed depending on its existence and the value passed by the developer. SetAttribute can process key/value pair(s). It also handles nullables (e.g. bool? is not added/set unless it has a value). And it also translates bool into a WiX compatible "yes/no":

//This is an extended fluent version of XElement.SetAttributeValue
element.SetAttribute("Count", 10)
       .SetAttribute("Title=Testing")
       .SetAttribute("Compressed=yes;SummaryCodepage=Windows-1252;Languages=1033")
       .SetAttribute("KeyPath", globals.UsingKeyPath);

When possible document your contribution
Xml code documentation (at least for public members) is obviously desirable. GhostDoc can be a great help. Also when it's applicable create a "Hello World" style sample in the sample folder. If you do so then UnitTesting will automatically run your build.cmd during the test.