Freigeben über


Grundlegendes zu UpdatePanel-Triggern in ASP.NET AJAX

von Scott Cate

Wenn Sie im Markup-Editor in Visual Studio arbeiten, können Sie (von IntelliSense) feststellen, dass es zwei untergeordnete Elemente eines UpdatePanel-Steuerelements gibt. Eines davon ist das Triggers-Element, das die Steuerelemente auf der Seite angibt (oder das Benutzersteuerelement, wenn Sie eines verwenden), das ein partielles Rendern des UpdatePanel-Steuerelements auslöst, in dem sich das Element befindet.

Einführung

Die ASP.NET Technologie von Microsoft bringt ein objektorientiertes und ereignisgesteuertes Programmiermodell und vereint es mit den Vorteilen von kompiliertem Code. Das serverseitige Verarbeitungsmodell hat jedoch mehrere Nachteile der Technologie, von denen viele durch die neuen Features der Microsoft ASP.NET 3.5 AJAX-Erweiterungen behoben werden können. Diese Erweiterungen ermöglichen viele neue umfangreiche Clientfeatures, einschließlich des teilweisen Renderings von Seiten, ohne dass eine vollständige Seitenaktualisierung erforderlich ist, die Möglichkeit, über Clientskripts (einschließlich der ASP.NET Profilerstellungs-API) auf Webdienste zuzugreifen, und eine umfangreiche clientseitige API, die zum Spiegel vieler Steuerungsschemas im ASP.NET serverseitigen Steuerelementsatz entwickelt wurde.

In diesem Whitepaper wird die FUNKTIONALITÄT von XML-Triggern der ASP.NET AJAX-Komponente UpdatePanel untersucht. XML-Trigger bieten eine präzise Kontrolle über die Komponenten, die ein partielles Rendering für bestimmte UpdatePanel-Steuerelemente verursachen können.

Dieses Whitepaper basiert auf der Beta 2-Version der .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 und nicht mit Visual Web Developer Express arbeiten und exemplarische Vorgehensweisen gemäß der Benutzeroberfläche von Visual Studio bereitstellen (obwohl Codeauflistungen unabhängig von der Entwicklungsumgebung vollständig kompatibel sind).

