Click to Rate and Give Feedback
Related Articles

This month we demonstrate how easy it is to use IronPython to test .NET-based libraries.

James McCaffrey

MSDN Magazine June 2009

...

Read more!

Microsoft Velocity exposes a unified, distributed memory cache for client application consumption. We show you how to add Velocity to your data-driven apps.

Aaron Dunnington

MSDN Magazine June 2009

...

Read more!

In this month's column, we’ll explore the pros and cons of both ASP.NET Web Forms and ASP.NET MVC.

Dino Esposito

MSDN Magazine July 2009

...

Read more!

With the help of Silverlight Deep Zoom and a remarkable control named MultiScaleImage, you can create scenes with many levels of zoom. Jeff Prosise illustrates with what else but the Mandlebrot set.

Jeff Prosise

MSDN Magazine July 2009

...

Read more!

This month we show you how to use F# to perform HTTP request-response testing for ASP.NET Web applications.

James McCaffrey

MSDN Magazine July 2009

...

Read more!

Also by this Author

There are two ways you can utilize resources such as strings, images, and text-based files from your Microsoft® . NET Framework-based application. You can embed them directly in the app or you can load them from an external file.

Ted Pattison

MSDN Magazine May 2006

...

Read more!

This new column explores how you can extend and customize Microsoft Office System applications and file formats.

Ted Pattison

MSDN Magazine February 2007

...

Read more!

WSS 3.0 introduces a new deployment mechanism that lets you move your development efforts into a staging or production environment.

Ted Pattison

MSDN Magazine August 2007

...

Read more!

In this installment of Advanced Basics Ted Pattison discusses the localization of Web sites in ASP.NET 2.0.

Ted Pattison

MSDN Magazine August 2006

...

Read more!

Ted Pattison

MSDN Magazine May 2007

...

Read more!

Popular Articles

One-time passwords offer solutions to dictionary attacks, phishing, interception, and lots of other security breaches. Here's how it all works.

Dan Griffin

MSDN Magazine May 2008

...

Read more!

The MVP pattern helps you separate your logic and keep your UI layer free of clutter. This month learn how.

Jean-Paul Boodhoo

MSDN Magazine August 2006

...

Read more!

A Sidebar gadget is a powerful little too that's surprisingly easy to create. Get in on the fun with Donavon West.

Donavon West

MSDN Magazine August 2007

...

Read more!

Here we introduce you to some of the concepts behind the new F# language, which combines elements of functional and object-oriented .NET languages. We then help you get started writing some simple programs.

Ted Neward

MSDN Magazine Launch 2008

...

Read more!

Paul DiLascia

MSDN Magazine August 2002

...

Read more!

Basic Instincts
Introducing ASP.NET Web Part Connections
Ted Pattison

Code download available at: BasicInstincts0602.exe (763 KB)
Browse the Code Online
When you begin to work with the Microsoft® .NET Framework 2.0 and ASP.NET, you discover that the new Web Parts infrastructure adds some very powerful functionality to the underlying platform. In the September 2005 issue of MSDN®Magazine, Fritz Onion and I have an article on programming Web Parts titled "ASP.NET 2.0: Personalize Your Portal with User Controls and Custom Web Parts". In this month's column, I am going to build on the information we presented in that article by discussing how Web Part connections works.
For this column, I assume that you already understand the basics of Web Parts such as how to work with the WebPartManager control, Web Part zones, editors, catalogs, and persistence properties. If you don't, I encourage you to read the aforementioned article before continuing with this one.

