C# Extension Methods for Biml
Why This Pattern Matters
Moving custom C# code into a separate code file already pays off in reuse and editor tooling. Turning those helpers into extension methods goes one step further: the helper looks and feels like a built in method on the Biml object it operates on, which keeps the calling Biml short and removes the need to remember which helper class owns a method.
What an Extension Method Is
An extension method adds a method to an existing object without modifying the original type. Once defined, the extension method is called as if it were declared on the object itself. Many built in Biml methods follow this pattern. For example, 'GetBiml' is an extension method, which is why it can be called on a package node:
<#=package.GetBiml()#>
Custom extension methods are called the same way:
<#=package.GetSomeCustomDetail()#>
Starting Point: A Helper Method in a Code File
A typical helper method in a Biml C# code file takes a Biml object as a parameter and returns a derived value. The example below builds a standardized table name from the schema and table name:
using Varigence.Languages.Biml.Table;
public static class NamingStandards
{
public static string GetCanonicalTableName(AstTableNode table)
{
return table.Schema.Name.ToUpper() + "_" + table.Name.ToUpper();
}
}
To call this helper from Biml, the class name has to be supplied along with the parameter:
<#=NamingStandards.GetCanonicalTableName(table)#>
This works, but the call is noisier than it needs to be.
Promoting the Helper to an Extension Method
The conversion is a single keyword. Adding 'this' in front of the first parameter signals that the method extends the type of that parameter:
using Varigence.Languages.Biml.Table;
public static class NamingStandards
{
public static string GetCanonicalTableName(this AstTableNode table)
{
return table.Schema.Name.ToUpper() + "_" + table.Name.ToUpper();
}
}
The class still has to be 'static', and the method still has to be 'static'. The 'this' keyword on the first parameter is the only addition.
Calling the Extension Method From Biml
The Biml file references the code file in the usual way and then calls the new extension method directly on the table node:
<#@ code file="NamingStandards.cs" #>
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Packages>
<# foreach (var table in RootNode.Tables) { #>
<Package Name="<#=table.GetCanonicalTableName()#>" ConstraintMode="Linear">
<Tasks>
<ExecuteSQL Name="Truncate <#=table.GetCanonicalTableName()#>" ConnectionName="StagingDb">
<DirectInput>TRUNCATE TABLE stg.<#=table.GetCanonicalTableName()#>
</DirectInput>
</ExecuteSQL>
<Dataflow Name="Load <#=table.GetCanonicalTableName()#>">
<Transformations>
<OleDbSource Name="Source <#=table.SsisSafeScopedName#>" ConnectionName="OpsSource">
<ExternalTableInput Table="<#=table.SchemaQualifiedName#>" />
</OleDbSource>
<OleDbDestination Name="Destination <#=table.GetCanonicalTableName()#>" ConnectionName="StagingDb">
<ExternalTableOutput Table="stg.<#=table.GetCanonicalTableName()#>" />
</OleDbDestination>
</Transformations>
</Dataflow>
</Tasks>
</Package>
<# } #>
</Packages>
</Biml>
The class name no longer appears in the Biml. The helper reads as if it were a built in property of the table.
Summary
Adding 'this' to the first parameter of a helper method turns it into an extension method on the parameter's type. The change is small but the calling Biml becomes shorter, easier to read, and consistent with built in methods such as 'GetBiml'.