ASP.NET WebParts Connections Transformers Tutorial

Contents

Download: Pending...

Introduction
Sample Scenario
Summary


Introduction

Connections are a very powerful feature of WebParts that allows interchanging data between two webparts, allowing creating more interesting non-monolitic WebParts.
A connection in WebParts is essentially the ability to expose an interface to a WebPart (Provider) that another WebPart (Consumer) can connect to and use it. This is an interesting feature that allows the creation of atomic units that are completely decoupled from each other. This allows end users to connect WebParts from different vendors to interact their web site even when the vendors were never aware of them.

ASP.NET WebPart connections give a lot of flexibility allowing WebPart developers to expose any arbitrary interfaces that might include events, methods, properties or anything that interfaces allow. This allows building interesting connections that can allow consumers notify providers using methods or events.
However, with this flexibility comes a problem, each vendor might start defining their own interfaces which will make potentially imposible to end users inter-connect webparts seemlesly.
ASP.NET understand the problem and to mitigate it, it has two features:

  • It defines a pre-defined set of "standard" interfaces that different vendors could try to stick to, so their webparts are more "connectable". Interfaces like IField, IParameters, IRow, etc try to provide common patterns of data interchange.
  • Transformers. This feature allows to build special "bridges" that allows to connect webparts that by definition are incompatible. This is what we will be covering in this article.

Sample Scenario

The scenario that we will create is the simplest transformer possible.
Lets assume we downloaded a DLL from a WebSite that "vendor A" created. This webpart exposes a connection with an interface IFoo (FooProvider WebPart).
We also downloaded from another site a WebPart that knows how to consume an interface called IBar (BarConsumer WebPart).
The problem that we have is that we would want to connect them to share data, but they are incompatible since they expose/consume different interfaces, so the ASP.NET WebPart Framework will not allow us to connect them.
So our job is to create the "bridge" that will tell the WebPart framework that they are "connectable", and that we know how to translate between one and the other.

Create a new Project


Create a new Web Application in Visual Web Developer or Visual Studio .NET 2005.

Create the WebParts

Even though this sample is not meant to show how to do the WebParts and the connections, we will show the code so you see how simple it is.
Just keep in mind that you do not need the source code of WebParts, or the interfaces to be able to build a transformer that converts between two different webparts.

Create the Code Directory
  • Select the project node in the Solution Explorer.
  • Right click it and select New Folder
  • Type Code as the name of the folder
Note. the Code directory is new to ASP.NET 2.0 that allows developers to place code inside this directory with the .cs or .vb extension and the asp.net build infrastructure will compile the code on demand only when needed. In the Beta2 it might be renamed to be called Application_Code.

Add a new BarConsumer file to the directory.
  • Select the Code folder
  • Right click it and select the option Add New Item
  • Select the option Class and type as the name BarConsumer
  • Replace the content of the generated class with the following code.
C# Code:
namespace  CarlosAg.Samples {
    
using  System ;
    using 
System.Web.UI ;
    using 
System.Web.UI.WebControls.WebParts ;

    
/// <summary>
    /// Simple Interface that Shares an Integer property
    /// </summary>
    
public interface  IBar {
        
int  IntegerData {  get; }
    }

    
/// <summary>
    /// WebPart that consumes an IBar.
    ///     Displays the info
    /// </summary>
    
public class  BarConsumer : WebPart {
        
private  IBar _bar ;

        
/// <summary>
        /// Exposes the Consumer Connection Point
        /// </summary>
        
[ConnectionConsumer( "IBar Consumer" )]
        
public void  SetProvider(IBar bar) {
            
this ._bar  bar ;
        
}

        
/// <summary>
        /// Renders the Data
        /// </summary>
        /// <param name="writer"></param>
        
protected override void  RenderContents(HtmlTextWriter writer) {
            
if  (_bar ! = null ) {
                writer.Write(
"Integer Data:"  + _bar.IntegerData.ToString()) ;
            
}
            
else  {
                writer.Write(
"IBar is null" ) ;
            
}
        }
    }
}

VB.NET Code:

Imports  System
Imports  System.Web.UI
Imports  System.Web.UI.WebControls.WebParts

Namespace  CarlosAg.Samples
    