Creating Web Parts for ASP.NET 2.0 Apps
There are two ways in which you can create a Web Part. The first involves creating a custom Web Part class that inherits from the WebPart class defined in the System.Web.UI.WebControls.WebParts namespace. When using this approach, it often makes sense to package custom Web Part classes in an assembly DLL to provide more control over reuse, versioning, and Visual Studio® 2005 integration. If you are familiar with building custom controls with previous versions of ASP.NET, many of the same techniques apply to building custom Web Parts into a DLL assembly.
A second approach for creating ASP.NET 2.0 Web Parts involves the use of User Controls. While this approach doesn't yield the same levels of reuse and version control, it does allow you to create the user interface aspects of a Web Part using the Visual Studio forms designer. If you like to create applications by dragging and dropping controls for user input, validation, and data binding onto a design surface, this approach is for you. Of course, it's also a good approach to take if you've already spent time creating a User Control that you'd like to use as a Web Part.
When you create a User Control that's specifically designed to be a Web Part, it's recommended that you implement the IWebPart interface. This allows the code behind your Web Part to programmatically assign several of its own internal Web Part properties such as its Title and TitleIconUrl.
The code sample that accompanies this month's column uses a custom base class named WebPartBase that inherits from UserControl and implements IWebPart. The definition for this base class is deployed in a source file named WebPartBase.vb in the App_Code directory. Whenever you create a new Web Part using a User Control, all you have to do is change the base class in the codebehind file to take advantage of this technique:
Partial Class WebParts_Customers
        Inherits WebPartBase

  Sub New()
    Title = "NorthWind Customer List"
    TitleIconImageUrl = "~\img\Customers.gif"
  End Sub

End Class

Designing Connectable Web Parts
Using Web Part connections, you can make it easier for your users to visualize the relationships that exist between items of data. For example, Web Part connections can model a master-detail scenario where one Web Part displaying a customer list is connected to another Web Part that displays the details of the currently selected customer. Figure 1 shows an example of what the user interface might look like with such a design.

Web Part connections can also be used to model one-to-many relationships. As an example, one Web Part that displays a customer list can be connected to another Web Part that displays all the orders for the currently selected customer.
Another scenario that's commonly modeled using Web Part connections is query-by-form. In such a scenario, one Web Part provides a user interface that allows the user to choose search or filter criteria for a query on data such as a database table. This Web Part is then connected to another Web Part that displays the results of the query. The Web Part connection is used to pass the filter criteria from one Web Part to the other before the query is run.
Web Part connections are based on the notion of providers and consumers. A provider Web Part supplies information to one or more consumer Web Parts through a programmatic interface. The information that is exchanged between a provider and a consumer could be a simple data item such as a number or a string or it could be something more exotic such as a reference to a complex array or to a collection of custom objects.
If you have programmed Web Parts for Windows® SharePoint® Services 2.0 (WSS), you might already be familiar with its model for connecting Web Parts. In WSS, Web Parts can only be connected using a set of predefined interface pairs. Examples of these interface pairs are ICellProvider and ICellConsumer as well as IRowProvider and IRowConsumer.
The Web Part connections model in ASP.NET 2.0 is easier and more flexible than the older model in WSS because you can use your own custom interfaces. That means you are not required to use an interface definition created by someone at Microsoft. Furthermore, you are not required to work in terms of interface pairs which must be implemented by both the provider and the consumer. With ASP.NET 2.0, only the provider is required to implement an interface.
To see how it all works, let's start by creating a connection between two Web Parts. For the examples I am presenting in this month's column, I decided to use the Northwind database because it has a Customers table and an Orders table. This allows me to show you how to design Web Parts for both master-detail and one-to-many relationships. Just note that if you are using SQL Server 2005, the sample Northwind database is not installed during product installation. To install it you must download and run the script available on the Microsoft Web site (see Microsoft SQL Server Home).
Now, imagine you want to establish a Web Part connection between a Web Part showing a customer list and a consumer Web Part showing the details of the currently selected customer such as the one shown in Figure 1. The Web Part showing the customer list will play the role of the provider while the Web Part showing the details of the currently selected customer will be the consumer. In this situation, you want the provider to supply the CustomerID field for the currently selected customer to the consumer.
First, create a simple interface named ICustomerIDProvider:
Public Interface ICustomerIDProvider
    ReadOnly Property CustomerID() As String
End Interface
In the code sample that accompanies this month's column, I have created the provider Web Part using a User Control with a SqlDataSource control and a GridView control to display customers from Northwind. The Web Part source files are Customers.ascx and Customers.ascx.vb, shown in Figure 2.
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts

Partial Class WebParts_Customers
        Inherits WebPartBase
        Implements ICustomerIDProvider

    Sub New()
        Title = "NorthWind Customer List"
        TitleIconImageUrl = "~\img\Customers.gif"
    End Sub

    <ConnectionProvider("Customer ID Provider")> _
    Public Function GetCustomerProvider() As ICustomerIDProvider
        Return Me
    End Function

    Public ReadOnly Property CustomerID() As String _
            Implements ICustomerIDProvider.CustomerID
        Get
            If gridCustomers.SelectedDataKey Is Nothing Then
                 Return String.Empty
            Else
                 Return Me.gridCustomers.SelectedDataKey.Value
            End If
        End Get
    End Property