Trigger

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 mithilfe von Markup eingeschlossen werden. dies erfolgt im <triggers> Abschnitt der UpdatePanel-Steuerelementdeklaration. Obwohl über die Triggers Auflistungseigenschaft auf Trigger zugegriffen werden kann, wird empfohlen, alle partiellen Rendertrigger zur Laufzeit zu registrieren (für instance, 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 neu registrieren, wenn sie erstellt werden.

Die automatische Aufnahme untergeordneter Trigger kann auch deaktiviert werden (sodass untergeordnete Steuerelemente, die Postbacks erstellen, nicht automatisch Teilrenderungen auslösen), indem sie die ChildrenAsTriggers -Eigenschaft auf false festlegen. 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 möglicherweise auftretende Ereignisse zu behandeln.

Beachten Sie, dass bei geschachtelten UpdatePanel-Steuerelementen, wenn updateMode auf Bedingt festgelegt ist, wenn das untergeordnete UpdatePanel ausgelöst wird, aber nicht das übergeordnete Element, nur das untergeordnete UpdatePanel aktualisiert wird. Wenn jedoch das übergeordnete UpdatePanel aktualisiert wird, wird auch das untergeordnete UpdatePanel aktualisiert.

Das <Triggers-Element>

Wenn Sie im Markup-Editor in Visual Studio arbeiten, können Sie (aus IntelliSense) feststellen, dass es zwei untergeordnete Elemente eines Steuerelements UpdatePanel gibt. Das am häufigsten zu sehende Element ist das <ContentTemplate> -Element, das im Wesentlichen den Inhalt kapselt, der im Updatebereich gespeichert wird (der Inhalt, für den wir ein partielles Rendering aktivieren). Das andere Element ist das <Triggers> -Element, das die Steuerelemente auf der Seite angibt (oder das Benutzersteuerelement, wenn Sie eines verwenden), das einen teilweisen Rendervorgang 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 und ControlIDEventNameund können jedes Steuerelement innerhalb der aktuellen Kapselungseinheit angeben (für instance sollten Sie nicht versuchen, auf ein Steuerelement auf der Seite zu verweisen, auf der sich das Benutzersteuerelement befindet.

Das <asp:AsyncPostBackTrigger> -Element ist besonders nützlich, da es auf jedes Ereignis aus einem Control-Element abzielen kann, das als untergeordnetes Element eines beliebigen UpdatePanel-Steuerelements in der Kapselungseinheit vorhanden ist, nicht nur auf das UpdatePanel, unter dem dieser Trigger ein untergeordnetes Element ist. Daher kann jedes Steuerelement erstellt werden, um eine partielle Seitenaktualisierung auszulösen.

Auf ähnliche Weise kann das <asp:PostBackTrigger> -Element verwendet werden, um ein partielles Seitenrendering auszulösen, das jedoch einen vollständigen Roundtrip zum Server erfordert. Dieses Triggerelement kann auch verwendet werden, um ein vollständiges Seitenrendering zu erzwingen, wenn ein Steuerelement sonst normalerweise ein partielles Seitenrendering auslöst (für instance, wenn ein Button Steuerelement im <ContentTemplate> Element eines UpdatePanel-Steuerelements vorhanden ist). Auch hier kann das PostBackTrigger-Element jedes Steuerelement angeben, das ein untergeordnetes Element eines beliebigen UpdatePanel-Steuerelements in der aktuellen Kapselungseinheit ist.

<Triggers-Elementreferenz>

Markupnachstamm:

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

Exemplarische Vorgehensweise: Cross-UpdatePanel-Trigger

  1. Erstellen Sie eine neue ASP.NET Seite, auf der ein ScriptManager-Objekt festgelegt ist, um das partielle Rendering zu ermöglichen. Fügen Sie dieser Seite zwei UpdatePanels hinzu– im ersten ein Label-Steuerelement ( Label1 ) und zwei Button-Steuerelemente ( Button1 und Button2 ). Button1 sollte click to update both sagen, und Button2 sollte Click to Update This oder etwas in dieser Richtung sagen. Schließen Sie im zweiten UpdatePanel nur ein Label-Steuerelement ( Label2 ) ein, aber legen Sie dessen ForeColor-Eigenschaft auf etwas anderes als den Standardwert fest, um es zu unterscheiden.
  2. Legen Sie die UpdateMode-Eigenschaft beider UpdatePanel-Tags auf Bedingt fest.

Auflistung 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. Legen Sie im Click-Ereignishandler für Button1 Label1.Text und Label2.Text auf etwas zeitabhängiges fest (z. B. DateTime.Now.ToLongTimeString()). Legen Sie für den Click-Ereignishandler für Button2 nur Label1.Text auf den zeitabhängigen Wert fest.

Listing 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 Bezeichnungen Text ändern. Wenn Sie jedoch auf Diesen Bereich aktualisieren klicken, wird nur Label1 aktualisiert.

Screenshot: erste Schaltfläche mit dem Status

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

Unter der Haube

Anhand des soeben erstellten Beispiels können wir einen Blick darauf werfen, was ASP.NET AJAX tut und wie die panelübergreifenden UpdatePanel-Trigger funktionieren. Dazu arbeiten wir mit dem generierten Seitenquell-HTML sowie mit 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 online frei verfügbar und können mit einer Internetsuche gefunden werden.

Eine Untersuchung des Seitenquellcodes zeigt fast nichts Außergewöhnliches; Die UpdatePanel-Steuerelemente werden als <div> Container gerendert, und wir können sehen, wie die Skriptressource enthält, die <asp:ScriptManager>von bereitgestellt wird. Es gibt auch einige neue AJAX-spezifische Aufrufe für den PageRequestManager, die in der AJAX-Clientskriptbibliothek intern sind. Schließlich sehen wir die beiden UpdatePanel-Container – einen mit den gerenderten <input> Schaltflächen mit den beiden <asp:Label> Steuerelementen, die als <span> Container gerendert werden. (Wenn Sie die DOM-Struktur in FireBug untersuchen, werden Sie feststellen, dass die Bezeichnungen abgeblendet sind, um anzugeben, dass sie keine sichtbaren Inhalte erzeugen.)

Klicken Sie auf die Schaltfläche Diesen Bereich aktualisieren, und beachten Sie, dass das oberste UpdatePanel mit der aktuellen Serverzeit aktualisiert wird. Wählen Sie in FireBug die Registerkarte Konsole aus, damit Sie die Anforderung untersuchen können. Untersuchen Sie zuerst die POST-Anforderungsparameter:

Screenshot: Firebug-Dialogfeld mit ausgewählter Konsole

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

Beachten Sie, dass updatePanel dem serverseitigen AJAX-Code genau angegeben hat, welche Steuerelementstruktur über den ScriptManager1-Parameter Button1 des -Steuerelements UpdatePanel1 ausgelöst wurde. Klicken Sie nun auf die Schaltfläche Beide Bereiche aktualisieren. Wenn wir dann die Antwort untersuchen, sehen wir eine durch Pipe getrennte Reihe von Variablen, die in einer Zeichenfolge festgelegt sind. Insbesondere sehen wir, dass das oberste UpdatePanel, UpdatePanel1, den gesamten HTML-Code 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 des Servers. Die Ergebnisse sind sehr ähnlich: Beide UpdatePanels erhalten neues HTML vom Server. Wie beim vorherigen Rückruf wird ein zusätzlicher Seitenzustand gesendet.

Wie wir sehen, kann die AJAX-Clientskriptbibliothek Formularpostbacks ohne zusätzlichen Code abfangen, da kein spezieller Code zum Ausführen eines AJAX-Postbacks verwendet wird. Serversteuerelemente verwenden automatisch JavaScript, sodass sie das Formular nicht automatisch übermitteln. ASP.NET fügt automatisch Code für die Formularüberprüfung und den Zustand bereits ein, was in erster Linie durch automatische Skriptressourceneinschluss, die PostBackOptions-Klasse und die ClientScriptManager-Klasse erreicht wird.

Betrachten Sie für instance ein CheckBox-Steuerelement. Untersuchen Sie die Klassen disassembliert in .NET Reflector. Stellen Sie hierzu sicher, dass Ihre System.Web-Assembly geöffnet ist, und navigieren Sie zur -Klasse, und System.Web.UI.WebControls.CheckBox öffnen Sie die RenderInputTag -Methode. Suchen Sie nach einer Bedingung, die die AutoPostBack Eigenschaft überprüft:

Screenshot: Code, der mit

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

Wenn das automatische Postback für ein CheckBox Steuerelement aktiviert ist (über die AutoPostBack-Eigenschaft true), 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 unauffällig in die Seite einzufügen, was dazu beiträgt, potenzielle Breaking Changes zu vermeiden, die durch die Verwendung einer möglicherweise ungenauen Zeichenfolgenersetzung auftreten könnten. Darüber hinaus ermöglicht dies jedem benutzerdefinierten ASP.NET-Steuerelement, die Leistungsfähigkeit ASP.NET AJAX ohne zusätzlichen Code zu nutzen, um die Verwendung in einem UpdatePanel-Container zu unterstützen.

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

Beispielsweise fügen wir der Seite zwei zusätzliche Steuerelemente hinzu, wobei ein Steuerelement außerhalb der UpdatePanels vollständig bleibt und eines in einem UpdatePanel-Element belassen wird. Wir fügen ein CheckBox-Steuerelement im oberen UpdatePanel hinzu und löschen eine DropDownList mit einer Reihe von Farben, die in der Liste definiert sind. Hier sehen Sie das neue Markup:

Eintrag 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 das 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 Bezeichnung anzuzeigen, dass das Kontrollkästchen sowohl bestimmt, ob es fett ist, als auch, ob die Bezeichnungen das Datum und die Uhrzeit anzeigen. Das Kontrollkästchen sollte kein AJAX-Update verursachen, aber die Dropdownliste sollte dies, auch wenn es nicht in einem UpdatePanel-Element enthalten ist.

Screenshot: Webbrowser mit dem Namen

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

Wie im obigen Screenshot zu sehen ist, war die neueste Schaltfläche, auf die geklickt werden sollte, die rechte Schaltfläche Diesen Bereich aktualisieren, die die Topzeit unabhängig von der untersten Zeit aktualisiert hat. Das Datum wurde auch zwischen Klicks deaktiviert, da das Datum in der unteren Beschriftung sichtbar ist. Schließlich ist die Farbe der unteren Bezeichnung von Interesse: Sie wurde vor kurzem aktualisiert als der Text der Bezeichnung, was zeigt, dass der Steuerungszustand wichtig ist, und benutzer erwarten, dass er durch AJAX-Postbacks beibehalten wird. Die Uhrzeit wurde jedoch nicht aktualisiert. Die Zeit wurde durch die Persistenz des __VIEWSTATE Felds der Seite, die von der ASP.NET Runtime interpretiert wurde, automatisch neu aufgefüllt, als das Steuerelement auf dem Server erneut gerendert wurde. Der ASP.NET AJAX-Servercode erkennt nicht, in welchen Methoden die Steuerelemente den Zustand ändern. Es wird einfach aus dem Ansichtszustand neu aufgefüllt und dann die geeigneten Ereignisse ausgeführt.

Es sollte jedoch darauf hingewiesen werden, dass, wenn ich die Zeit innerhalb des Page_Load Ereignisses initialisiert hätte, die Zeit korrekt erhöht worden wäre. Daher sollten Entwickler vorsichtig sein, dass der entsprechende Code während der entsprechenden Ereignishandler ausgeführt wird, und die Verwendung von Page_Load vermeiden, wenn ein Steuerelementereignishandler geeignet wäre.

Zusammenfassung

Das updatePanel-Steuerelement ASP.NET AJAX-Erweiterungen ist vielseitig und kann eine Reihe von Methoden zum Identifizieren von Steuerelementereignissen verwenden, die zu einer Aktualisierung führen 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 die Serververarbeitung zu verringern, wird empfohlen, die ChildrenAsTriggers -Eigenschaft eines UpdatePanel-Elements auf falsefestzulegen, und dass Ereignisse aktiviert und nicht standardmäßig eingeschlossen werden. 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 für den Benutzer transparent aktualisiert wird und die Ursache daher möglicherweise nicht sofort offensichtlich ist.

Durch Die Untersuchung des inneren Funktionierens des ASP.NET AJAX-Formularmodells nach dem Abfangen konnten wir feststellen, dass es das bereits von ASP.NET bereitgestellte Framework verwendet. Auf diese Weise wird eine maximale Kompatibilität mit Steuerelementen beibehalten, die mit demselben Framework entworfen wurden, und es wird nur minimal in alle zusätzlichen JavaScript-Elemente eingegriffen, die für die Seite geschrieben wurden.

Biografie

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

Scott Cate arbeitet seit 1997 mit Microsoft-Webtechnologien und ist President von myKB.com (www.myKB.com), wo er sich auf das Schreiben von ASP.NET basierten Anwendungen spezialisiert hat, die sich auf Knowledge Base-Softwarelösungen konzentrieren. Scott kann per E-Mail unter scott.cate@myKB.com oder seinem Blog unter ScottCate.com