' <summary>
    ' Simple Interface that Shares an Integer property
    ' </summary>
    
Public Interface  IBar
        
ReadOnly Property  IntegerData()  As Integer
    End Interface

    
' <summary>
    ' WebPart that consumes an IBar.
    '     Displays the info
    ' </summary>
    
Public Class  BarConsumer
        
Inherits  WebPart

        
Private  _bar  As  IBar

        
' <summary>
        ' Exposes the Consumer Connection Point
        ' </summary>
        
<ConnectionConsumer( "IBar Consumer" )> _
        
Public Sub  SetProvider( ByVal  bar  As  IBar)
            
Me ._bar  bar
        
End Sub

        
' <summary>
        ' Renders the Data
        ' </summary>
        ' <param name="writer"></param>
        
Protected Overrides Sub  RenderContents( ByVal  writer  As  HtmlTextWriter)
            
If  ( Not  (_bar)  Is  Nothing)  Then
                
writer.Write(( "Integer Data:"  + _bar.IntegerData.ToString))
            
Else
                
writer.Write( "IBar is null" )
            
End If
        End Sub
    End Class
End Namespace

As you can see creating a consumer is extremely easy, just expose a public method that has no return value, that receives one object and that is tagged with the ConnectionConsumer attribute.
Once you do that, just make sure to save a reference of the object passed and use it later, say at PreRender, or Render methods, to ensure everything is connected correctly.

Create the Provider WebPart


Create the FooProvider class
  • Select the Code folder node
  • Right click it and select the option Add New Item
  • Select the option Class
  • Type FooProvider as the name and replace the content as follows
C# Code
namespace  CarlosAg.Samples {
    
using  System ;
    using 
System.Web.UI.WebControls ;
    using 
System.Web.UI.WebControls.WebParts ;

    
/// <summary>
    /// Simple Interface that Shares a String property
    /// </summary>
    
public interface  IFoo {
        
string  StringData {  get; }
    }

    
/// <summary>
    /// WebPart that serves as an IFoo Provider.
    ///     Prompts the user using a TextBox
    /// </summary>
    
public class  FooProvider : WebPart, IFoo {
        
private  TextBox _dataTextBox ;

        
/// <summary>
        /// Public property to allow users to set the Data
        /// </summary>
        
[Personalizable(PersonalizationScope.User)]
        
public string  Data {
            
get  {
                
return  TextBox.Text ;
            
}
            
set  {
                TextBox.Text 
= value;
            
}
        }

        
/// <summary>
        /// Text Box to allow end users to change the data
        /// </summary>
        
protected  TextBox TextBox {
            
get  {
                EnsureChildControls()
;
                return 
_dataTextBox ;
            
}
        }

        
/// <summary>
        /// Creates a new instance of the class
        /// </summary>
        
public  FooProvider() {

        }

        
/// <summary>
        /// Overrides the CreateChildControls to create the TextBox
        /// </summary>
        
protected override void  CreateChildControls() {
            Label _label 
= new  Label() ;
            
_label.Text  "Enter a Number:" ;
            
_label.Font.Bold  = true;
            this
.Controls.Add(_label) ;

            
_dataTextBox  = new  TextBox() ;
            
_dataTextBox.AutoPostBack  = true;
            
_dataTextBox.TextChanged + = new  EventHandler(_dataTextBox_TextChanged) ;
            this
.Controls.Add(_dataTextBox) ;
        
}

        
/// <summary>
        /// Event raised when the user changes the text
        /// </summary>
        
private void  _dataTextBox_TextChanged( object  sender, EventArgs e) {
            Data 
TextBox.Text ;
        
}

        
// ***********************************************
        // Here starts the connection related code
        // ***********************************************
        /// <summary>
        /// Exposes the Provider Connection Point
        /// </summary>
        
[ConnectionProvider( "IFoo Provider" )]
        
public  IFoo GetProvider() {
            
return this;
        
}

        
/// <summary>
        /// Implementation of the interface
        /// </summary>
        
string  IFoo.StringData {
            
get  {
                
return this .Data ;
            
}
        }
    }
}

VB.NET Code

Imports  System
Imports  System.Web.UI.WebControls
Imports  System.Web.UI.WebControls.WebParts