End Class
As you can see, WebParts_Customers acts as a provider and implements the interface used for the Web Part connection. In this case, WebParts_Customers implements the ICustomerIDProvider interface. While the most common pattern is that the provider WebPart implements the connection interface itself, it is not required to do so. The only actual requirement is that the ConnectionProvider method return an instance of the specified interface. So, as an alternative, the provider Web Part could instead return a helper object that implements the connection interface. This is typically necessary if a provider Web Part has more than one connection point with the same interface type.
The WebParts_Customers class implements the CustomerID property by returning the value from the GridView control's SelectedDataKey property. The GridView control has been set up to display records from the Northwind Customers table and it also recognizes the CustomerID field as the SelectedDataKey value.
You should notice that the WebParts_Customers class has a method named GetCustomerProvider with a return type defined in terms of the ICustomerIDProvider interface. In this case, since the Web Part itself implements the desired interface, the GetCustomerProvider can simply return the Me reference to the current instance of the class. Also note that this method has been defined using the ConnectionProvider attribute:
<ConnectionProvider("Customer ID Provider")>
The WebPartManager is responsible for connecting Web Parts at run time. When the WebPartManager sees that a Web Part contains a method defined with ConnectionProvider attribute, it knows the Web Part exposes a connection point and can, therefore, act as a provider and be connected to a consumer. When it's time to connect two Web Parts together, the WebPartManager will call the GetCustomerProvider method to obtain a strongly typed reference to the provider Web Part.
It's possible to define whether a provider Web Part accepts multiple connections to consumers. In some case it is fine for a provider to have connections to multiple consumers at the same time. In other situations, you might want to limit a provider so it can have at most a single connection to one consumer Web Part. By default, providers allow multiple connections, and consumers do not. To change this, when you apply the ConnectionProvider attribute, you can make use of the named parameter AllowsMultipleConnections, as shown here:
<ConnectionProvider("Customer ID Provider", _
    AllowsMultipleConnections:=False)>
Now that you have seen how to create a method that exposes a connection point in the provider Web Part, let's see how this is complemented within a consumer Web Part. A consumer WebPart exposes a connection point by supplying a method defined with the ConnectionConsumer attribute. The consumer's connection point method is different from the provider's connection method because it does not define a return value. Instead, it takes a single parameter defined using the connection's interface type:
<ConnectionConsumer("Customer ID Consumer")> _
Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)
    ... ' implementation
End Sub
Keep in mind that the names of the provider's connection point method and the consumer's connection point method are not important. The only thing that matters is that each method be defined using the ConnectionProvider attribute and the ConnectionConsumer attribute, respectively.
Now let's see how the connection is established by the WebPartManager at run time. The WebPartManager calls the provider's connection point method to acquire the reference to the provider object. Next, the WebPartManager calls the consumer's connection point method to pass it a strongly typed reference back to the provider.
Once the WebPartManager has done its work, the consumer Web Part has an active connection back to the provider Web Part. At this point, the consumer can interact directly with the provider by using this reference to access the methods and properties defined in the interface. However, the ASP.NET team recommends that consumer Web Parts should not use methods or properties on the provider interface until the PreRender phase. Specifically, they should not use methods or properties on the provider interface in the <ConnectionConsumer()> method itself. The reason is that connections may have dependencies on each other. You may have a ProviderWebPart, connected to a ProviderConsumerWebPart, connected to a ConsumerWebPart. The ConsumerWebPart cannot query the provider interface until both connections have been established, and the order in which the connections are established is up to the Framework.
A complete code listing for the consumer Web Part in CustomerDetails.ascx.vb is shown in Figure 3. You can see that the consumer Web Part is responsible for holding on to a reference so it can track its connection to the provider. This consumer Web Part contains a private field named provider that is defined in terms of the ICustomerIDProvider interface.
Partial Class WebParts_CustomerDetails
        Inherits WebPartBase

    Sub New()
        Me.Title = "Customer Details"
        Me.TitleIconImageUrl = "~\img\Customer.gif"
    End Sub

    Private provider As ICustomerIDProvider

    <ConnectionConsumer("Customer ID Consumer")> _
    Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)
        Me.provider = provider
    End Sub

    Protected Sub SqlDataSource1_Selecting(ByVal sender As Object, _
            ByVal e As SqlDataSourceSelectingEventArgs) _
            Handles SqlDataSource1.Selecting
        SqlDataSource1.FilterExpression = _
            "CustomerID='" & provider.CustomerID & "'"
    End Sub

