Freigeben über


Grundlegendes zu ASP.NET AJAX UpdatePanel-Triggern

von Scott Cate

Wenn Sie im Markup-Editor in Visual Studio arbeiten, stellen Sie möglicherweise fest (aus IntelliSense), dass zwei untergeordnete Elemente eines UpdatePanel-Steuerelements vorhanden sind. Eines davon ist das Triggers-Element, das die Steuerelemente auf der Seite (oder das Benutzersteuerelement, wenn Sie eins verwenden) angibt, das ein teilweises Rendern des UpdatePanel-Steuerelements auslöst, in dem sich das Element befindet.

Einführung

Die ASP.NET-Technologie von Microsoft bietet ein objektorientiertes und ereignisgesteuertes Programmiermodell und vereint es mit den Vorteilen kompilierter Code. Das serverseitige Verarbeitungsmodell hat jedoch mehrere Nachteile in der Technologie, von denen viele von den neuen Features, die in den Microsoft ASP.NET 3.5 AJAX-Erweiterungen enthalten sind, behoben werden können. Diese Erweiterungen ermöglichen viele neue Rich-Client-Features, einschließlich teilweisem Rendern von Seiten, ohne dass eine vollständige Seitenaktualisierung erforderlich ist, die Möglichkeit, über clientbasierte Skripts (einschließlich der ASP.NET Profilerstellungs-API) auf Webdienste zuzugreifen, und eine umfangreiche clientseitige API, die so konzipiert ist, dass viele der Steuerelementschemas im ASP.NET serverseitigen Steuerelementsatzes gespiegelt werden.

In diesem Whitepaper werden die XML Triggers-Funktionalität der ASP.NET AJAX-Komponente UpdatePanel untersucht. XML-Trigger ermöglichen eine präzise Kontrolle über die Komponenten, die teilweises Rendering für bestimmte UpdatePanel-Steuerelemente verursachen können.

Dieses Whitepaper basiert auf der Beta 2-Version von .NET Framework 3.5 und Visual Studio 2008. Die ASP.NET AJAX-Erweiterungen, zuvor eine Add-On-Assembly für ASP.NET 2.0, sind jetzt in die .NET Framework-Basisklassenbibliothek integriert. In diesem Whitepaper wird auch davon ausgegangen, dass Sie mit Visual Studio 2008 arbeiten, nicht mit Visual Web Developer Express, und stellen exemplarische Vorgehensweisen gemäß der Benutzeroberfläche von Visual Studio bereit (obwohl Codeauflistungen unabhängig von der Entwicklungsumgebung vollständig kompatibel sind).

Auslöser

Trigger für ein bestimmtes UpdatePanel enthalten standardmäßig automatisch alle untergeordneten Steuerelemente, die ein Postback aufrufen, einschließlich (z. B.) TextBox-Steuerelementen, deren AutoPostBack Eigenschaft auf "true" festgelegt ist. Trigger können jedoch auch deklarativ mit Markup eingeschlossen werden; Dies erfolgt im <triggers> Abschnitt der UpdatePanel-Steuerelementdeklaration. Obwohl auf Trigger über die Triggers Sammlungseigenschaft zugegriffen werden kann, wird empfohlen, alle teilweisen Rendertrigger zur Laufzeit zu registrieren (z. B. wenn ein Steuerelement zur Entwurfszeit nicht verfügbar ist), indem Sie die RegisterAsyncPostBackControl(Control) Methode des ScriptManager-Objekts für Ihre Seite innerhalb des Page_Load Ereignisses verwenden. Denken Sie daran, dass Seiten zustandslos sind, und daher sollten Sie diese Steuerelemente jedes Mal erneut registrieren, wenn sie erstellt werden.

Die automatische Aufnahme untergeordneter Trigger kann auch deaktiviert werden, sodass untergeordnete Steuerelemente, die Postbacks erstellen, partielle Renderungen nicht automatisch auslösen, indem die ChildrenAsTriggers Eigenschaft auf false festgelegt wird. Dies ermöglicht Ihnen die größte Flexibilität beim Zuweisen, welche bestimmten Steuerelemente ein Seitenrendering aufrufen können, und wird empfohlen, damit ein Entwickler sich für die Reaktion auf ein Ereignis entscheidet, anstatt Ereignisse zu behandeln, die auftreten können.

