Vision
A Domain-Specific Language: using WPCL 2007
August 3, 2007
A domain-specific language is a language that is closely tied to a problem domain, as opposed to general purpose languages such as UML. DSLs can be textual or graphical and are intended to make solving a very specific problem easier than a general purpose language ever could. DSLs are typically high-level and often need to be transformed in some other form before they are really useful. A common example of this is some kind of model that can be transformed to code, which in turn can be compiled into an executable.
The WPCL 2007 stands for the Web Part Connection Language 2007, a DSL that integrates with Visual Studio.NET 2005 and can be used to create ASP.NET 2.0 connectable web parts. The WPCL language:
The reason we have developed the WPCL is to make the creation of connectable web parts that can be used in a SharePoint 2007 environment (or, for that matter, every other ASP.NET 2.0 web site supporting web parts) easier. If you like the idea, you are welcome to download the WPCL, use it or send suggestions to us. In this post, you will learn how to install and use the WPCL 2007.
Tip If you need more information about creating connectable ASP.NET 2.0 web parts, please refer to MSDN (at http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.webparts(VS.80).aspx").
Installing WPCL 2007
If you want to install WPCL 2007, you need to have installed the latest release of Visual Studio 2005 SDK Version 4.0. At the time of writing, this is the February 2007 version (VsSDKFebruary2007.exe). Newer versions of the SDK are released regularly, check the web site http://msdn.microsoft.com/vstudio/DSLTools/ or go to the Visual Studio 2005 Extensibility Center (http://msdn.microsoft.com/vstudio/extend/) and download the latest release of Visual Studio 2005 SDK Version 4.0.
After installing Visual Studio 2005 SDK Version 4.0, you can download the WPCL 2007 here. The download consists of a zip file called WPCL2007.zip. The zip file consists of several files:
If you are missing a part of the DSL tools, setup.exe first runs DSLToolsRedist.msi to try to fix this. Do not depend on this; you really need to make sure you have installed the Visual Studio 2005 SDK Version 4.0 first. After that, the WPCL itself is installed on the client computer. If you need more information about the WPCL or want to check if updates are available, please refer to our web site at http://www.lcbridge.nl/download.
Double-click setup.exe to install the Web Part Connection Language. This opens the WebPartConnectionLanguage Setup wizard. Follow the instructions and complete the wizard.
Note The current version (version 0.1) of the WPCL 2007 only supports C#.
Creating a new WPCL 2007 Application
If you start up Visual Studio.NET 2005 after installing the WPCL, you will see that a new type of project appears in the New Project dialog, the WPCL 2007 Application. This is shown in Figure 1.

Figure 1
If you create a new project based on this template, you will notice that such a project contains two default files: test.wpcl and WebPartsTemplate.tt. This is shown in Figure 2.

Figure 2
The Test.wpcl file is used to create WPCL diagrams; WebPartsTemplate.tt is a text template that can be used to create C# code based on a WPCL diagram. If you want, you can add new WPCL diagrams to the project. Just right-click the project name and choose Add ~TRA New Item. Under the Visual C# Project Items node, you will find a new entry for a WebPartConnectionLanguage project item, as can be seen in Figure 3. We will discuss the creation of WPCL diagrams extensively in the rest of the post.

Figure 3
Near the top of the WebPartsTemplate.tt file, you will find a processor directive that refers to a WPCL model called Test.wpcl. This is shown in the next code fragment:
<#@ WebPartConnectionLanguageprocessor="WebPartConnectionLanguageDirectiveProcessor"
requires="fileName='Test.wpcl'" #>
If you let the text template refer to another WPCL diagram, the template will generate code based on that model. If you are happy with the way your WPCL diagram looks (again, this will be discussed in detail later), you can start generating code based on the diagram by right-clicking WebPartsTemplate.tt and choosing Run Custom Tool. This is shown in Figure 4.

Figure 4
As a result of this, a new output file is created. In this case, a C# class (.cs) file. This is shown in Figure 5.

Figure 5
Elements of the WPCL
If you open a WPCL diagram (.wpcl file), the WPCL adds two new sections to the Visual Studio.NET 2005 toolbox: WPCL General and WPCL Interfaces. Figure 6 shows both of these sections. The WPCL language contains several language elements that are divided over both sections.

Figure 6
You can use the language elements in the toolbox to create WPCL diagrams by dragging and dropping them to the designer canvas. In this section, we will discuss every language element of the WPCL.
Let’s start with the designer canvas itself. The canvas represents a WPCL model. If you click on it, the Properties window shows all properties that we have defined at the upper most level of the language. The current version only has support for a single property, called Namespace. This is the default namespace that is used for web parts (and optionally, interfaces) that are created during code generation (the time when a WPCL model is transformed to C# code).
In this post we will create several code examples using the WPCL, and we want a default namespace called LoisAndClark.TestConnections to be used within all of those samples. Figure 7 shows how to use the Properties window to define a default namespace within a WPCL model.

Figure 7
Note Although the validation rules of version 0.1 of the WPCL do not check for the presence of a namespace value, you should make sure you enter a value here.
Now, you can drop language elements to the canvas and build a WPCL model. The first language element that we’ll discuss is the WebPart element. The WebPart element represents an ASP.NET 2.0 web part and looks like Figure 8 when it is dragged to the designer canvas of a WPCL model. WebPart elements allow you to define a web part name. In this example, this name is set to WebPart1. This name will be used as the class name of the web part during code generation.

Figure 8
Web parts can have connections to each other, although there are some restrictions, such as the fact that a web part consumer is only allowed to have a single provider.
Note A limited set of validation rules is added to the WPCL that indicate flaws in the design of a WPCL diagram. The validation of a WPCL diagram is started by right-clicking the designer canvas of the diagram and choosing Validate All.
The Connection element of the WPCL enables you to define a connection between two web parts. The direction in which the relationship is drawn determines which web part acts as the provider in a web part connection, and which web part acts as the consumer. Connection elements allow you to define a Label, which is only used for clarity’s sake. You can use Labels to annotate a WPCL diagram, this information is discarded during code generation.
Figure 9 shows a web part connection between two web parts called WebPart1 and WebPart2. In this case, WebPart1 acts as the provider, WebPart2 as the consumer. The connection is annotated with a default comment, Connection1, which is only used in the WPCL model and is discarded once the code generation process starts.

Figure 9
Connected web parts need some kind of interface that let them communicate to each other. You can either use one of the predefined interfaces in the System.Web.UI.WebControls.WebParts namespace (either the IWebPartField, IWebPartRow, IWebPartTable, or IWebPartParameters interface), or you can define your own custom interface. In the WPCL Interfaces section of the toolbox, you will find four representations of the predefined web part connection interfaces and one you can use if you want to build a custom interface. The WPCL interface elements are shown in Figure 10. All elements have a Name property. In the case of the four predefined interfaces, this property is only used to annotate a WPCL diagram should you feel the need to. In the case of a custom interface, the name you specify will actually be used to generate a custom interface during code generation.

Figure 10
Web parts can be associated to interfaces. To be precisely, a web part provider always needs to be associated to an interface. In the WPCL, a web part consumer can optionally be associated to an interface, indicating that it is compatible with a given interface. For instance, a web part consumer associated to the IWebPartField interface indicates it supports providers implementing this interface.
The Implements element of the WPCL is used to associate web parts to interfaces, as can be seen in Figure 11. The Implements element has a property called Label that can be used to annotate diagrams. This information is discarded during the code transformation process.

Figure 11
Figure 12 shows a web part provider called MyProvider that implements a custom interface called CustomInterface1. The MyProvider web part provides data to a web part consumer called MyConsumer, which does not have an explicit relationship with any interface. In such a case, the WPCL assumes it is compatible with the interface implemented by its web part provider, in casu CustomInterface1.

Figure 12
Figure 13 expresses the same meaning as previous Figure 12. In this case, MyConsumer is explicitly associated to the CustomInterface1 interface, thereby declaring that this consumer is compatible with web part providers implementing the CustomInterface1 interface.

Figure 13
The final important part of the WPCL is the InformationObject element. InformationObjects in a WPCL diagram mean different things in different contexts, and can be associated to web parts or interfaces. This is explained in following table.
| Associated to | Context | Meaning |
| Provider web part | IWebPartField | Describes field used in connection. |
| Consumer web part | IWebPartField | Describes member variable that is used to contain provider field. |
| Provider web part | IWebPartRow | Refers to column in row of data. |
| Consumer web part | IWebPartRow | Refers to column in row of data. |
| Provider web part | IWebPartTable | Refers to column in table of data. |
| Consumer web part | IWebPartTable | Refers to column in table of data. |
| Provider web part | IWebPartParameters | Describes parameter used in connection. |
| Consumer web part | IWebPartParameters | Describes member variable that is used to contain provider parameter. |
| Interface | CustomInterface | Describes interface method used to provide data to consumer. |
Figure 14 shows what an InformationObject looks like once it is dragged to a WPCL diagram.

Figure 14
The InformationObject element contains several properties that allow you to describe a field, column, parameter, member, or method:
The Properties window can be used to set these properties, as can be seen in Figure 15.

Figure 15
Note Although version 0.1 of the WPCL does not check if you enter valid values for the InformationObject properties, you should ensure that you enter values here. Failing to do so results in the generation of invalid code, which is easy to correct at a later stage.
If you want to associate a web part to an information object, you can use the MapToInformation element of the WPCL. This is shown in Figure 16. The MapToInformation element contains a Label property that is used to annotate a diagram, this information is discarded during code generation.

Figure 16
You can use the MapCustomInterfaceToInformationObject element of the WPCL to associate an interface to an information object. This is shown in Figure 17. The MapCustomInterfaceToInformationObject element contains a Label property that is used to annotate a diagram, this information is discarded during code generation.
Information objects can only be associated to custom interfaces, not to the IWebPartField, IWebPartRow, IWebPartTable, and IWebPartParameters interfaces. This is because those interfaces have been predefined. For a custom interface, you will have to define exactly what it looks like.

Figure 17
In this section, you have learned about all the existing elements in the WPCL. In the following sections, you will learn how to use those elements to build connectable web parts.
Creating a connection using the IWebPartField interface
In this example, we have added two web parts to a WPCL diagram: MyFieldProvider and MyFieldConsumer. We have drawn a Connection relationship from MyFieldProvider to MyFieldConsumer, thereby designating MyFieldProvider as the web part provider. MyFieldProvider implements the predefined IWebPartField interface, indicating it is a Field provider. The field provided by MyFieldProvider is called ProviderValueA. MyFieldConsumer contains a member variable ConsumerValue that can be used to contain the value provided by MyFieldProvider. This is shown in Figure 18.

Figure 18
You can generate code based on this model by right-clicking WebPartsTemplate.tt (discussed in section "Creating a new WPCL 2007 Application"). The generated code can be retrieved (when you unfold WebPartsTemplate.tt) from the file called WebPartTemplate.cs.
The code for the MyFieldProvider web part that is generated by the WPCL based on this diagram looks like this (we have omitted namespace imports and the namespace declaration from this code):
public class MyFieldProvider : WebPart, IWebPartField{
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("This is LoisAndClark.WebPartConnectionLanguage.IWebPartField provider");
}
[ConnectionProvider("field provider MyFieldProvider")]
public IWebPartField GetFieldProvider()
{
return this;
}
public void GetFieldValue(FieldCallback callback)
{
callback.Invoke(ProviderValueA);
}
public System.ComponentModel.PropertyDescriptor Schema
{
get
{
return TypeDescriptor.GetProperties(this)["ProviderValueA"];
}
}
private string _ProviderValueA = "provider value a";
[Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
WebDisplayName("ProviderValueA"), WebDescription("Value for column
ProviderValueA")]
public string ProviderValueA
{
get { return _ProviderValueA; }
set { _ProviderValueA = value; }
}
}
The code for the MyFieldConsumer web part that is generated by the WPCL based on this diagram looks like this:
public class MyFieldConsumer : WebPart{
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write(ConsumerValueA.ToString());
}
[ConnectionConsumer("Field consumer MyFieldConsumer")]
public void GetProvider(IWebPartField objProvider)
{
FieldCallback objCallback = new FieldCallback(GetField);
objProvider.GetFieldValue(objCallback);
}
public void GetField(object objField)
{
if (objField != null) ConsumerValueA = objField.ToString();
}
private string _ConsumerValueA = "consumer value A";
[Personalizable(PersonalizationScope.Shared), WebBrowsable(true),
WebDisplayName("ConsumerValueA"), WebDescription("Value for column
ConsumerValueA")]
public string ConsumerValueA
{
get { return _ConsumerValueA; }
set { _ConsumerValueA = value; }
}
}
You can copy this code in a web part library project. If you had both web parts to a web part page, you can connect the MyFieldProvider provider web part and the MyFieldConsumer consumer web part to each other, as can be seen in Figure 19.

Figure 19
After the web part connection has been made, the web part consumer displays the value provided by the web part provider. This is shown in Figure 20.

Figure 20
Creating a connection using the IWebPartRow interface
In this example, we have added two web parts to a WPCL diagram: MyRowProvider and MyRowConsumer. MyRowProvider acts as a row web part provider that provides a row consisting of two columns: ColumnA and ColumnB. This is shown in Figure 21.

Figure 21
The code for the MyRowProvider web part that is generated by the WPCL based on this diagram looks like this (we have omitted namespace imports and the namespace declaration from this code):
public class MyRowProvider : WebPart, IWebPartRow{
private DataTable _dtData;
public MyRowProvider()
{
_dtData = new DataTable();
_dtData.Locale = CultureInfo.InvariantCulture;
DataColumn columnColumnA = new DataColumn();
columnColumnA.DataType = typeof(string);
columnColumnA.ColumnName = "ColumnA";
_dtData.Columns.Add(columnColumnA);
DataColumn columnColumnB = new DataColumn();
columnColumnB.DataType = typeof(string);
columnColumnB.ColumnName = "ColumnB";
_dtData.Columns.Add(columnColumnB);
DataRow objRow = _dtData.NewRow();
objRow["ColumnA"] = "column a value";
objRow["ColumnB"] = "column b value";
_dtData.Rows.Add(objRow);
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("This is LoisAndClark.WebPartConnectionLanguage.IWebPartRow
provider");
}
[ConnectionProvider("row provider MyRowProvider")]
public IWebPartRow GetRowProvider()
{
return this;
}
public void GetRowData(RowCallback callback)
{
DataRowCollection coll = _dtData.Rows;
DataRowView view = _dtData.DefaultView[0];
callback.Invoke(_dtData.Rows);
}
public System.ComponentModel.PropertyDescriptorCollection Schema
{
get
{
return TypeDescriptor.GetProperties(_dtData.DefaultView[0]);
}
}
}
The code for the MyRowConsumer web part that is generated by the WPCL based on this diagram looks like this:
public class MyRowConsumer : WebPart{
protected override void RenderContents(HtmlTextWriter writer)
{
if (Data != null)
{
foreach (DataRow objRow in Data)
{
writer.Write("column ColumnA : " + objRow["ColumnA"]);
writer.WriteBreak();
writer.Write("column ColumnB : " + objRow["ColumnB"]);
writer.WriteBreak();
}
}
else
{
writer.Write("Not connected");
}
}
[ConnectionConsumer("Row consumer MyRowConsumer")]
public void GetProvider(IWebPartRow objProvider)
{
RowCallback objCallback = new RowCallback(GetRow);
objProvider.GetRowData(objCallback);
}
public void GetRow(object objRow)
{
if (objRow != null) Data = (ICollection)objRow;
}
private ICollection _collData;
public ICollection Data
{
get { return _collData; }
set { _collData = value; }
}
}
If you copy the generated code to a web part library project you can add the two web parts to a page. Figure 22 shows that MyRowConsumers displays the values provided by MyRowProvider.

Figure 22
Creating a connection using the IWebPartTable interface
In this example, we have added two web parts to a WPCL diagram: MyTableProvider and MyTableConsumer. MyTableProvider provides data to MyTableConsumer over an IWebPartTable interface. It provides a data table that contains two columns: ColumnA and ColumnB. This is shown in Figure 23.

Figure 23
The code for the MyTableProvider web part that is generated by the WPCL based on this diagram looks like this (we have omitted namespace imports and the namespace declaration from this code):
public class MyTableProvider : WebPart, IWebPartTable{
private DataTable _dtData;
public MyTableProvider()
{
_dtData = new DataTable();
_dtData.Locale = CultureInfo.InvariantCulture;
DataColumn columnColumnA = new DataColumn();
columnColumnA.DataType = typeof(string);
columnColumnA.ColumnName = "ColumnA";
_dtData.Columns.Add(columnColumnA);
DataColumn columnColumnB = new DataColumn();
columnColumnB.DataType = typeof(string);
columnColumnB.ColumnName = "ColumnB";
_dtData.Columns.Add(columnColumnB);
DataRow objRow = _dtData.NewRow();
objRow["ColumnA"] = "column a value";
objRow["ColumnB"] = "column b value";
_dtData.Rows.Add(objRow);
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("This is LoisAndClark.WebPartConnectionLanguage.IWebPartTable provider");
}
[ConnectionProvider("table provider MyTableProvider")]
public IWebPartTable GetTableProvider()
{
return this;
}
public void GetTableData(TableCallback callback)
{
callback.Invoke(_dtData.Rows);
}
public System.ComponentModel.PropertyDescriptorCollection Schema
{
get
{
return TypeDescriptor.GetProperties(_dtData.DefaultView[0]);
}
}
}
The code for the MyTableConsumer web part that is generated by the WPCL based on this diagram looks like this:
public class MyTableConsumer : WebPart{
protected override void RenderContents(HtmlTextWriter writer)
{
if (Data != null)
{
foreach (DataRow objRow in Data)
{
writer.Write("column ColumnA : " + objRow["ColumnA"]);
writer.WriteBreak();
writer.Write("column ColumnB : " + objRow["ColumnB"]);
writer.WriteBreak();
}
}
else
{
writer.Write("Not connected");
}
}
[ConnectionConsumer("table consumer MyTableConsumer")]
public void GetProvider(IWebPartTable objProvider)
{
TableCallback objCallback = new TableCallback(GetTable);
objProvider.GetTableData(objCallback);
}
public void GetTable(ICollection objTable)
{
if (objTable != null) Data = (ICollection)objTable;
}
private ICollection _collData;
public ICollection Data
{
get { return _collData; }
set { _collData = value; }
}
}
If you copy this code to a web part library you can add both web parts to a page. Figure 24 shows that the MyTableConsumer web part displays data provided by the MyTableProvider web part.

Figure 24
Creating a connection using the IWebPartParameters interface
In this example, we have added two web parts to a WPCL diagram: MyParametersProvider and MyParametersConsumer. The MyParametersProvider implements the IWebPartParameter interface and provides two parameters to a consumer: ParameterA and ParameterB. This is shown in Figure 25.

Figure 25
The code for the MyParametersProvider web part that is generated by the WPCL based on this diagram looks like this (we have omitted namespace imports and the namespace declaration from this code):
public class MyParametersProvider : WebPart, IWebPartParameters{
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("This is LoisAndClark.WebPartConnectionLanguage.IWebPartParameters provider");
}
[ConnectionProvider("parameters provider MyParametersProvider")]
public IWebPartParameters GetParametersProvider()
{
return this;
}
public void GetParametersData(ParametersCallback callback)
{
StateBag objParameters = new StateBag();
foreach (PropertyDescriptor objProperty in Parameters)
{
switch (objProperty.Name)
{
case "ParameterA":
objParameters.Add("ParameterA", ParameterA);
break;
case "ParameterB":
objParameters.Add("ParameterB", ParameterB);
break;
default:
throw new Exception("ParametersProvider: Unknown parameter name");
}
}
callback.Invoke(objParameters);
}
public System.ComponentModel.PropertyDescriptorCollection Schema
{
get
{
PropertyDescriptorCollection objProperties;
PropertyDescriptor[] arrProperties = new PropertyDescriptor[Parameters.Count];
objProperties = TypeDescriptor.GetProperties(this);
int intParameterCount = 0;
foreach (PropertyDescriptor objProperty in Parameters)
{
if (Parameters[objProperty.Name] != null )
{
intParameterCount++;
arrProperties[intParameterCount] = objProperty;
}
}
objProperties = new PropertyDescriptorCollection(arrProperties);
return objProperties;
}
}
public void SetConsumerSchema(System.ComponentModel.PropertyDescriptor Collection schema)
{
Parameters = schema;
}
private PropertyDescriptorCollection _objParameters;
public PropertyDescriptorCollection Parameters
{
get { return _objParameters; }
set { _objParameters = value; }
}
private string _ParameterA = "column B value";
[Personalizable(PersonalizationScope.Shared),
WebBrowsable(true), WebDisplayName("ParameterA"),
WebDescription("Value for column ParameterA")]
public string ParameterA
{
get { return _ParameterA; }
set { _ParameterA = value; }
}
private string _ParameterB = "column B value";
[Personalizable(PersonalizationScope.Shared),
WebBrowsable(true), WebDisplayName("ParameterB"),
WebDescription("Value for column ParameterB")]
public string ParameterB
{
get { return _ParameterB; }
set { _ParameterB = value; }
}
}
The code for the MyParametersConsumer web part that is generated by the WPCL based on this diagram looks like this:
public class MyParametersConsumer : WebPart{
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("ParameterA : " + ParameterA);
writer.WriteBreak();
writer.Write("ParameterB : " + ParameterB);
writer.WriteBreak();
}
[ConnectionConsumer("parameters
consumerMyParametersConsumer")]
public void GetProvider(IWebPartParameters objProvider)
{
PropertyDescriptor[] objProperties =
{
TypeDescriptor.GetProperties(this)["ParameterA"],
TypeDescriptor.GetProperties(this)["ParameterB"]
};
PropertyDescriptorCollection objSchema = new PropertyDescriptorCollection(objProperties);
objProvider.SetConsumerSchema(objSchema);
ParametersCallback objCallback = new ParametersCallback(GetParameters);
objProvider.GetParametersData(objCallback);
}
public void GetParameters(IDictionary objParameters)
{
foreach (DictionaryEntry objEntry in objParameters)
{
StateItem objStateItem;
switch (objEntry.Key.ToString())
{
case "ParameterA":
objStateItem = (StateItem) objEntry.Value;
ParameterA = objStateItem.Value.ToString();
break;
case "ParameterB":
objStateItem = (StateItem) objEntry.Value;
ParameterB = objStateItem.Value.ToString();
break;
default:
throw new Exception("unknown parameter");
}
}
}
private string _ParameterA = "column B value";
[Personalizable(PersonalizationScope.Shared),
WebBrowsable(true), WebDisplayName("ParameterA"),
WebDescription("Value for column ParameterA")]
public string ParameterA
{
get { return _ParameterA; }
set { _ParameterA = value; }
}
private string _ParameterB = "column B value";
[Personalizable(PersonalizationScope.Shared),
WebBrowsable(true), WebDisplayName("ParameterB"),
WebDescription("Value for column ParameterB")]
public string ParameterB
{
get { return _ParameterB; }
set { _ParameterB = value; }
}
}
Once you have added both web parts to a page and make a connection between them, the ParametersConsumer web part displays the parameters provided by the ParametersProvider web part. The end result is shown in Figure 26.

Figure 26
Creating a connection using a custom interface
In this example, we have added two web parts to a WPCL diagram: MyCustomInterfaceProvider and MyCustomInterfaceConsumer. The MyCustomInterfaceProvider web part implements a custom interface called IMyCustomInterface that contains a single method called GetCustomMethod(). This is shown in Figure 27.

Figure 27
The code for the IMyCustomInterface interface that is generated by the WPCL based on this diagram looks like this (we have omitted namespace imports and the namespace declaration from this code):
public interface IMyCustomInterface{
string GetCustomMethod();
}
The code for the MyCustomInterfaceProvider web part that is generated by the WPCL based on this diagram looks like this:
public class MyCustomInterfaceProvider : WebPart, IMyCustomInterface{
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("custom interface provider MyCustomInterfaceProvider");
}
[ConnectionProvider("custom interface connection provider MyCustomInterfaceProvider")]
public IMyCustomInterface GetMyCustomInterfaceProvider()
{
return this;
}
public string GetCustomMethod()
{
return "custom method default value";
}
}
The code for the MyCustomInterfaceConsumer web part that is generated by the WPCL based on this diagram looks like this (we have omitted namespace imports and the namespace declaration from this code):
public class MyCustomInterfaceConsumer : WebPart{
protected override void RenderContents(HtmlTextWriter writer)
{
if (Provider != null)
{
writer.Write(Provider.GetCustomMethod());
}
else
{
writer.Write("no connection established");
}
}
[ConnectionConsumer("connection consumer MyCustomInterfaceConsumer")]
public void GetProvider(IMyCustomInterface objProvider)
{
Provider = objProvider;
}
private IMyCustomInterface _objProvider;
public IMyCustomInterface Provider
{
get { return _objProvider; }
set { _objProvider = value; }
}
}
If you add this code to a web part library you can add both web parts to a page. Figure 28 shows that the MyCustomInterfaceConsumer web part displays the value provided by the MyCustomInterfaceProvider web part.

Figure 28
What if you are not happy with the generated code?
The problem with any tool that generates code is that you might not like the end result. If you don’t have access to the code templates responsible for generating code this can become a reason for not using the tool. If you don’t like the end result of the code generation template, there are a couple things you can do. First of all, you can e-mail suggestions to info@lcbridge.nl. If we like the ideas we will include them in the WPCL, or enhance the language so that you are able to specify a code style that influences the way the generated code looks. You can also change WebPartsTemplate.tt or create a new text template altogether. Finally, if you are not interested in changing the code template, you can change the end result, the code itself.
To sum up
The WPCL 2007 is intended to make the creation of connectable web parts significantly easier. It does this by providing a visual language that lets you create diagrams that can be used to create code. This code can be copied and pasted into web part library projects. Once the web part library project is compiled, the connectable web parts can be added to SharePoint 2007 pages (or any ASP.NET 2.0 page that supports web parts, provided you do not need to use any parts of the SharePoint framework).