Namespace  CarlosAg.Samples

    
' <summary>
    ' Simple Interface that Shares a String property
    ' </summary>
    
Public Interface  IFoo
        
ReadOnly Property  StringData()  As String
    End Interface

    
' <summary>
    ' WebPart that serves as an IFoo Provider.
    '     Prompts the user using a TextBox
    ' </summary>
    
Public Class  FooProvider
        
Inherits  WebPart
        
Implements  IFoo

        
Private  _dataTextBox  As  TextBox

        
' <summary>
        ' Creates a new instance of the class
        ' </summary>
        
Public Sub New ()
            
MyBase . New ()
        
End Sub

        
' <summary>
        ' Public property to allow users to set the Data
        ' </summary>
        
<Personalizable(PersonalizationScope.User)> _
        
Public Property  Data()  As String
            Get
                Return 
TextBox.Text
            
End Get
            Set
( ByVal  value  As String )
                TextBox.Text 
value
            
End Set
        End Property

        
' <summary>
        ' Text Box to allow end users to change the data
        ' </summary>
        
Protected ReadOnly Property  TextBox()  As  TextBox
            
Get
                
EnsureChildControls()
                
Return  _dataTextBox
            
End Get
        End Property

        
' <summary>
        ' Implementation of the interface
        ' </summary>
        
ReadOnly Property  IFoo_StringData()  As String  _
                            
Implements  IFoo.StringData
            
Get
                Return Me
.Data
            
End Get
        End Property

        
' <summary>
        ' Overrides the CreateChildControls to create the TextBox
        ' </summary>
        
Protected Overrides Sub  CreateChildControls()
            
Dim  _label  As  Label  = New  Label
            _label.Text 
"Enter a Number:"
            
_label.Font.Bold  = True
            Me
.Controls.Add(_label)
            _dataTextBox 
= New  TextBox
            _dataTextBox.AutoPostBack 
= True
            AddHandler 
_dataTextBox.TextChanged,  AddressOf Me ._dataTextBox_TextChanged
            
Me .Controls.Add(_dataTextBox)
        
End Sub

        
' <summary>
        ' Event raised when the user changes the text
        ' </summary>
        
Private Sub  _dataTextBox_TextChanged( ByVal  sender  As Object , _
                            
ByVal  As  EventArgs)
            Data 
TextBox.Text
        
End Sub

        
' ***********************************************
        ' Here starts the connection related code
        ' ***********************************************
        ' <summary>
        ' Exposes the Provider Connection Point
        ' </summary>
        
<ConnectionProvider( "IFoo Provider" )> _
        
Public Function  GetProvider()  As  IFoo
            
Return Me
        End Function
    End Class
End Namespace

Creating the page

Now we will create the page where we actually use both webparts.

Create the Page
  • Select the Project node
  • Right click it and select the option Add New Item
  • Select the option Web Form
  • Type Sample.aspx as the name for the Page
  • Replace the content of the Page so that it looks as the following code 

Code

<%@ Page Language="C#" %>
<%@ Register TagPrefix="sample" Namespace="CarlosAg.Samples" %>
< html >
<
head  runat ="server">
    <
title >Transformer Sample< / title >
<
/ head >
<
body >
    <
form  id ="form1"  runat ="server">
        <
asp:WebPartManager  ID ="WebPartManager1"  Runat ="server"   />
        <
asp:WebPartPageMenu  ID ="WebPartPageMenu1"  Runat ="server"   />
        <
hr   />
        <
asp:WebPartZone  ID ="WebPartZone1"  Runat ="server"  PartTitleStyle-BackColor ="#99ccff">
            <
ZoneTemplate >
                <
sample:FooProvider  Title ="Foo Provider"  Runat ="server"  ID ="fooProvider1"  Data ="23"   />
                <
sample:BarConsumer  Title ="Bar Consumer"  Runat ="server"  ID ="barConsumer1"   />
            <
/ ZoneTemplate >
            <
PartStyle  BorderColor ="SlateGray"  BorderStyle ="Solid"  BorderWidth ="4px"   />
        <
/ asp:WebPartZone >
        <
br   />
        <
asp:ConnectionsZone  ID ="ConnectionsZone1"  Runat ="server"  HeaderStyle-BackColor ="#99ccff"   />
    <