Beachten Sie, dass beim Verschachteln von UpdatePanel-Steuerelementen, wenn UpdateMode auf Bedingt festgelegt ist, und das untergeordnete UpdatePanel ausgelöst wird, aber nicht das übergeordnete, dann wird nur das untergeordnete UpdatePanel aktualisiert. Wenn das übergeordnete UpdatePanel jedoch aktualisiert wird, wird das untergeordnete UpdatePanel ebenfalls aktualisiert.

Das <Triggers-Element>

Wenn Sie im Markup-Editor in Visual Studio arbeiten, stellen Sie möglicherweise fest (aus IntelliSense), dass zwei untergeordnete Elemente eines UpdatePanel Steuerelements vorhanden sind. Das am häufigsten gesehene Element ist das <ContentTemplate> Element, das im Wesentlichen den Inhalt kapselt, der vom Updatepanel gehalten wird (der Inhalt, für den wir partielles Rendering aktivieren). Das andere Element ist das <Triggers> Element, das die Steuerelemente auf der Seite (oder das Benutzersteuerelement, wenn Sie eins verwenden) angibt, das ein teilweises Rendern des UpdatePanel-Steuerelements auslöst, in dem sich das <Triggers-Element> befindet.

Das <Triggers> Element kann eine beliebige Anzahl von zwei untergeordneten Knoten enthalten: <asp:AsyncPostBackTrigger> und <asp:PostBackTrigger>. Beide akzeptieren zwei Attribute, ControlID und EventName, und können ein beliebiges Steuerelement innerhalb der aktuellen Kapselungseinheit angeben. Befindet sich Ihr UpdatePanel-Steuerelement beispielsweise in einem Web-Benutzersteuerelement, sollten Sie nicht versuchen, auf ein Steuerelement der Seite zu verweisen, auf der sich das Benutzersteuerelement befindet.

Das <asp:AsyncPostBackTrigger>-Element ist besonders nützlich, da es auf ein beliebiges Ereignis eines Steuerelements abzielen kann, das als untergeordnetes Element eines UpdatePanel-Steuerelements in der Kapselungseinheit vorhanden ist, nicht nur auf das UpdatePanel, unter dem dieser Trigger ein untergeordnetes Element ist. Daher kann jedes Steuerelement so konfiguriert werden, dass es eine partielle Seitenaktualisierung auslöst.

Ebenso kann das <asp:PostBackTrigger> Element verwendet werden, um ein teilweises Seitenrendern auszulösen, das jedoch einen vollständigen Roundtrip zum Server erfordert. Dieses Triggerelement kann auch verwendet werden, um das Rendern einer ganzen Seite zu erzwingen, wenn ein Steuerelement andernfalls normalerweise einen teilweisen Seitenrendering auslöst (z. B. wenn ein Button Steuerelement im <ContentTemplate> Element eines UpdatePanel-Steuerelements vorhanden ist). Auch hier kann das PostBackTrigger-Element jedes Steuerelements angeben, das ein untergeordnetes Element eines UpdatePanel-Steuerelements in der aktuellen Kapselungseinheit ist.

<Trigger-Elementreferenz>

Markup-Nachkommen:

Etikett Beschreibung
<asp:AsyncPostBackTrigger> Gibt ein Steuerelement und ein Ereignis an, das zu einer teilweisen Seitenaktualisierung für das UpdatePanel führt, das diesen Triggerverweis enthält.
<asp:PostBackTrigger> Gibt ein Steuerelement und ein Ereignis an, das zu einer vollständigen Seitenaktualisierung führt. Dieses Tag kann verwendet werden, um eine vollständige Aktualisierung zu erzwingen, wenn ein Steuerelement andernfalls partielles Rendering auslöst.