End Class
When the WebPartManager calls RegisterCustomerProvider, the consumer takes the incoming reference parameter and assigns it to the provider field. Once the provider field has been assigned the reference, the consumer Web Part can then directly interact with the provider Web Part. When you design the interface for a connection, you should add whatever methods and properties will provide the interaction you require.
There are certain situations in which a consumer Web Part may be designed to work regardless of whether there is an active connection to a provider. In such a design, you will want to add contingency code into the consumer Web Part that works correctly in cases when the provider field has a value of Nothing:
If provider IsNot Nothing Then
    ... ' interact with provider
Else
    ... ' contingency code goes here if required
End If

Timing a Web Part Connection
When you begin to design Web Parts that support connections, your understanding of the timing involved is critical. Figure 4 shows a trace of a page running a provider Web Part and a consumer Web Part during an HTTP GET. While there are more page-level events that fire during an HTTP POST, the timing for when the connection is established remains the same.

The trace information shown in Figure 4 illustrates when each of the connection methods is fired with respect to the standard ASP.NET 2.0 page-level events. You should be able to see from this trace information that the WebPartManager connects Web Parts together during the page-level LoadComplete command.
It's important to remember that the Web Part connection has not been established when page-level events PreInit, Init, PreLoad, and Load are executing. That means you should never attempt to access the provider inside a consumer Web Part's handler method that is bound to one of these events. The code inside a consumer Web Part must wait until after the LoadComplete event has executed before trying to access the provider Web Part.
In this example, the consumer Web Part handles the Selecting event of the SqlDataSource control, which fires during the page-level PreRender event. At this point it is safe to access the provider and retrieve the customer ID.

Defining Static Web Part Connections
Now that you have seen how to create Web Parts that support connections and you understand the timing involved, it's time to explore how to actually connect them together. As you will see, you can add tags directly to a Web Part page definition to establish a static Web Part connection. Web Part connections can also be established dynamically at run time through either code or user interaction. I am going to begin by showing how to create a static connection between two Web Parts because it is the most straightforward approach.
To create a static Web Part connection between two Web Parts on a page, you add a StaticConnections element inside the WebPartManager tag:
<asp:WebPartManager ID="WebPartManager1" runat="server">
    <StaticConnections>
        <asp:WebPartConnection ID="c1" 
            ProviderID="Customers1"
            ConsumerID="CustomerDetails1" />
    </StaticConnections>
</asp:WebPartManager>
For this code to work properly, the provider Web Part named Customers1 and the consumer Web Part named CustomerDetails1 must also be statically defined and properly named within Web Part Zones on the same page.
It's important to remember that there can only be one WebPartManager control per page. However, in many application designs involving Web Parts, you'll find that it's convenient to add the WebPartManager to a User Control or a Master Page so that it can be reused across many pages.
When a Web Part page is based on a Master Page or is using a User Control that contains a WebPartManager control, you cannot add a second instance of the WebPartManager control to define a StaticConnections tag. For these situations, the ASP.NET 2.0 Web Part control set provides the ProxyWebPartManager control. Here's an example of how to use it:
<asp:ProxyWebPartManager ID="ProxyWebPartManager1" runat="server">
    <StaticConnections>
        <asp:WebPartConnection ID="c1" 
            ProviderID="Customers1" 
            ConsumerID="CustomerDetails1" />
    </StaticConnections>
</asp:ProxyWebPartManager>
The value of the ProxyWebPartManager control is that it allows you to add static connections at the page level in situations where the page cannot contain a WebPartManager tag. In the sample page default.aspx that accompanies this column, the ProxyWebPartManager must be used to establish a static Web Part connection because the WebPartManager has been encapsulated within a User Control named WebPartManagerPanel.ascx.