/ form >
<
/ body >
<
/ html >

If you try running the page now, you should be able to see both webparts working, you can use the WebPartPageMenu to switch to connect mode, and you will notice that no connection can be established, since as we said they are incompatible.

Creating the Transformer

Now we will create the actual Transformer class that will allow us to connect both webparts.

Create the FooToBarTransformer class
  • Select the Code node
  • Right click it and select the option Add New Item
  • Select the option Class
  • Type FooToBarTransformer as the name for the Class
  • Replace the content so that it looks as the following code 

C# Code
namespace  CarlosAg.Samples {
    
using  System ;
    using 
System.Web.UI.WebControls.WebParts ;

    
[Transformer( typeof (IFoo),  typeof (IBar))]
    
public class  FooToBarTransformer : Transformer, IBar {
        IFoo _foo
;

        
/// <summary>
        /// Transforms from IFoo to IBar
        /// </summary>
        
public override object  Transform( object  providerData) {
            _foo 
(IFoo)providerData ;
            return this;
        
}

        
/// <summary>
        /// Implements IBar funtionality
        /// </summary>
        
int  IBar.IntegerData {
            
get  {
                
if  (_foo.StringData ! = null ) {
                    
try  {
                        
return int .Parse(_foo.StringData) ;
                    
}
                    
catch  { }
                }
                
return  - 1 ;
            
}
        }
    }
}

VB.NET Code
Imports  System
Imports  System.Web.UI.WebControls.WebParts

Namespace  CarlosAg.Samples

    <Transformer(
GetType (IFoo),  GetType (IBar))> _
    
Public Class  FooToBarTransformer
        
Inherits  Transformer
        
Implements  IBar

        
Private  _foo  As  IFoo

        
' <summary>
        ' Implements IBar funtionality
        ' </summary>
        
ReadOnly Property  IBar_IntegerData()  As Integer  _
                
Implements  IBar.IntegerData
            
Get
                If 
( Not  (_foo.StringData)  Is  Nothing)  Then
                    Try
                        Return CInt
(_foo.StringData)
                    
Catch  ex  As  System. Exception
                    End Try
                End If
                Return 
- 1
            
End Get
        End Property

        
' <summary>
        ' Transforms from IFoo to IBar
        ' </summary>
        
Public Overrides Function  Transform( ByVal  providerData  As Object As Object
            
_foo  = CType (providerData, IFoo)
            
Return Me
        End Function
    End Class
End Namespace

If you try running the page again, you will still see you are not able to connect them. The reason for this is that in order for transformers to work you have to "publish" them in the web.config or machine.config.

Modifying the web.config

Open the web.config and add the webParts section that is shown below so that it is inside the system.web section.

Web.Config
< ?xml  version ="1.0"  ? >
<
configuration  xmlns ="http://schemas.microsoft.com/.NetConfiguration/v2.0">
    <
system.web >
        <
authentication  mode ="Windows"   />
        <
webParts >
            <
transformers >
                <
add  name ="Foo To Bar Transformer"  
                     type
="CarlosAg.Samples.FooToBarTransformer"    />
            <
/ transformers >
        <
/ webParts >
    <
/ system.web >
<
/ configuration >

Running the Sample

To run the sample just browse to Sample.aspx.
Select the Connect WebParts option in the drop down menu and select the Change button


Click the Connect Verb from the Popup Menu that will appear in the Title of the Provider WebPart.
At this point the WebPart framework will realize that this WebPart can only be used as a provider and will enable only a link to connect to a consumer.
Click the Link "Create a Connection to a Consumer".
The WebPart framework will look for all compatible consumer connections and will look for possible transformers as well.
It will realize that the FooToBarTransformer is available and so it will display as a possible connection the Foo -> Bar.
Select the Bar consumer from the drop down, and click Connect.
At this point the webparts are connected, so type some numbers in the text box and press Tab, or move the focus out of the text box so the autopostback works and will update the second webpart.

Summary

Connections are a very powerfull feature in WebParts. Transformers give the ability to connect webparts that otherwise would be incompatible.
In this tutorial we just scratched the surface of Transformers, there are other methods that you could use to create a User interface to prompt for additional values or parameters for your transformer as well as some methods to load and save custom state that could be use during the transformation.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值