Anleitung: Cross-UpdatePanel-Trigger

  1. Erstellen Sie eine neue ASP.NET Seite mit einem ScriptManager-Objektsatz, um das teilweise Rendering zu aktivieren. Fügen Sie dieser Seite zwei UpdatePanels hinzu – fügen Sie zunächst ein Bezeichnungssteuerelement ( Label1 ) und zwei Schaltflächensteuerelemente ( Button1 und Button2 ) hinzu. Schaltfläche1 sollte "Klicken, um beides zu aktualisieren" sagen, und Schaltfläche2 sollte "Klicken, um dies zu aktualisieren" sagen oder etwas Ähnliches. Fügen Sie im zweiten UpdatePanel nur ein Bezeichnungssteuerelement (Label2) hinzu, legen Sie jedoch die ForeColor-Eigenschaft auf einen anderen Wert als den Standardwert fest, um es zu unterscheiden.
  2. Legen Sie die UpdateMode-Eigenschaft beider UpdatePanel-Tags auf "Bedingt" fest.

Eintrag 1: Markup für default.aspx:



<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
   <head runat="server">
      <title>Untitled Page</title>
   </head>
   <body>
      <form id="form1" runat="server">
         <asp:ScriptManager EnablePartialRendering="true"
            ID="ScriptManager1" runat="server"></asp:ScriptManager>
         <div>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server"
               UpdateMode="Conditional">
               <ContentTemplate>
                  <asp:Label ID="Label1" runat="server" />
                  <br />
                  <asp:Button ID="Button1" runat="server"
                     Text="Update Both Panels" OnClick="Button1_Click" />
                  <asp:Button ID="Button2" runat="server"
                     Text="Update This Panel" OnClick="Button2_Click" />
               </ContentTemplate>
            </asp:UpdatePanel>
            <asp:UpdatePanel ID="UpdatePanel2" runat="server"
               UpdateMode="Conditional">
               <ContentTemplate>
                  <asp:Label ID="Label2" runat="server" ForeColor="red" />
               </ContentTemplate>
               <Triggers>
                  <asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
               </Triggers>
            </asp:UpdatePanel>
         </div>
      </form>
   </body>
</html>

  1. Im Click-Ereignishandler für Button1 setzen Sie "Label1.Text" und "Label2.Text" auf einen zeitabhängigen Wert, wie etwa DateTime.Now.ToLongTimeString(). Legen Sie für den Click-Ereignishandler für Button2 nur "Label1.Text" auf den zeitabhängigen Wert fest.

Auflistung 2: Codebehind (gekürzt) in default.aspx.cs:

public partial class _Default : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToLongTimeString();
        Label2.Text = DateTime.Now.ToLongTimeString();
    }
    protected void Button2_Click(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToLongTimeString();
    }
}
  1. Drücken Sie F5, um das Projekt zu erstellen und auszuführen. Beachten Sie, dass beim Klicken auf "Beide Bereiche aktualisieren" beide Beschriftungen ihren Text ändern; wenn Sie jedoch auf "Diesen Bereich aktualisieren" klicken, wird nur Label1 aktualisiert.

Screenshot der ersten Schaltfläche mit dem Status

(Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Unter der Haube

Mit dem eben erstellten Beispiel können wir uns ansehen, was ASP.NET AJAX tut und wie unsere Panel-übergreifenden Trigger im UpdatePanel funktionieren. Dazu arbeiten wir mit dem generierten Seitenquell-HTML sowie der Mozilla Firefox-Erweiterung FireBug - damit können wir die AJAX-Postbacks problemlos untersuchen. Wir werden auch das .NET Reflector Tool von Lutz Roeder verwenden. Beide Tools sind kostenlos online verfügbar und können mit einer Internetsuche gefunden werden.

Eine Untersuchung des Seitenquellcodes zeigt fast nichts Ungewöhnliches; die UpdatePanel-Steuerelemente werden als <div> Container gerendert, und wir sehen, dass die Skriptressource von der <asp:ScriptManager> bereitgestellt wird. Es gibt auch neue AJAX-spezifische Aufrufe des PageRequestManager, die sich intern in der AJAX-Clientskriptbibliothek befinden. Schließlich sehen wir die beiden UpdatePanel-Container – einer mit den gerenderten <input>-Schaltflächen, wobei die beiden <asp:Label>-Steuerelemente als <span>-Container gerendert werden. (Wenn Sie die DOM-Struktur in FireBug prüfen, werden Sie feststellen, dass die Beschriftungen abgeblendet sind, um anzugeben, dass sie keine sichtbaren Inhalte erzeugen).

Klicken Sie auf die Schaltfläche "Dieses Panel aktualisieren", und stellen Sie fest, dass das obere UpdatePanel mit der aktuellen Serverzeit aktualisiert wird. Wählen Sie in FireBug die Registerkarte "Konsole" aus, damit Sie die Anforderung untersuchen können. Überprüfen Sie zuerst die POST-Anforderungsparameter:

Screenshot eines Firebug-Dialogfelds mit ausgewählter Konsole.

(Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Beachten Sie, dass das UpdatePanel dem serverseitigen AJAX-Code genau angegeben hat, welche Steuerelementstruktur durch den ScriptManager1-Parameter ausgelöst wurde: das Steuerelement Button1 des Steuerelements UpdatePanel1. Klicken Sie nun auf die Schaltfläche "Beide Bereiche aktualisieren". Bei der Untersuchung der Antwort erscheint eine pipe-getrennte Serie von Variablen, die in einer Zeichenfolge festgelegt sind; insbesondere erscheint das oberste UpdatePanel, UpdatePanel1, das seinen gesamten HTML-Inhalt an den Browser gesendet hat. Die AJAX-Clientskriptbibliothek ersetzt den ursprünglichen HTML-Inhalt von UpdatePanel durch den neuen Inhalt über die .innerHTML Eigenschaft, sodass der Server den geänderten Inhalt vom Server als HTML sendet.

Klicken Sie nun auf die Schaltfläche "Beide Bereiche aktualisieren", und überprüfen Sie die Ergebnisse vom Server. Die Ergebnisse sind sehr ähnlich - beide UpdatePanels erhalten neue HTML vom Server. Wie beim vorherigen Callback wird der zusätzliche Seitenstatus gesendet.

Wie wir sehen können, kann die AJAX-Clientskriptbibliothek Formularpostbacks ohne zusätzlichen Code abfangen, da kein spezieller Code zum Ausführen eines AJAX-Postbacks verwendet wird. Serversteuerelemente nutzen JavaScript automatisch, sodass sie das Formular nicht automatisch übermitteln – ASP.NET injiziert automatisch bereits Code für die Formularüberprüfung und den Zustand, in erster Linie durch den Einschluss von Skriptressourcen, die PostBackOptions-Klasse und die ClientScriptManager-Klasse.

Ziehen Sie beispielsweise ein CheckBox-Steuerelement in Betracht; untersuchen Sie die Klassenmontage in .NET Reflector. Stellen Sie hierzu sicher, dass Ihre System.Web-Assembly geöffnet ist, und navigieren Sie zur System.Web.UI.WebControls.CheckBox Klasse, und öffnen Sie die RenderInputTag Methode. Suchen Sie nach einer Bedingung, die die AutoPostBack Eigenschaft überprüft:

Screenshot mit Code, der mit

(Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Wenn das automatische Postback für ein CheckBox Steuerelement (über die AutoPostBack-Eigenschaft "true") aktiviert ist, wird das resultierende <input> Tag daher mit einem ASP.NET Ereignisbehandlungsskript in seinem onclick Attribut gerendert. Das Abfangen der Übermittlung des Formulars ermöglicht es dann, ASP.NET AJAX nicht in die Seite einzufügen, wodurch potenzielle Unterbrechungsänderungen vermieden werden können, die durch die Verwendung einer möglicherweise ungenauen Zeichenfolgenersetzung auftreten können. Darüber hinaus kann jedes benutzerdefinierte ASP.NET-Steuerelement die Leistungsfähigkeit von ASP.NET AJAX ohne zusätzlichen Code nutzen, um die Verwendung in einem UpdatePanel-Container zu unterstützen.

Die <triggers> Funktionalität entspricht den Werten, die im PageRequestManager-Aufruf an _updateControls initialisiert werden (beachten Sie, dass die ASP.NET AJAX-Clientskriptbibliothek die Konvention verwendet, die Methoden, Ereignisse und Feldnamen, die mit einem Unterstrich beginnen, als intern gekennzeichnet sind und nicht für die Verwendung außerhalb der Bibliothek selbst vorgesehen sind). Damit können wir beobachten, welche Steuerelemente AJAX-Postbacks verursachen sollen.

Angenommen, wir fügen der Seite zwei zusätzliche Steuerelemente hinzu, wobei ein Steuerelement vollständig außerhalb der UpdatePanels bleibt und eines innerhalb eines UpdatePanels platziert wird. Wir werden ein CheckBox-Steuerelement im oberen UpdatePanel hinzufügen und eine DropDownList einfügen, die eine Auswahl an definierten Farben enthält. Hier ist das neue Markup:

Auflistung 3: Neues Markup

<%@ Page Language="C#" AutoEventWireup="true"
 CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
 <head id="Head1" runat="server">
 <title>Untitled Page</title>
 </head>
 <body>
 <form id="form1" runat="server">
 <asp:ScriptManager EnablePartialRendering="true"
 ID="ScriptManager1" runat="server"></asp:ScriptManager>
 <div>
 <asp:UpdatePanel ID="UpdatePanel1" runat="server"
 UpdateMode="Conditional">
 <ContentTemplate>
 <asp:Label ID="Label1" runat="server" /><br />
 <asp:Button ID="Button1" runat="server"
 Text="Update Both Panels" OnClick="Button1_Click" />
 <asp:Button ID="Button2" runat="server"
 Text="Update This Panel" OnClick="Button2_Click" />
 <asp:CheckBox ID="cbDate" runat="server"
 Text="Include Date" AutoPostBack="false"
 OnCheckedChanged="cbDate_CheckedChanged" />
 </ContentTemplate>
 </asp:UpdatePanel>
 <asp:UpdatePanel ID="UpdatePanel2" runat="server"
 UpdateMode="Conditional">
 <ContentTemplate>
 <asp:Label ID="Label2" runat="server"
 ForeColor="red" />
 </ContentTemplate>
 <Triggers>
 <asp:AsyncPostBackTrigger ControlID="Button1" 
 EventName="Click" />
 <asp:AsyncPostBackTrigger ControlID="ddlColor" 
 EventName="SelectedIndexChanged" />
 </Triggers>
 </asp:UpdatePanel>
 <asp:DropDownList ID="ddlColor" runat="server"
 AutoPostBack="true"
 OnSelectedIndexChanged="ddlColor_SelectedIndexChanged">
 <asp:ListItem Selected="true" Value="Red" />
 <asp:ListItem Value="Blue" />
 <asp:ListItem Value="Green" />
 </asp:DropDownList>
 </div>
 </form>
 </body>
</html>

Und hier ist der neue CodeBehind:

Eintrag 4: Codebehind

public partial class _Default : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        if (cbDate.Checked)
        {
            Label1.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
            Label2.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
        }
        else
        {
            Label1.Text = DateTime.Now.ToLongTimeString();
            Label2.Text = DateTime.Now.ToLongTimeString();
        }
    }
    protected void Button2_Click(object sender, EventArgs e)
    {
        if (cbDate.Checked)
        {
            Label1.Text = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss");
        }
        else
        {
            Label1.Text = DateTime.Now.ToLongTimeString();
        }
    }
    protected void cbDate_CheckedChanged(object sender, EventArgs e)
    {
        cbDate.Font.Bold = cbDate.Checked;
    }
    protected void ddlColor_SelectedIndexChanged(object sender, EventArgs e)
    {
        Color c = Color.FromName(ddlColor.SelectedValue);
        Label2.ForeColor = c;
    }
}

Die Idee hinter dieser Seite besteht darin, dass die Dropdownliste eine von drei Farben auswählt, um die zweite Beschriftung anzuzeigen, dass das Kontrollkästchen bestimmt, ob es fett formatiert ist und ob die Beschriftungen das Datum sowie die Uhrzeit anzeigen. Das Kontrollkästchen sollte kein AJAX-Update verursachen, aber die Dropdownliste sollte, auch wenn es nicht in einem UpdatePanel untergebracht ist.

Screenshot eines Webbrowsers mit dem Namen

(Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Wie im obigen Screenshot ersichtlich, war die zuletzt angeklickte Schaltfläche die rechte Schaltfläche "Diesen Bereich aktualisieren", die die obere Zeit unabhängig von der unteren Zeit aktualisiert hat. Das Datum wurde auch zwischen den Klicks ausgeschaltet, da es in der unteren Beschriftung sichtbar ist. Schließlich ist die Farbe der unteren Beschriftung von Interesse: Sie wurde vor kürzerer Zeit als der Text der Bezeichnung aktualisiert, was zeigt, dass der Zustand der Steuerung wichtig ist und Benutzer erwarten, dass er bei AJAX-Postbacks erhalten bleibt. Die Zeit wurde jedoch nicht aktualisiert. Die Zeit wurde automatisch mithilfe der Persistenz des __VIEWSTATE-Feldes auf der Seite aufgefüllt, das von der ASP.NET-Laufzeit interpretiert wurde, als das Steuerelement auf dem Server erneut gerendert wurde. Der ASP.NET AJAX-Servercode erkennt nicht, in welchen Methoden Steuerelemente ihren Zustand ändern; er lädt einfach erneut aus dem Ansichtszustand und führt anschließend die entsprechenden Ereignisse aus.

Man sollte jedoch darauf hinweisen, dass, wenn ich die Zeit innerhalb des Page_Load-Ereignisses hätte initialisiert, die Zeit korrekt erhöht worden wäre. Daher sollten Entwickler darauf achten, dass der entsprechende Code während der korrekten Ereignishandler ausgeführt wird, und die Verwendung von Page_Load vermeiden, wenn ein Steuerelement-Ereignishandler angemessen wäre.

Zusammenfassung

Das ASP.NET AJAX-Erweiterung-UpdatePanel-Steuerelement ist vielseitig und kann eine Reihe von Methoden verwenden, um eventuelle Steuerelementereignisse zu identifizieren, die seine Aktualisierung verursachen sollten. Es unterstützt die automatische Aktualisierung durch die untergeordneten Steuerelemente, kann aber auch auf Steuerelementereignisse an anderer Stelle auf der Seite reagieren.

Um das Potenzial für eine hohe Serverlast zu verringern, wird empfohlen, die Eigenschaft ChildrenAsTriggers eines UpdatePanel auf false festzulegen und Ereignisse gezielt auszuwählen, anstatt sie standardmäßig einzuschließen. Dadurch wird auch verhindert, dass nicht benötigte Ereignisse potenziell unerwünschte Effekte verursachen, einschließlich Validierung und Änderungen an Eingabefeldern. Diese Arten von Fehlern können schwierig zu isolieren sein, da die Seite transparent für den Benutzer aktualisiert wird und die Ursache daher möglicherweise nicht sofort offensichtlich ist.

Durch die Untersuchung der inneren Funktionsweise des ASP.NET AJAX-Formulars nach dem Abfangenmodell konnten wir feststellen, dass es das framework nutzt, das bereits von ASP.NET bereitgestellt wurde. Auf diese Weise wird die maximale Kompatibilität mit Steuerelementen beibehalten, die mit demselben Framework entworfen wurden, und es greift minimal in zusätzliche für die Seite geschriebene JavaScript-Elemente ein.

Biografie

Rob Paveza ist senior .NET-Anwendungsentwickler bei Terralever (www.terralever.com), einer führenden interaktiven Marketingfirma in Tempe, AZ. Er ist erreichbar unter robpaveza@gmail.com, und sein Blog befindet sich in http://geekswithblogs.net/robp/.

Scott Cate arbeitet seit 1997 mit Microsoft Web Technologies zusammen und ist Präsident von myKB.com (www.myKB.com), wo er sich auf das Schreiben ASP.NET basierten Anwendungen spezialisiert hat, die sich auf Knowledge Base-Softwarelösungen konzentrierten. Scott kann per E-Mail oder seinem Blog bei scott.cate@myKB.comScottCate.com kontaktiert werden