Named Connection Points
In the example I have built up so far, the connection between the provider Web Part and the consumer Web Part have been based on default connection points. However, it is possible for a Web Part connection method to provide a named connection point. To add a named connection point to the provider, you simply add a second string parameter to the ConnectionProvider attribute:
<ConnectionProvider("Customer ID Provider", "CustomerIDProvider")> _
Public Function GetCustomerProvider() As ICustomerIDProvider
    Return Me
End Function
One motivation for named connection points is that a provider or a consumer can have more than one connection point and, therefore, must be able to differentiate between them. To add a named connection point to the consumer Web Part, you can add a second string parameter to the ConnectionConsumer attribute:
<ConnectionConsumer("Customer ID" & "Consumer", "CustomerIDConsumer")> _
Sub RegisterCustomerProvider(ByVal provider As ICustomerIDProvider)
    Me.provider = provider
End Sub
When you begin to use named connection points, you must supply two extra attribute values when you define a StaticConnections tag at the page level for the ProviderConnectionPointID and the ConsumerConnectionPointID.

Establishing Connections Dynamically
There are times when you will want to connect Web Parts together where you will not be able to rely on static Web Part connections. For example, this will be the case if you want to connect Web Parts that have been dynamically created either through custom code or by users who have added Web Parts to a page using a Web Part catalog.
In cases where static Web Part connections cannot be used, you must connect Web Parts using a dynamic technique. This can be done either through custom code or by using the ConnectionsZone control that is included with the ASP.NET 2.0 Web Part control set.
Let's start by examining custom code that creates two Web Parts and connects them together dynamically, as you can see in Figure 5. This code creates Web Part instances from user controls for the provider and the consumer and adds them to existing Web Part zones on the hosting Web Part page. It then establishes a connection between them. Note that the Web Parts and connections will be saved as part of a user's personalization information, so they should only be added to the WebPartManager once. Additional APIs are available if you don't want the Web Parts and connections saved in this fashion.
'*** get WebPartManager object
Dim wpMgr As WebPartManager = _
    WebPartManager.GetCurrentWebPartManager(Me.Page)

'*** create and add provider Web Part
Dim uc1 As UserControl = Me.Page.LoadControl("~\WebParts\Customers.ascx")
uc1.ID = "wp1"
Dim wp1 As GenericWebPart = wpMgr.CreateWebPart(uc1)
wp1 = wpMgr.AddWebPart(wp1, LeftWebPartZone, 0)

'*** create and add consumer Web Part
Dim uc2 As UserControl = _
    Me.Page.LoadControl("~\WebParts\CustomerDetails.ascx")
uc2.ID = "wp2"
Dim wp2 As GenericWebPart = wpMgr.CreateWebPart(uc2)
wp2 = wpMgr.AddWebPart(wp2, RightWebPartZone, 0)

'*** get desired connection points for provider and consumer
Dim cp1 As ProviderConnectionPoint = _
  wpMgr.GetProviderConnectionPoints(wp1)("CustomerIDProvider")
Dim cp2 As ConsumerConnectionPoint = _
  wpMgr.GetConsumerConnectionPoints(wp2)("CustomerIDConsumer")

'*** dynamically establish Web Part connection
wpMgr.ConnectWebParts(wp1, cp1, wp2, cp2)
Figure 6 Connect Display Mode  
You can see that the technique shown in Figure 5 requires the use of a ProviderConnectionPoint object and a ConsumerConnectionPoint. These objects can be retrieved by calling methods supplied by the WebPartManager and passing the string identifiers for those named connection points.
The other technique you and your users can employ to establish a dynamic Web Part connection involves the ConnectionsZone control. To use this technique effectively, you should create a Web Part page with a right-hand task pane that contains the ConnectionsZone control. Once the user puts the page into connect view display mode, a Connect command will be added to the Web Part menu of each Web Part that exposes connection points, as shown in Figure 6.
When the user selects the Connect command, the Web Part page then displays the ConnectionsZone control and allows the user to see all the compatible connection points from all the connectable Web Parts on that page (see Figure 7). Using this technique, you can connect a consumer to a provider. Likewise, you can also connect a provider to the consumer.


Send your questions and comments for Ted to  instinct@microsoft.com.


Ted Pattison is an author and trainer who delivers hands-on training through his company, the Ted Pattison Group. Ted is currently researching and writing a new book focusing on Windows SharePoint Services "V3" and Office 12 servers technology.

Page view tracker