Archiviazione di informazioni utente aggiuntive (C#)

di Scott Mitchell

Nota

Poiché questo articolo è stato scritto, i provider di appartenenza ASP.NET sono stati sostituiti da ASP.NET Identity. È consigliabile aggiornare le app per usare la ASP.NET Identity Platform anziché i provider di appartenenza in primo piano al momento della scrittura di questo articolo. ASP.NET Identity offre numerosi vantaggi rispetto al sistema di appartenenza ASP.NET, tra cui :

  • Prestazioni migliori
  • Miglioramento dell'estendibilità e della testability
  • Supporto per OAuth, OpenID Connect e autenticazione a due fattori
  • Supporto delle identità basate sulle attestazioni
  • Interoperabilità migliore con ASP.Net Core

Scaricare codice o scaricare pdf

Questa esercitazione risponderà a questa domanda creando un'applicazione guestbook molto rudimentaria. A tale scopo, verranno esaminate diverse opzioni per la modellazione delle informazioni utente in un database e quindi verrà illustrato come associare questi dati agli account utente creati dal framework Di appartenenza.

Introduzione

ASP. Il framework di appartenenza di NET offre un'interfaccia flessibile per la gestione degli utenti. L'API Appartenenza include metodi per la convalida delle credenziali, il recupero di informazioni sull'utente attualmente connesso, la creazione di un nuovo account utente e l'eliminazione di un account utente, tra gli altri. Ogni account utente nel framework di appartenenza contiene solo le proprietà necessarie per convalidare le credenziali ed eseguire attività essenziali relative all'account utente. Ciò è evidenziato dai metodi e dalle proprietà della MembershipUser classe, che modella un account utente nel framework Di appartenenza. Questa classe include proprietà come UserName, Emaile IsLockedOute metodi come GetPassword e UnlockUser.

Spesso, le applicazioni devono archiviare informazioni utente aggiuntive non incluse nel framework di appartenenza. Ad esempio, un rivenditore online potrebbe dover consentire a ogni utente di archiviare gli indirizzi di spedizione e fatturazione, le informazioni di pagamento, le preferenze di consegna e il numero di telefono di contatto. Inoltre, ogni ordine nel sistema è associato a un determinato account utente.

La MembershipUser classe non include proprietà come PhoneNumber o DeliveryPreferencesPastOrders. Come è quindi possibile tenere traccia delle informazioni utente necessarie dall'applicazione e integrarla con il framework di appartenenza? Questa esercitazione risponderà a questa domanda creando un'applicazione guestbook molto rudimentaria. A tale scopo, verranno esaminate diverse opzioni per la modellazione delle informazioni utente in un database e quindi verrà illustrato come associare questi dati agli account utente creati dal framework Di appartenenza. È possibile iniziare subito.

Passaggio 1: Creazione del modello di dati dell'applicazione Guestbook

Esistono diverse tecniche che possono essere usate per acquisire informazioni utente in un database e associarlo agli account utente creati dal framework Di appartenenza. Per illustrare queste tecniche, sarà necessario aumentare l'applicazione Web dell'esercitazione in modo che acquisisca alcuni tipi di dati correlati all'utente. Attualmente, il modello di dati dell'applicazione contiene solo le tabelle dei servizi applicazione necessarie da SqlMembershipProvider.)

Verrà creata un'applicazione guestbook molto semplice in cui un utente autenticato può lasciare un commento. Oltre a archiviare i commenti del guestbook, è possibile consentire a ogni utente di archiviare la propria città, la home page e la firma. Se specificato, la città principale dell'utente, la home page e la firma verranno visualizzati su ogni messaggio che ha lasciato nel guestbook.

Aggiunta dellaGuestbookCommentstabella

Per acquisire i commenti del guestbook, è necessario creare una tabella di database denominata GuestbookComments con colonne come CommentId, Subject, Bodye CommentDate. È anche necessario avere ogni record nella GuestbookComments tabella che fa riferimento all'utente che ha lasciato il commento.

Per aggiungere questa tabella al database, passare a Esplora database in Visual Studio ed eseguire il drill-down nel SecurityTutorials database. Fare clic con il pulsante destro del mouse sulla cartella Tabelle e scegliere Aggiungi nuova tabella. In questo modo viene visualizzata un'interfaccia che consente di definire le colonne per la nuova tabella.

Aggiungere una nuova tabella al database SecurityTutorials

Figura 1: Aggiungere una nuova tabella al SecurityTutorials database (fare clic per visualizzare l'immagine full-size)

Definire quindi le GuestbookCommentscolonne di . Iniziare aggiungendo una colonna denominata CommentId di tipo uniqueidentifier. Questa colonna identificherà in modo univoco ogni commento nel guestbook, quindi non consentire NULL e contrassegnarlo come chiave primaria della tabella. Anziché specificare un valore per il CommentId campo in ogni INSERToggetto , è possibile indicare che un nuovo uniqueidentifier valore deve essere generato automaticamente per questo campo impostando INSERT il valore predefinito della colonna su NEWID(). Dopo aver aggiunto questo primo campo, contrassegnandolo come chiave primaria e impostandone il valore predefinito, la schermata dovrebbe essere simile alla schermata visualizzata nella figura 2.

Aggiungere una colonna primaria denominata CommentId

Figura 2: Aggiungere una colonna primaria denominata CommentId (fare clic per visualizzare l'immagine full-size)

Aggiungere quindi una colonna denominata di tipo e una colonna denominata SubjectBody di tipo nvarchar(50)nvarchar(MAX), disallowing NULL s in entrambe le colonne. Successivamente, aggiungere una colonna denominata CommentDate di tipo datetime. Non consentire NULL s e impostare il CommentDate valore predefinito della colonna su getdate().

Tutto ciò che rimane consiste nell'aggiungere una colonna che associa un account utente a ogni commento del guestbook. Un'opzione consiste nell'aggiungere una colonna denominata UserName di tipo nvarchar(256). Questa è una scelta adatta quando si usa un provider di appartenenza diverso da SqlMembershipProvider. Tuttavia, quando si usa SqlMembershipProvider, come si è in questa serie di esercitazioni, la UserName colonna nella aspnet_Users tabella non è garantita univoca. La aspnet_Users chiave primaria della tabella è e è UserId di tipo uniqueidentifier. Pertanto, la GuestbookComments tabella richiede una colonna denominata UserId di tipo uniqueidentifier (non consentiti NULL valori). Andare avanti e aggiungere questa colonna.

Nota

Come illustrato nell'esercitazione Creazione dello schema di appartenenza in SQL Server, il framework di appartenenza è progettato per abilitare più applicazioni Web con account utente diversi per condividere lo stesso archivio utenti. Questa operazione viene eseguita partizionando gli account utente in applicazioni diverse. Mentre ogni nome utente è garantito essere univoco all'interno di un'applicazione, lo stesso nome utente può essere usato in applicazioni diverse usando lo stesso archivio utenti. Esiste un vincolo composito UNIQUE nella aspnet_Users tabella UserName sui campi e ApplicationId , ma non uno solo sul UserName campo. Di conseguenza, è possibile che la tabella aspnet_Users disponga di due record (o più) con lo stesso UserName valore. Esiste tuttavia un UNIQUE vincolo sul aspnet_Users campo della UserId tabella (poiché è la chiave primaria). Un UNIQUE vincolo è importante perché senza non è possibile stabilire un vincolo di chiave esterna tra le GuestbookComments tabelle e aspnet_Users .

Dopo aver aggiunto la colonna, salvare la UserId tabella facendo clic sull'icona Salva nella barra degli strumenti. Denominare la nuova tabella GuestbookComments.

È necessario GuestbookComments creare un vincolo di chiave esterna tra la colonna e la GuestbookComments.UserIdaspnet_Users.UserId colonna. A questo scopo, fare clic sull'icona Relazione nella barra degli strumenti per avviare la finestra di dialogo Relazioni chiave esterna. In alternativa, è possibile avviare questa finestra di dialogo passando al menu Tabella Designer e scegliendo Relazioni.

Fare clic sul pulsante Aggiungi nell'angolo inferiore sinistro della finestra di dialogo Relazioni chiave esterna. Verrà aggiunto un nuovo vincolo di chiave esterna, anche se è comunque necessario definire le tabelle che partecipano alla relazione.

Utilizzare la finestra di dialogo Relazioni chiave esterna per gestire i vincoli di chiave esterna di una tabella

Figura 3: Usare la finestra di dialogo Relazioni chiave esterna per gestire i vincoli di chiave esterna di una tabella (fare clic per visualizzare l'immagine full-size)

Fare quindi clic sull'icona dei puntini di sospensione nella riga "Specifiche tabella e colonne" a destra. Verrà avviata la finestra di dialogo Tabelle e colonne, da cui è possibile specificare la tabella e la colonna chiave primaria e la colonna chiave esterna dalla GuestbookComments tabella. In particolare, selezionare aspnet_Users e UserId come tabella e colonna chiave primaria e UserId dalla GuestbookComments tabella come colonna chiave esterna (vedere la figura 4). Dopo aver definito le tabelle e le colonne chiave primaria ed esterna, fare clic su OK per tornare alla finestra di dialogo Relazioni chiave esterna.

Stabilire un vincolo di chiave esterna tra le tabelle aspnet_Users e GuesbookComments

Figura 4: Stabilire un vincolo di chiave esterna tra le aspnet_Users tabelle e GuesbookComments (fare clic per visualizzare l'immagine full-size)

A questo punto è stato stabilito il vincolo di chiave esterna. La presenza di questo vincolo garantisce l'integrità relazionale tra le due tabelle garantendo che non vi sarà mai una voce del guestbook che fa riferimento a un account utente non esistente. Per impostazione predefinita, un vincolo di chiave esterna non consente l'eliminazione di un record padre se sono presenti record figlio corrispondenti. In questo caso, se un utente effettua uno o più commenti del guestbook e quindi si tenta di eliminare l'account utente, l'eliminazione avrà esito negativo a meno che i commenti del guestbook non vengano eliminati prima.

I vincoli di chiave esterna possono essere configurati per eliminare automaticamente i record figlio associati quando viene eliminato un record padre. In altre parole, è possibile configurare questo vincolo di chiave esterna in modo che le voci del guestbook di un utente vengano eliminate automaticamente quando l'account utente viene eliminato. A tale scopo, espandere la sezione "INSERT and UPDATE Specification" e impostare la proprietà "Delete Rule" su Cascade.

Configurare il vincolo di chiave esterna in Eliminazioni a catena

Figura 5: Configurare il vincolo chiave esterna in Elimina a catena (fare clic per visualizzare l'immagine a dimensioni complete)

Per salvare il vincolo di chiave esterna, fare clic sul pulsante Chiudi per uscire dalle relazioni con chiavi esterne. Fare quindi clic sull'icona Salva nella barra degli strumenti per salvare la tabella e la relazione.

Archiviazione della home town, della home page e della firma dell'utente

La GuestbookComments tabella illustra come archiviare informazioni che condividono una relazione uno-a-molti con gli account utente. Poiché ogni account utente può avere un numero arbitrario di commenti associati, questa relazione viene modellata creando una tabella per contenere il set di commenti che include una colonna che collega ogni commento a un determinato utente. Quando si usa SqlMembershipProvider, questo collegamento è meglio stabilito creando una colonna denominata UserId di tipo uniqueidentifier e un vincolo di chiave esterna tra questa colonna e aspnet_Users.UserId.

È ora necessario associare tre colonne a ogni account utente per archiviare la città principale, la home page e la firma dell'utente, che verrà visualizzata nei commenti del suo guestbook. Esistono diversi modi per eseguire questa operazione:

  • Aggiungere nuove colonne all'oggettoaspnet_UsersOaspnet_MembershipTabelle. Non è consigliabile questo approccio perché modifica lo schema usato da SqlMembershipProvider. Questa decisione potrebbe tornare a stentare la strada. Ad esempio, cosa accade se una versione futura di ASP.NET usa uno schema diverso SqlMembershipProvider . Microsoft può includere uno strumento per eseguire la migrazione dei dati ASP.NET 2.0 al nuovo schema, ma se è stato modificato lo schema ASP.NET 2.0 SqlMembershipProviderSqlMembershipProvider , tale conversione potrebbe non essere possibile.

  • Usare ASP. Framework profilo di NET, definizione di una proprietà del profilo per la città principale, la home page e la firma. ASP.NET include un framework di profilo progettato per archiviare dati specifici dell'utente aggiuntivi. Analogamente al framework Di appartenenza, il framework del profilo viene compilato in cima al modello del provider. .NET Framework viene fornito con uno sthat archivia i dati del profilo in un SqlProfileProvider database SQL Server. Infatti, il database ha già la tabella usata da SqlProfileProvider (aspnet_Profile), come è stato aggiunto quando sono stati aggiunti i servizi dell'applicazione nell'esercitazione Creazione dello schema di appartenenza in SQL Server.
    Il vantaggio principale del framework profile è che consente agli sviluppatori di definire le proprietà del profilo in Web.config - nessun codice deve essere scritto per serializzare i dati del profilo da e verso l'archivio dati sottostante. In breve, è incredibilmente facile definire un set di proprietà del profilo e usarle nel codice. Tuttavia, il sistema profilo lascia molto da desiderare quando si tratta del controllo delle versioni, quindi se si dispone di un'applicazione in cui si prevede che le nuove proprietà specifiche dell'utente vengano aggiunte in un secondo momento o quelle esistenti da rimuovere o modificare, il framework del profilo potrebbe non essere l'opzione migliore. Inoltre, archivia SqlProfileProvider le proprietà del profilo in modo altamente denormalizzato, rendendo quindi impossibile eseguire query direttamente sui dati del profilo, ad esempio quanti utenti hanno una città principale di New York.
    Per altre informazioni sul framework del profilo, consultare la sezione "Ulteriori letture" alla fine di questa esercitazione.

  • Aggiungere queste tre colonne a una nuova tabella nel database e stabilire una relazione uno-a-uno tra questa tabella easpnet_Users. Questo approccio comporta un po' di lavoro maggiore rispetto al framework Profile, ma offre massima flessibilità nel modo in cui le proprietà utente aggiuntive vengono modellate nel database. Questa è l'opzione che verrà usata in questa esercitazione.

Verrà creata una nuova tabella chiamata UserProfiles per salvare la città principale, la home page e la firma per ogni utente. Fare clic con il pulsante destro del mouse sulla cartella Tabelle nella finestra Esplora database e scegliere di creare una nuova tabella. Assegnare un nome alla prima colonna UserId e impostarne il tipo su uniqueidentifier. Non consentire i valori e contrassegnare NULL la colonna come chiave primaria. Aggiungere quindi colonne denominate: HomeTown di tipo ; HomepageUrl di tipo nvarchar(100)nvarchar(50); e Firma di tipo nvarchar(500). Ognuna di queste tre colonne può accettare un NULL valore.

Creare la tabella UserProfiles

Figura 6: Creare la tabella (fare clic per visualizzare l'immagineUserProfiles full-size)

Salvare la tabella e denominarla UserProfiles. Infine, stabilire un vincolo di chiave esterna tra il UserProfiles campo della UserId tabella e il aspnet_Users.UserId campo. Come è stato fatto con il vincolo di chiave esterna tra le GuestbookComments tabelle e aspnet_Users , è possibile eliminare questo vincolo. Poiché il campo in UserProfiles è la UserId chiave primaria, ciò garantisce che non siano presenti più record nella UserProfiles tabella per ogni account utente. Questo tipo di relazione viene definito uno-a-uno.

Dopo aver creato il modello di dati, è possibile usarlo. Nei passaggi 2 e 3 si esaminerà come l'utente attualmente connesso può visualizzare e modificare le informazioni sulla propria città, home page e firma. Nel passaggio 4 verrà creata l'interfaccia per gli utenti autenticati per inviare nuovi commenti al guestbook e visualizzare quelli esistenti.

Passaggio 2: Visualizzazione della home town, della home page e della firma dell'utente

Esistono diversi modi per consentire all'utente attualmente connesso di visualizzare e modificare la propria città, la home page e le informazioni sulla firma. È possibile creare manualmente l'interfaccia utente con i controlli TextBox e Label oppure usare uno dei controlli Web dati, ad esempio il controllo DetailsView. Per eseguire le istruzioni e UPDATE il databaseSELECT, è possibile scrivere ADO.NET codice nella classe code-behind della pagina o, in alternativa, usare un approccio dichiarativo con SqlDataSource. Idealmente l'applicazione contiene un'architettura a livelli, che è possibile richiamare a livello di codice dalla classe code-behind della pagina o dichiarativamente tramite il controllo ObjectDataSource.

Poiché questa serie di esercitazioni è incentrata sull'autenticazione dei moduli, l'autorizzazione, gli account utente e i ruoli, non sarà presente una discussione approfondita su queste diverse opzioni di accesso ai dati o sul motivo per cui un'architettura a livelli è preferibile per l'esecuzione di istruzioni SQL direttamente dalla pagina ASP.NET. Verrà illustrato l'uso di un oggetto DetailsView e SqlDataSource, l'opzione più rapida e più semplice, ma i concetti illustrati possono essere certamente applicati ai controlli Web alternativi e alla logica di accesso ai dati. Per altre informazioni sull'uso dei dati in ASP.NET, vedere Uso dei dati nella serie di esercitazioni di ASP.NET 2.0 .

Aprire la AdditionalUserInfo.aspx pagina nella Membership cartella e aggiungere un controllo DetailsView alla pagina, impostandone ID la proprietà su UserProfile e cancellandone Width le proprietà e Height . Espandere lo Smart Tag di DetailsView e scegliere di associarlo a un nuovo controllo origine dati. Verrà avviata la Configurazione guidata origine dati (vedere la figura 7). Il primo passaggio chiede di specificare il tipo di origine dati. Poiché ci si connette direttamente al SecurityTutorials database, scegliere l'icona Database, specificando come IDUserProfileDataSource.

Aggiungere un nuovo controllo SqlDataSource denominato UserProfileDataSource

Figura 7: Aggiungere un nuovo controllo SqlDataSource denominato UserProfileDataSource (fare clic per visualizzare l'immagine full-size)

La schermata successiva richiede l'uso del database. Per il SecurityTutorials database è già stata definita una stringa Web.config di connessione. Questo nome della stringa di connessione: SecurityTutorialsConnectionString deve trovarsi nell'elenco a discesa. Selezionare questa opzione e fare clic su Avanti.

Scegliere SecurityTutorialsConnectionString dall'elenco di Drop-Down

Figura 8: Scegliere SecurityTutorialsConnectionString dall'elenco Drop-Down (fare clic per visualizzare l'immagine a dimensioni complete)

La schermata successiva chiede di specificare la tabella e le colonne da eseguire per la query. Scegliere la UserProfiles tabella dall'elenco a discesa e controllare tutte le colonne.

Ripristinare tutte le colonne dalla tabella UserProfiles

Figura 9: Ripristinare tutte le colonne dalla UserProfiles tabella (fare clic per visualizzare l'immagine full-size)

La query corrente nella figura 9 restituisce tutti i record in UserProfiles, ma siamo interessati solo al record dell'utente attualmente connesso. Per aggiungere una WHERE clausola, fare clic sul pulsante per visualizzare la WHERE finestra di dialogo Aggiungi WHERE clausola (vedere Figura 10). Qui è possibile selezionare la colonna da filtrare, l'operatore e l'origine del parametro di filtro. Selezionare UserId come colonna e "=" come Operatore.

Purtroppo non esiste un'origine dei parametri predefinita per restituire il valore dell'utente UserId attualmente connesso. Sarà necessario afferrare questo valore a livello di codice. Impostare quindi l'elenco a discesa Origine su "Nessuno", fare clic sul pulsante Aggiungi per aggiungere il parametro e quindi fare clic su OK.

Aggiungere un parametro di filtro nella colonna UserId

Figura 10: Aggiungere un parametro di filtro nella colonna (fare clic per visualizzare l'immagineUserId a dimensioni complete)

Dopo aver fatto clic su OK, verrà restituito alla schermata visualizzata nella figura 9. Questa volta, tuttavia, la query SQL nella parte inferiore della schermata deve includere una WHERE clausola. Fare clic su Avanti per passare alla schermata "Query di test". Qui è possibile eseguire la query e visualizzare i risultati. Fare clic su Fine per completare la procedura guidata.

Al termine della configurazione guidata DataSource, Visual Studio crea il controllo SqlDataSource in base alle impostazioni specificate nella procedura guidata. Inoltre, aggiunge manualmente BoundFields a DetailsView per ogni colonna restituita dall'oggetto SqlDataSource.SelectCommand Non è necessario visualizzare il campo in DetailsView, poiché l'utente UserId non deve conoscere questo valore. È possibile rimuovere questo campo direttamente dal markup dichiarativo del controllo DetailsView oppure facendo clic sul collegamento "Modifica campi" dal relativo Smart Tag.

A questo punto il markup dichiarativo della pagina dovrebbe essere simile al seguente:

<asp:DetailsView ID="UserProfile" runat="server"
     AutoGenerateRows="False" DataKeyNames="UserId"
     DataSourceID="UserProfileDataSource">
     <Fields>
          <asp:BoundField DataField="HomeTown" HeaderText="HomeTown"
               SortExpression="HomeTown" />
          <asp:BoundField DataField="HomepageUrl" HeaderText="HomepageUrl"
               SortExpression="HomepageUrl" />
          <asp:BoundField DataField="Signature" HeaderText="Signature"
               SortExpression="Signature" />
     </Fields>
</asp:DetailsView>
<asp:SqlDataSource ID="UserProfileDataSource" runat="server"
          ConnectionString="<%$ ConnectionStrings:SecurityTutorialsConnectionString %>"
          SelectCommand="SELECT [UserId], [HomeTown], [HomepageUrl], [Signature] FROM
          [UserProfiles] WHERE ([UserId] = @UserId)">
     <SelectParameters>
          <asp:Parameter Name="UserId" Type="Object" />
     </SelectParameters>
</asp:SqlDataSource>

È necessario impostare a livello di codice il parametro del UserId controllo SqlDataSource sul parametro dell'utente UserId attualmente connesso prima dell'selezione dei dati. Questa operazione può essere eseguita creando un gestore eventi per l'evento Selecting sqlDataSource e aggiungendo il codice seguente:

protected void UserProfileDataSource_Selecting(object sender, 
          SqlDataSourceSelectingEventArgs e)
{
     // Get a reference to the currently logged on user
     MembershipUser currentUser = Membership.GetUser();
 
     // Determine the currently logged on user's UserId value
     Guid currentUserId = (Guid)currentUser.ProviderUserKey;
 
     // Assign the currently logged on user's UserId to the @UserId parameter
     e.Command.Parameters["@UserId"].Value = currentUserId;
}

Il codice precedente inizia ottenendo un riferimento all'utente attualmente connesso chiamando il Membership metodo della GetUser classe. Restituisce un MembershipUser oggetto, la cui ProviderUserKey proprietà contiene .UserId Il UserId valore viene quindi assegnato al parametro sqlDataSource @UserId .

Nota

Il Membership.GetUser() metodo restituisce informazioni sull'utente attualmente connesso. Se un utente anonimo sta visitando la pagina, restituirà un valore di null. In questo caso, questo comporta un NullReferenceException oggetto nella riga di codice seguente quando si tenta di leggere la ProviderUserKey proprietà. Naturalmente, non è necessario preoccuparsi di Membership.GetUser() restituire un null valore nella AdditionalUserInfo.aspx pagina perché è stata configurata l'autorizzazione url in un'esercitazione precedente in modo che solo gli utenti autenticati possano accedere alle risorse ASP.NET in questa cartella. Se è necessario accedere alle informazioni sull'utente attualmente connesso in una pagina in cui è consentito l'accesso anonimo, assicurarsi di verificare che un oggetto nonnull MembershipUser venga restituito dal GetUser() metodo prima di fare riferimento alle relative proprietà.

Se si visita la AdditionalUserInfo.aspx pagina tramite un browser, verrà visualizzata una pagina vuota perché è ancora necessario aggiungere qualsiasi riga alla UserProfiles tabella. Nel passaggio 6 verrà illustrato come personalizzare il controllo CreateUserWizard per aggiungere automaticamente una nuova riga alla UserProfiles tabella quando viene creato un nuovo account utente. Per il momento, tuttavia, sarà necessario creare manualmente un record nella tabella.

Passare a Esplora database in Visual Studio e espandere la cartella Tabelle. Fare clic con il pulsante destro del mouse sulla aspnet_Users tabella e scegliere "Mostra dati tabella" per visualizzare i record nella tabella. Eseguire la stessa operazione per la UserProfiles tabella. La figura 11 mostra questi risultati quando viene riquadri verticalmente. Nel database sono attualmente aspnet_Users presenti record per Bruce, Fred e Tito, ma non sono presenti record nella UserProfiles tabella.

Vengono visualizzati i contenuti delle tabelle aspnet_Users e UserProfiles

Figura 11: il contenuto delle aspnet_Users tabelle e UserProfiles viene visualizzato (fare clic per visualizzare l'immagine a dimensioni complete)

Aggiungere un nuovo record alla UserProfiles tabella digitando manualmente i valori per i HomeTowncampi , HomepageUrle Signature . Il modo più semplice per ottenere un valore valido nel nuovo UserProfiles record consiste nel selezionare il UserId campo da un determinato account utente nella aspnet_Users tabella e copiarlo e incollarlo nel UserId campo in UserProfiles.UserId La figura 12 mostra la tabella dopo l'aggiunta UserProfiles di un nuovo record per Bruce.

Un record è stato aggiunto a UserProfiles per Bruce

Figura 12: Un record è stato aggiunto a UserProfiles Bruce (fare clic per visualizzare l'immagine a dimensioni complete)

Tornare alla AdditionalUserInfo.aspx pagina, connesso come Bruce. Come illustrato nella figura 13, vengono visualizzate le impostazioni di Bruce.

L'utente attualmente in visita mostra le sue impostazioni

Figura 13: l'utente attualmente in visita mostra le impostazioni (fare clic per visualizzare l'immagine a dimensioni complete)

Nota

Andare avanti e aggiungere manualmente record nella UserProfiles tabella per ogni utente di appartenenza. Nel passaggio 6 verrà illustrato come personalizzare il controllo CreateUserWizard per aggiungere automaticamente una nuova riga alla UserProfiles tabella quando viene creato un nuovo account utente.

Passaggio 3: Consentire all'utente di modificare la propria città di casa, la home page e la firma

A questo punto l'utente attualmente connesso può visualizzare la propria città, la home page e l'impostazione di firma, ma non possono ancora modificarle. Aggiornare il controllo DetailsView in modo che i dati possano essere modificati.

La prima cosa da eseguire consiste nell'aggiungere un oggetto UpdateCommand per SqlDataSource, specificando l'istruzione UPDATE da eseguire e i relativi parametri corrispondenti. Selezionare SqlDataSource e, nel Finestra Proprietà, fare clic sui puntini di sospensione accanto alla proprietà UpdateQuery per visualizzare la finestra di dialogo Editor comandi e parametri. Immettere l'istruzione seguente UPDATE nella casella di testo:

UPDATE UserProfiles SET
     HomeTown = @HomeTown,
     HomepageUrl = @HomepageUrl,
     Signature = @Signature
WHERE UserId = @UserId

Fare quindi clic sul pulsante "Aggiorna parametri", che creerà un parametro nell'insieme del UpdateParameters controllo SqlDataSource per ognuno dei parametri nell'istruzione UPDATE . Lasciare l'origine per tutti i parametri impostati su Nessuno e fare clic sul pulsante OK per completare la finestra di dialogo.

Specificare updateCommand e UpdateParameter di SqlDataSource

Figura 14: Specificare sqlDataSource e UpdateParameters (fare clic per visualizzare l'immagineUpdateCommand a dimensioni complete)

A causa delle aggiunte apportate al controllo SqlDataSource, il controllo DetailsView può ora supportare la modifica. Nella casella di controllo "Abilita modifica" di DetailsView selezionare la casella di controllo "Abilita modifica". In questo modo viene aggiunto un CommandField all'insieme del Fields controllo con la relativa ShowEditButton proprietà impostata su True. In questo modo viene eseguito il rendering di un pulsante Modifica quando detailsView viene visualizzato in modalità di sola lettura e i pulsanti Aggiorna e Annulla quando vengono visualizzati in modalità di modifica. Anziché richiedere all'utente di fare clic su Modifica, è possibile avere il rendering DetailsView in uno stato "sempre modificabile" impostando la proprietà del DefaultMode controllo DetailsView su Edit.

Con queste modifiche, il markup dichiarativo del controllo DetailsView dovrebbe essere simile al seguente:

<asp:DetailsView ID="UserProfile" runat="server"
          AutoGenerateRows="False" DataKeyNames="UserId"
          DataSourceID="UserProfileDataSource" DefaultMode="Edit">
     <Fields>
          <asp:BoundField DataField="HomeTown" HeaderText="HomeTown"
               SortExpression="HomeTown" />
          <asp:BoundField DataField="HomepageUrl" HeaderText="HomepageUrl"
               SortExpression="HomepageUrl" />
          <asp:BoundField DataField="Signature" HeaderText="Signature"
               SortExpression="Signature" />
          <asp:CommandField ShowEditButton="True" />
     </Fields>
</asp:DetailsView>

Si noti l'aggiunta dell'oggetto CommandField e della DefaultMode proprietà .

Andare avanti e testare questa pagina tramite un browser. Quando si visita con un utente con un record corrispondente in UserProfiles, le impostazioni dell'utente vengono visualizzate in un'interfaccia modificabile.

DetailsView esegue il rendering di un'interfaccia modificabile

Figura 15: DetailsView esegue il rendering di un'interfaccia modificabile (fare clic per visualizzare un'immagine full-size)

Provare a modificare i valori e fare clic sul pulsante Aggiorna. Sembra come se non accadesse nulla. È presente un postback e i valori vengono salvati nel database, ma non è presente alcun feedback visivo che si è verificato il salvataggio.

Per risolvere questo problema, tornare a Visual Studio e aggiungere un controllo Label sopra DetailsView. IDSettingsUpdatedMessageImpostare su , la relativa Text proprietà su "Le impostazioni sono state aggiornate" e le relative Visible proprietà e EnableViewState su false.

<asp:Label ID="SettingsUpdatedMessage" runat="server"
     Text="Your settings have been updated."
     EnableViewState="false"
     Visible="false"></asp:Label>

È necessario visualizzare l'etichetta SettingsUpdatedMessage ogni volta che detailsView viene aggiornato. A questo scopo, creare un gestore eventi per l'evento ItemUpdated DetailsView e aggiungere il codice seguente:

protected void UserProfile_ItemUpdated(object sender, DetailsViewUpdatedEventArgs e)
{
     SettingsUpdatedMessage.Visible = true;
}

Tornare alla AdditionalUserInfo.aspx pagina tramite un browser e aggiornare i dati. Questa volta viene visualizzato un messaggio di stato utile.

Viene visualizzato un breve messaggio quando vengono aggiornate le impostazioni

Figura 16: Viene visualizzato un breve messaggio quando vengono aggiornate le impostazioni (fare clic per visualizzare l'immagine a dimensioni complete)

Nota

L'interfaccia di modifica del controllo DetailsView lascia molto da desiderare. Usa caselle di testo di dimensioni standard, ma il campo Firma dovrebbe probabilmente essere una casella di testo a più righe. È consigliabile usare Un regularExpressionValidator per assicurarsi che l'URL della home page, se immesso, inizi con "http://" o "https://". Inoltre, poiché il controllo DetailsView ha la proprietà DefaultMode impostata su Edit, il pulsante Annulla non esegue alcuna operazione. Deve essere rimosso o, quando si fa clic, reindirizzare l'utente ad altre pagine (ad esempio ~/Default.aspx). Lascio questi miglioramenti come esercizio per il lettore.

Attualmente, il sito Web non fornisce collegamenti alla AdditionalUserInfo.aspx pagina. L'unico modo per raggiungere è immettere l'URL della pagina direttamente nella barra degli indirizzi del browser. Aggiungiamo un collegamento a questa pagina nella Site.master pagina master.

Tenere presente che la pagina master contiene un controllo Web LoginView nel relativo LoginContent ContentPlaceHolder che visualizza markup diverso per i visitatori autenticati e anonimi. Aggiornare il controllo LoggedInTemplate LoginView per includere un collegamento alla AdditionalUserInfo.aspx pagina. Dopo aver apportato queste modifiche, il markup dichiarativo del controllo LoginView dovrebbe essere simile al seguente:

<asp:LoginView ID="LoginView1" runat="server">
     <LoggedInTemplate>
          Welcome back,
          <asp:LoginName ID="LoginName1" runat="server" />.
          <br />
          <asp:HyperLink ID="lnkUpdateSettings" runat="server" 
               NavigateUrl="~/Membership/AdditionalUserInfo.aspx">
               Update Your Settings</asp:HyperLink>
     </LoggedInTemplate>
     <AnonymousTemplate>
          Hello, stranger.
     </AnonymousTemplate>
</asp:LoginView>

Si noti l'aggiunta del controllo HyperLink all'oggetto lnkUpdateSettingsLoggedInTemplate. Con questo collegamento, gli utenti autenticati possono passare rapidamente alla pagina per visualizzare e modificare le impostazioni di home town, homepage e firma.

Passaggio 4: Aggiunta di nuovi commenti guestbook

La Guestbook.aspx pagina è in cui gli utenti autenticati possono visualizzare il guestbook e lasciare un commento. Iniziamo con la creazione dell'interfaccia per aggiungere nuovi commenti del guestbook.

Aprire la Guestbook.aspx pagina in Visual Studio e costruire un'interfaccia utente costituita da due controlli TextBox, uno per l'oggetto del nuovo commento e uno per il relativo corpo. Impostare la prima proprietà del ID controllo TextBox su e sulla relativa Columns proprietà Subject su 40; impostare BodyID rispettivamente su , WidthTextModeMultiLineRows su e le relative proprietà e su "95%" e su 8. Per completare l'interfaccia utente, aggiungere un controllo Web Button denominato PostCommentButton e impostarne la Text proprietà su "Post Your Comment".

Poiché ogni commento del guestbook richiede un oggetto e un corpo, aggiungere un oggetto RequiredFieldValidator per ognuna delle Caselle di testo. Impostare la proprietà di questi controlli su "EnterComment"; analogamente, impostare la ValidationGroupPostCommentButton proprietà del ValidationGroup controllo su "EnterComment". Per altre informazioni su ASP. Controlli di convalida di NET, vedere Convalida modulo in ASP.NET.

Dopo aver creato l'interfaccia utente del markup dichiarativo della pagina, dovrebbe essere simile al seguente:

<h3>Leave a Comment</h3>
<p>
     <b>Subject:</b>
     <asp:RequiredFieldValidator ID="SubjectReqValidator" runat="server"
          ErrorMessage="You must provide a value for Subject"
          ControlToValidate="Subject" ValidationGroup="EnterComment">
     </asp:RequiredFieldValidator><br/>
     <asp:TextBox ID="Subject" Columns="40" runat="server"></asp:TextBox>
</p>
<p>
     <b>Body:</b>
     <asp:RequiredFieldValidator ID="BodyReqValidator" runat="server"
          ControlToValidate="Body"
          ErrorMessage="You must provide a value for Body" ValidationGroup="EnterComment">
     </asp:RequiredFieldValidator><br/>
     <asp:TextBox ID="Body" TextMode="MultiLine" Width="95%"
          Rows="8" runat="server"></asp:TextBox>
</p>
<p>
     <asp:Button ID="PostCommentButton" runat="server" 
          Text="Post Your Comment"
          ValidationGroup="EnterComment" />
</p>

Con il completamento dell'interfaccia utente, l'attività successiva consiste nell'inserire un nuovo record nella GuestbookComments tabella quando viene PostCommentButton fatto clic su . Questa operazione può essere eseguita in diversi modi: è possibile scrivere ADO.NET codice nel gestore eventi del pulsante. È possibile aggiungere un controllo SqlDataSource alla pagina, configurarne InsertCommande quindi chiamare Insert il relativo metodo dal Click gestore eventi; oppure è possibile creare un livello intermedio responsabile dell'inserimento Click di nuovi commenti del guestbook e richiamare questa funzionalità dal Click gestore eventi. Poiché è stato esaminato l'uso di sqlDataSource nel passaggio 3, è possibile usare ADO.NET codice qui.

Nota

Le classi ADO.NET usate per accedere a livello di codice ai dati da un database di SQL Server Microsoft si trovano nello System.Data.SqlClient spazio dei nomi. Potrebbe essere necessario importare questo spazio dei nomi nella classe code-behind della pagina , ad esempio using System.Data.SqlClient;.

Creare un gestore eventi per l'evento PostCommentButtone Click aggiungere il codice seguente:

protected void PostCommentButton_Click(object sender, EventArgs e)
{
     if (!Page.IsValid)
          return;
 
     // Determine the currently logged on user's UserId
     MembershipUser currentUser = Membership.GetUser();
     Guid currentUserId = (Guid)currentUser.ProviderUserKey;
 
     // Insert a new record into GuestbookComments
     string connectionString = 
          ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
     string insertSql = "INSERT INTO GuestbookComments(Subject, Body, UserId) VALUES(@Subject,
               @Body, @UserId)";
 
     using (SqlConnection myConnection = new SqlConnection(connectionString))
     {
          myConnection.Open();
          SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
          myCommand.Parameters.AddWithValue("@Subject", Subject.Text.Trim());
          myCommand.Parameters.AddWithValue("@Body", Body.Text.Trim());
          myCommand.Parameters.AddWithValue("@UserId", currentUserId);
          myCommand.ExecuteNonQuery();
          myConnection.Close();
     }
 
     // "Reset" the Subject and Body TextBoxes
     Subject.Text = string.Empty;
     Body.Text = string.Empty;
}

Il Click gestore eventi inizia controllando che i dati forniti dall'utente siano validi. In caso contrario, il gestore eventi viene chiuso prima di inserire un record. Supponendo che i dati forniti siano validi, il valore dell'utente UserId attualmente connesso viene recuperato e archiviato nella currentUserId variabile locale. Questo valore è necessario perché è necessario specificare un valore quando si inserisce un UserId record in GuestbookComments.

In seguito, viene recuperata Web.config la stringa di connessione per il SecurityTutorials database e viene specificata l'istruzione INSERT SQL. Viene quindi creato e aperto un SqlConnection oggetto. Successivamente, viene costruito un SqlCommand oggetto e i valori per i parametri usati nella INSERT query vengono assegnati. L'istruzione INSERT viene quindi eseguita e la connessione chiusa. Alla fine del gestore eventi, le Subject proprietà e Body TextBoxes vengono cancellate in modo che i valori dell'utente non vengano mantenuti Text nel postback.

Andare avanti e testare questa pagina in un browser. Poiché questa pagina si trova nella Membership cartella non è accessibile ai visitatori anonimi. Pertanto, sarà necessario eseguire prima l'accesso (se non è già presente). Immettere un valore nelle Subject caselle di testo e Body fare clic sul PostCommentButton pulsante . In questo modo verrà aggiunto un nuovo record a GuestbookComments. Dopo il postback, il soggetto e il corpo forniti vengono cancellati da TextBoxes.

Dopo aver fatto clic sul PostCommentButton pulsante non sono presenti commenti visivi che il commento è stato aggiunto al guestbook. È comunque necessario aggiornare questa pagina per visualizzare i commenti del guestbook esistenti, che verranno impostati nel passaggio 5. Al termine, il commento appena aggiunto verrà visualizzato nell'elenco dei commenti, fornendo commenti visivi adeguati. Per ora, verificare che il commento del GuestbookComments guestbook sia stato salvato esaminando il contenuto della tabella.

La figura 17 mostra il contenuto della GuestbookComments tabella dopo che sono stati lasciati due commenti.

È possibile visualizzare i commenti del guestbook nella tabella GuestbookComments

Figura 17: È possibile visualizzare i commenti del guestbook nella GuestbookComments tabella (fare clic per visualizzare l'immagine a dimensioni complete)

Nota

Se un utente tenta di inserire un commento guestbook contenente markup potenzialmente pericoloso, ad esempio HTML, ASP.NET genererà un'eccezione HttpRequestValidationException. Per altre informazioni su questa eccezione, sui motivi per cui viene generata e su come consentire agli utenti di inviare valori potenzialmente pericolosi, vedere il white paper sulla convalida delle richieste.

Passaggio 5: Presentazione dei commenti del guestbook esistente

Oltre a lasciare i commenti, un utente che visita la Guestbook.aspx pagina deve anche essere in grado di visualizzare i commenti esistenti del guestbook. A tale scopo, aggiungere un controllo ListView denominato CommentList alla fine della pagina.

Nota

Il controllo ListView è una novità di ASP.NET versione 3.5. È progettato per visualizzare un elenco di elementi in un layout molto personalizzabile e flessibile, ma offre ancora funzionalità di modifica predefinite, inserimento, eliminazione, paging e ordinamento come GridView. Se si usa ASP.NET 2.0, sarà invece necessario usare il controllo DataList o Repeater. Per altre informazioni sull'uso di ListView, vedere l'articolo del blog di Scott Guthrie, The asp:ListView Control e my article, Displaying Data with the ListView Control.For more information on using the ListView, see Scott Guthrie's blog entry, The asp:ListView Control, and my article, Displaying Data with the ListView Control.

Aprire lo smart tag di ListView e, nell'elenco a discesa Scegli origine dati, associare il controllo a una nuova origine dati. Come illustrato nel passaggio 2, verrà avviata la Configurazione guidata origine dati. Selezionare l'icona Database, assegnare un nome a SqlDataSource CommentsDataSourcerisultante e fare clic su OK. Selezionare quindi la SecurityTutorialsConnectionString stringa di connessione dall'elenco a discesa e fare clic su Avanti.

A questo punto nel passaggio 2 sono stati specificati i dati per la query selezionando la UserProfiles tabella dall'elenco a discesa e selezionando le colonne da restituire (fare riferimento alla figura 9). Questa volta, tuttavia, si vuole creare un'istruzione SQL che estrae non solo i record da GuestbookComments, ma anche la città principale del commento, la home page, la firma e il nome utente del commento. Selezionare quindi il pulsante di opzione "Specificare un'istruzione SQL personalizzata o una stored procedure" e fare clic su Avanti.

Verrà visualizzata la schermata "Definisci istruzioni personalizzate o stored procedure". Fare clic sul pulsante Generatore query per compilare graficamente la query. Il generatore di query inizia richiedendo di specificare le tabelle da cui eseguire la query. Selezionare le GuestbookCommentstabelle , UserProfilese aspnet_Users e fare clic su OK. Verranno aggiunte tutte e tre le tabelle all'area di progettazione. Poiché sono presenti vincoli di chiave esterna tra le GuestbookCommentstabelle , UserProfilese aspnet_Users , Il generatore di query esegue automaticamente JOIN queste tabelle.

Tutto ciò che rimane consiste nel specificare le colonne da restituire. GuestbookComments Nella tabella selezionare le Subjectcolonne , Bodye CommentDate , restituire le HomeTowncolonne , HomepageUrle Signature dalla UserProfiles tabella e restituire UserName da aspnet_Users. Aggiungere anche "ORDER BY CommentDate DESC" alla fine della SELECT query in modo che i post più recenti vengano restituiti per primi. Dopo aver eseguito queste selezioni, l'interfaccia di Generatore query dovrebbe essere simile alla schermata nella figura 18.

La query costruita joINs le tabelle GuestbookComments, UserProfiles e aspnet_Users

Figura 18: Query costruita JOIN nelle GuestbookCommentstabelle , UserProfilese aspnet_Users (fare clic per visualizzare l'immagine a dimensioni intere)

Fare clic su OK per chiudere la finestra Generatore query e tornare alla schermata "Definisci istruzioni personalizzate o stored procedure". Fare clic su Avanti per passare alla schermata "Test query", in cui è possibile visualizzare i risultati della query facendo clic sul pulsante Query di test. Quando si è pronti, fare clic su Fine per completare la procedura guidata Configura origine dati.

Al termine della procedura guidata Configura origine dati nel passaggio 2, la raccolta del Fields controllo DetailsView associata è stata aggiornata per includere un BoundField per ogni colonna restituita da SelectCommand. Il controllo ListView, tuttavia, rimane invariato; dobbiamo ancora definirne il layout. Il layout di ListView può essere costruito manualmente tramite il markup dichiarativo o dall'opzione "Configura ListView" nel relativo Smart Tag. In genere preferisco definire il markup manualmente, ma usare qualsiasi metodo sia più naturale per te.

Ho finito di usare il seguente LayoutTemplate, ItemTemplatee ItemSeparatorTemplate per il controllo ListView:

<asp:ListView ID="CommentList" runat="server" DataSourceID="CommentsDataSource">
     <LayoutTemplate>
          <span ID="itemPlaceholder" runat="server" />
          <p>
               <asp:DataPager ID="DataPager1" runat="server">
                    <Fields>
                         <asp:NextPreviousPagerField ButtonType="Button" 
                              ShowFirstPageButton="True"
                              ShowLastPageButton="True" />
                    </Fields>
               </asp:DataPager>
          </p>
     </LayoutTemplate>
     <ItemTemplate>
          <h4><asp:Label ID="SubjectLabel" runat="server" 
               Text='<%# Eval("Subject") %>' /></h4>
          <asp:Label ID="BodyLabel" runat="server" 
               Text='<%# Eval("Body").ToString().Replace(Environment.NewLine, "<br />") %>' />
          <p>
               ---<br />
               <asp:Label ID="SignatureLabel" Font-Italic="true" runat="server"
                    Text='<%# Eval("Signature") %>' />
               <br />
               <br />
               My Home Town:
               <asp:Label ID="HomeTownLabel" runat="server" 
                    Text='<%# Eval("HomeTown") %>' />
               <br />
               My Homepage:
               <asp:HyperLink ID="HomepageUrlLink" runat="server" 
                    NavigateUrl='<%# Eval("HomepageUrl") %>' 
                    Text='<%# Eval("HomepageUrl") %>' />
          </p>
          <p align="center">
               Posted by
               <asp:Label ID="UserNameLabel" runat="server" 
                    Text='<%# Eval("UserName") %>' /> on
               <asp:Label ID="CommentDateLabel" runat="server" 
                    Text='<%# Eval("CommentDate") %>' />
          </p>
     </ItemTemplate>
     <ItemSeparatorTemplate>
          <hr />
     </ItemSeparatorTemplate>
</asp:ListView>

Definisce LayoutTemplate il markup generato dal controllo , mentre esegue il ItemTemplate rendering di ogni elemento restituito da SqlDataSource. Il ItemTemplatemarkup risultante viene inserito nel LayoutTemplatecontrollo del .itemPlaceholder Oltre a itemPlaceholder, include LayoutTemplate un controllo DataPager, che limita listView a visualizzare solo 10 commenti del guestbook per pagina (impostazione predefinita) ed esegue il rendering di un'interfaccia di paging.

Il mio ItemTemplate visualizza l'oggetto di ogni commento del guestbook in un <h4> elemento con il corpo situato sotto l'oggetto. Si noti che la sintassi usata per visualizzare il corpo accetta i dati restituiti dall'istruzione Eval("Body") databinding, li converte in una stringa e sostituisce le interruzioni di riga con l'elemento <br /> . Questa conversione è necessaria per visualizzare le interruzioni di riga immesse durante l'invio del commento poiché lo spazio vuoto viene ignorato da HTML. La firma dell'utente viene visualizzata sotto il corpo in corsivo, seguita dalla città principale dell'utente, da un collegamento alla home page, dalla data e dall'ora in cui è stato effettuato il commento e dal nome utente della persona che ha lasciato il commento.

Dedicare qualche minuto alla visualizzazione della pagina tramite un browser. Verranno visualizzati i commenti aggiunti al guestbook nel passaggio 5 visualizzato qui.

Guestbook.aspx Visualizza ora i commenti del guestbook

Figura 19: Guestbook.aspx Visualizza ora i commenti del guestbook (fare clic per visualizzare l'immagine a dimensione intera)

Provare ad aggiungere un nuovo commento al guestbook. Quando si fa clic sul pulsante viene eseguito il PostCommentButton postback della pagina e il commento viene aggiunto al database, ma il controllo ListView non viene aggiornato per visualizzare il nuovo commento. Questo problema può essere risolto in uno dei due casi seguenti:

  • Aggiornamento del PostCommentButton gestore eventi del Click pulsante in modo che richiami il metodo del DataBind() controllo ListView dopo aver inserito il nuovo commento nel database o
  • Impostazione della proprietà del EnableViewState controllo ListView su false. Questo approccio funziona perché disabilitando lo stato di visualizzazione del controllo, deve essere riassociato ai dati sottostanti in ogni postback.

Il sito Web dell'esercitazione scaricabile da questa esercitazione illustra entrambe le tecniche. La proprietà del EnableViewState controllo ListView su false e il codice necessario per riassociare i dati a livello di codice a ListView sono presenti nel Click gestore eventi, ma viene impostato come commento.

Nota

Attualmente la AdditionalUserInfo.aspx pagina consente all'utente di visualizzare e modificare le impostazioni di home page, home page e firma. Potrebbe essere utile aggiornare per visualizzare AdditionalUserInfo.aspx i commenti del guestbook dell'utente connesso. Ovvero, oltre a esaminare e modificare le informazioni, un utente può visitare la AdditionalUserInfo.aspx pagina per vedere quali commenti del libro guest ha fatto in passato. Lascio questo come esercizio per il lettore interessato.

Passaggio 6: Personalizzazione del controllo CreateUserWizard per includere un'interfaccia per la home town, la home page e la firma

La SELECT query utilizzata dalla Guestbook.aspx pagina usa un oggetto INNER JOIN per combinare i record correlati tra le GuestbookCommentstabelle , UserProfilese aspnet_Users . Se un utente che non dispone di record in UserProfiles effettua un commento al guestbook, il commento non verrà visualizzato in ListView perché restituisce GuestbookCommentsINNER JOIN solo i record quando sono presenti record corrispondenti in UserProfiles e aspnet_Users. E come abbiamo visto nel passaggio 3, se un utente non dispone di un record in UserProfiles non può visualizzare o modificare le impostazioni nella AdditionalUserInfo.aspx pagina.

Inutile dire, a causa delle nostre decisioni di progettazione è importante che ogni account utente nel sistema di appartenenza disponga di un record corrispondente nella UserProfiles tabella. Ciò a cui si vuole aggiungere UserProfiles un record corrispondente ogni volta che viene creato un nuovo account utente di appartenenza tramite CreateUserWizard.

Come illustrato nell'esercitazione Creazione di account utente, dopo la creazione del nuovo account utente di appartenenza, il controllo CreateUserWizard genera l'eventoCreatedUser. È possibile creare un gestore eventi per questo evento, ottenere l'UserId per l'utente appena creato e quindi inserire un record nella UserProfiles tabella con i valori predefiniti per le HomeTowncolonne , HomepageUrle Signature . Per altre informazioni, è possibile richiedere all'utente questi valori personalizzando l'interfaccia del controllo CreateUserWizard per includere caselle di testo aggiuntive.

Si esamini prima di tutto come aggiungere una nuova riga alla UserProfiles tabella nel CreatedUser gestore eventi con valori predefiniti. In seguito verrà illustrato come personalizzare l'interfaccia utente del controllo CreateUserWizard per includere campi modulo aggiuntivi per raccogliere la città principale, la home page e la firma del nuovo utente.

Aggiunta di una riga predefinita aUserProfiles

Nell'esercitazione Creazione di account utente è stato aggiunto un controllo CreateUserWizard alla CreatingUserAccounts.aspx pagina nella Membership cartella . Per fare in modo che il controllo CreateUserWizard aggiunga un record alla UserProfiles tabella al momento della creazione dell'account utente, è necessario aggiornare la funzionalità del controllo CreateUserWizard. Anziché apportare queste modifiche alla CreatingUserAccounts.aspx pagina, aggiungere invece un nuovo controllo CreateUserWizard alla EnhancedCreateUserWizard.aspx pagina e apportare le modifiche per questa esercitazione.

Aprire la EnhancedCreateUserWizard.aspx pagina in Visual Studio e trascinare un controllo CreateUserWizard dalla casella degli strumenti nella pagina. Impostare la proprietà del ID controllo CreateUserWizard su NewUserWizard. Come illustrato nell'esercitazione Creazione di account utente , l'interfaccia utente predefinita di CreateUserWizard richiede al visitatore le informazioni necessarie. Dopo aver fornito queste informazioni, il controllo crea internamente un nuovo account utente nel framework di appartenenza, senza che sia necessario scrivere una singola riga di codice.

Il controllo CreateUserWizard genera un numero di eventi durante il flusso di lavoro. Dopo che un visitatore ha fornito le informazioni sulla richiesta e ha inviato il modulo, il controllo CreateUserWizard ne genera CreatingUser inizialmente l'evento. Se si verifica un problema durante il processo di creazione, l'eventoCreateUserError viene generato, ma se l'utente viene creato correttamente, viene generato l'eventoCreatedUser. Nell'esercitazione Creazione di account utente è stato creato un gestore eventi per l'evento CreatingUser per assicurarsi che il nome utente specificato non contenga spazi iniziali o finali e che il nome utente non sia stato visualizzato in nessun punto della password.

Per aggiungere una riga nella UserProfiles tabella per l'utente appena creato, è necessario creare un gestore eventi per l'evento CreatedUser . Al momento dell'attivazione dell'evento CreatedUser , l'account utente è già stato creato nel framework di appartenenza, consentendoci di recuperare il valore UserId dell'account.

Creare un gestore eventi per l'evento NewUserWizarddi CreatedUser e aggiungere il codice seguente:

protected void NewUserWizard_CreatedUser(object sender, EventArgs e)
{
     // Get the UserId of the just-added user
     MembershipUser newUser = Membership.GetUser(NewUserWizard.UserName);
     Guid newUserId = (Guid)newUser.ProviderUserKey;
 
     // Insert a new record into UserProfiles
     string connectionString = 
          ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
     string insertSql = "INSERT INTO UserProfiles(UserId, HomeTown, HomepageUrl,
          Signature) VALUES(@UserId, @HomeTown, @HomepageUrl, @Signature)";
 
     using (SqlConnection myConnection = new SqlConnection(connectionString))
     {
          myConnection.Open();
          SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
          myCommand.Parameters.AddWithValue("@UserId", newUserId);
          myCommand.Parameters.AddWithValue("@HomeTown", DBNull.Value);
          myCommand.Parameters.AddWithValue("@HomepageUrl", DBNull.Value);
          myCommand.Parameters.AddWithValue("@Signature", DBNull.Value);
          myCommand.ExecuteNonQuery();
          myConnection.Close();
     }
}

Gli esseri di codice precedenti recuperano l'ID utente dell'account utente appena aggiunto. Questa operazione viene eseguita usando il Membership.GetUser(username) metodo per restituire informazioni su un determinato utente e quindi usando la proprietà per recuperare il ProviderUserKey relativo UserId. Il nome utente immesso dall'utente nel controllo CreateUserWizard è disponibile tramite la relativaUserName proprietà.

Successivamente, la stringa di connessione viene recuperata da Web.config e viene specificata l'istruzione INSERT . Vengono create istanze degli oggetti ADO.NET necessari e il comando eseguito. Il codice assegna un'istanza DBNull ai @HomeTownparametri , @HomepageUrle @Signature , che ha l'effetto di inserire valori di database NULL per i HomeTowncampi , HomepageUrle Signature .

Visitare la EnhancedCreateUserWizard.aspx pagina tramite un browser e creare un nuovo account utente. Dopo aver eseguito questa operazione, tornare a Visual Studio ed esaminare il contenuto delle aspnet_Users tabelle e UserProfiles , come illustrato nella figura 12. Verrà visualizzato il nuovo account utente in aspnet_Users e una riga corrispondente UserProfiles (con NULL i valori per HomeTown, HomepageUrle Signature).

Sono stati aggiunti un nuovo account utente e un record UserProfiles

Figura 20: Sono stati aggiunti un nuovo account utente e UserProfiles un nuovo record (fare clic per visualizzare l'immagine a dimensione intera)

Dopo che il visitatore ha fornito le informazioni sul nuovo account e aver fatto clic sul pulsante "Crea utente", viene creato l'account utente e viene aggiunta una riga alla UserProfiles tabella. CreateUserWizard visualizza quindi il relativo CompleteWizardStep, che visualizza un messaggio di operazione riuscita e un pulsante Continua. Facendo clic sul pulsante Continua viene generato un postback, ma non viene eseguita alcuna azione, lasciando l'utente bloccato nella EnhancedCreateUserWizard.aspx pagina.

È possibile specificare un URL a cui inviare l'utente quando si fa clic sul pulsante Continua tramite la proprietà del ContinueDestinationPageUrlcontrollo CreateUserWizard. Impostare la ContinueDestinationPageUrl proprietà su "~/Membership/AdditionalUserInfo.aspx". In questo modo il nuovo utente passa a AdditionalUserInfo.aspx, dove può visualizzare e aggiornare le impostazioni.

Personalizzazione dell'interfaccia di CreateUserWizard per richiedere la home town, la home page e la firma del nuovo utente

L'interfaccia predefinita del controllo CreateUserWizard è sufficiente per scenari di creazione di account semplici in cui devono essere raccolte solo le informazioni di base sull'account utente, ad esempio nome utente, password e posta elettronica. Ma cosa succede se volevamo chiedere al visitatore di entrare nella sua città natale, nella home page e nella firma durante la creazione del suo account? È possibile personalizzare l'interfaccia del controllo CreateUserWizard per raccogliere informazioni aggiuntive all'iscrizione e queste informazioni possono essere usate nel CreatedUser gestore eventi per inserire record aggiuntivi nel database sottostante.

Il controllo CreateUserWizard estende il controllo ASP.NET Procedura guidata, ovvero un controllo che consente a uno sviluppatore di pagine di definire una serie di elementi ordinati WizardSteps. Il controllo Procedura guidata esegue il rendering del passaggio attivo e fornisce un'interfaccia di navigazione che consente al visitatore di spostarsi attraverso questi passaggi. Il controllo Procedura guidata è ideale per suddividere un'attività lunga in diversi passaggi brevi. Per altre informazioni sul controllo Procedura guidata, vedere Creazione di un'interfaccia utente dettagliata con il controllo procedura guidata ASP.NET 2.0.

Il markup predefinito del controllo CreateUserWizard definisce due WizardStepselementi: CreateUserWizardStep e CompleteWizardStep.

<asp:CreateUserWizard ID="NewUserWizard" runat="server"
     ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
     <WizardSteps>
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
          </asp:CreateUserWizardStep>
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
          </asp:CompleteWizardStep>
     </WizardSteps>
</asp:CreateUserWizard>

Il primo WizardStep, CreateUserWizardStepesegue il rendering dell'interfaccia che richiede nome utente, password, posta elettronica e così via. Dopo che il visitatore ha fornito queste informazioni e ha fatto clic su "Crea utente", viene visualizzata la CompleteWizardStep, che mostra il messaggio di operazione riuscita e un pulsante Continua.

Per personalizzare l'interfaccia del controllo CreateUserWizard per includere campi modulo aggiuntivi, è possibile:

  • Creare uno o più nuoviWizardSteps per contenere gli elementi aggiuntivi dell'interfaccia utente. Per aggiungere un nuovo WizardStep oggetto a CreateUserWizard, fare clic sul collegamento "Aggiungi/Rimuovi WizardSteps" dallo smart tag per avviare l'Editor WizardStep raccolta. Da qui è possibile aggiungere, rimuovere o riordinare i passaggi della procedura guidata. Questo è l'approccio che verrà usato per questa esercitazione.

  • Convertire l'oggettoCreateUserWizardStepin un oggetto modificabileWizardStep. In questo modo viene CreateUserWizardStep sostituito con un oggetto equivalente WizardStep il cui markup definisce un'interfaccia utente corrispondente a CreateUserWizardStepquella di . Convertendo in CreateUserWizardStep un WizardStep oggetto è possibile riposizionare i controlli o aggiungere altri elementi dell'interfaccia utente a questo passaggio. Per convertire o CreateUserWizardStepCompleteWizardStep in un oggetto modificabile WizardStep, fare clic sul collegamento "Personalizza crea passaggio utente" o "Personalizza passaggio completo" dallo smart tag del controllo.

  • Usare una combinazione delle due opzioni precedenti.

Un aspetto importante da tenere presente è che il controllo CreateUserWizard esegue il processo di creazione dell'account utente quando si fa clic sul pulsante "Crea utente" dall'interno di CreateUserWizardStep. Non importa se ci sono altri WizardStep dopo o CreateUserWizardStep meno.

Quando si aggiunge un oggetto personalizzato WizardStep al controllo CreateUserWizard per raccogliere input utente aggiuntivo, è possibile posizionare l'oggetto personalizzato WizardStep prima o dopo .CreateUserWizardStep Se viene prima di , CreateUserWizardStep l'input utente aggiuntivo raccolto dall'oggetto personalizzato WizardStep è disponibile per il CreatedUser gestore eventi. Tuttavia, se l'oggetto personalizzato WizardStep viene eseguito dopo CreateUserWizardStep , entro il momento in cui viene visualizzato il WizardStep nuovo account utente è già stato creato e l'evento CreatedUser è già stato generato.

La figura 21 mostra il flusso di lavoro quando l'oggetto aggiunto WizardStep precede .CreateUserWizardStep Poiché le informazioni aggiuntive sull'utente sono state raccolte dal momento in cui viene generato l'evento CreatedUser , è necessario aggiornare il CreatedUser gestore eventi per recuperare questi input e usarli per i INSERT valori dei parametri dell'istruzione (anziché DBNull.Value).

Flusso di lavoro CreateUserWizard quando una procedura guidata aggiuntivaP precede createUserWizardStep

Figura 21: Flusso di lavoro CreateUserWizard quando un'altra WizardStep precede (CreateUserWizardStepfare clic per visualizzare l'immagine a dimensione intera)

Se l'oggetto personalizzato WizardStep viene inserito dopo , CreateUserWizardSteptuttavia, il processo di creazione dell'account utente viene eseguito prima che l'utente abbia avuto la possibilità di immettere la propria città, home page o firma. In tal caso, queste informazioni aggiuntive devono essere inserite nel database dopo la creazione dell'account utente, come illustrato nella figura 22.

Flusso di lavoro CreateUserWizard quando viene eseguita un'aggiunta guidataPassaggio dopo createUserWizardStep

Figura 22: Flusso di lavoro CreateUserWizard quando viene WizardStep aggiunto dopo (CreateUserWizardStepfare clic per visualizzare l'immagine a dimensioni intere)

Il flusso di lavoro illustrato nella figura 22 attende l'inserimento di un record nella UserProfiles tabella fino al completamento del passaggio 2. Se il visitatore chiude il browser dopo il passaggio 1, tuttavia, verrà raggiunto uno stato in cui è stato creato un account utente, ma non è stato aggiunto alcun record a UserProfiles. Una soluzione alternativa consiste nell'inserire un record con NULL o valori UserProfiles predefiniti nel gestore eventi (che viene attivato dopo il passaggio 1) e quindi aggiornare questo record al termine del CreatedUser passaggio 2. In questo modo si garantisce che venga aggiunto un UserProfiles record per l'account utente anche se l'utente interrompe il processo di registrazione a metà strada.

Per questa esercitazione verrà creato un nuovo WizardStep oggetto che si verifica dopo ma CreateUserWizardStep prima di CompleteWizardStep. Si otterrà prima di tutto wizardStep sul posto e quindi si esaminerà il codice.

Dallo smart tag del controllo CreateUserWizard selezionare la finestra di dialogo "Aggiungi/Rimuovi WizardStep " che consente di visualizzare la WizardStep finestra di dialogo Editor raccolta. Aggiungere un nuovo WizardStepoggetto , impostandone ID su UserSettings, su Title "Impostazioni" e su StepTypeStep. Posizionarla in modo che venga eseguita dopo l'operazione CreateUserWizardStep ("Iscrizione per il nuovo account") e prima di CompleteWizardStep ("Completa"), come illustrato nella figura 23.

Aggiungere una nuova procedura guidataPassaggio al controllo CreateUserWizard

Figura 23: Aggiungere un nuovo WizardStep al controllo CreateUserWizard (fare clic per visualizzare l'immagine a dimensione intera)

Fare clic su OK per chiudere la WizardStep finestra di dialogo Editor raccolta. Il nuovo WizardStep è evidenziato dal markup dichiarativo aggiornato del controllo CreateUserWizard:

<asp:CreateUserWizard ID="NewUserWizard" runat="server"
     ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
     <WizardSteps>
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
          </asp:CreateUserWizardStep>
          <asp:WizardStep runat="server" ID="UserSettings" StepType="Step"
               Title="Your Settings">
          </asp:WizardStep>
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
          </asp:CompleteWizardStep>
     </WizardSteps>
</asp:CreateUserWizard>

Prendere nota del nuovo <asp:WizardStep> elemento. È necessario aggiungere l'interfaccia utente per raccogliere qui la città principale, la home page e la firma del nuovo utente. È possibile immettere questo contenuto nella sintassi dichiarativa o tramite il Designer. Per usare il Designer, selezionare il passaggio "Impostazioni" dall'elenco a discesa nello Smart Tag per visualizzare il passaggio nella Designer.

Nota

Se si seleziona un'istruzione nell'elenco a discesa di Smart Tag, viene aggiornata la proprietà del ActiveStepIndexcontrollo CreateUserWizard, che specifica l'indice del passaggio iniziale. Pertanto, se si usa questo elenco a discesa per modificare il passaggio "Impostazioni" nel Designer, assicurarsi di impostarlo di nuovo su "Iscrizione per il nuovo account" in modo che questo passaggio venga visualizzato quando gli utenti visitano per la prima volta la EnhancedCreateUserWizard.aspx pagina.

Creare un'interfaccia utente all'interno del passaggio "Impostazioni" che contiene tre controlli TextBox denominati HomeTown, HomepageUrle Signature. Dopo aver costruito questa interfaccia, il markup dichiarativo di CreateUserWizard dovrebbe essere simile al seguente:

<asp:CreateUserWizard ID="NewUserWizard" runat="server"
     ContinueDestinationPageUrl="~/Membership/AdditionalUserInfo.aspx">
     <WizardSteps>
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
          </asp:CreateUserWizardStep>
          <asp:WizardStep runat="server" ID="UserSettings" StepType="Step"
               Title="Your Settings">
               <p>
                    <b>Home Town:</b><br />
                    <asp:TextBox ID="HomeTown" runat="server"></asp:TextBox>
               </p>
               <p>
                    <b>Homepage URL:</b><br />
                    <asp:TextBox ID="HomepageUrl" Columns="40" runat="server"></asp:TextBox>
               </p>
               <p>
                    <b>Signature:</b><br />
                    <asp:TextBox ID="Signature" TextMode="MultiLine" Width="95%"
                         Rows="5" runat="server"></asp:TextBox>
               </p>
          </asp:WizardStep>
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
          </asp:CompleteWizardStep>
     </WizardSteps>
</asp:CreateUserWizard>

Andare avanti e visitare questa pagina tramite un browser e creare un nuovo account utente, specificando i valori per la città principale, la home page e la firma. Dopo aver completato l'account CreateUserWizardStep utente viene creato nel framework di appartenenza e il CreatedUser gestore eventi viene eseguito, che aggiunge una nuova riga a UserProfiles, ma con un valore di database NULL per HomeTown, HomepageUrle Signature. I valori immessi per la città principale, la home page e la firma non vengono mai utilizzati. Il risultato netto è un nuovo account utente con un UserProfiles record i cui HomeTowncampi , HomepageUrle Signature devono ancora essere specificati.

È necessario eseguire il codice dopo il passaggio "Impostazioni" che porta alla città principale, all'honepage e ai valori della firma immessi dall'utente e aggiorna il record appropriato UserProfiles . Ogni volta che l'utente si sposta tra i passaggi di un controllo Procedura guidata, viene generato l'evento della ActiveStepChanged procedura guidata. È possibile creare un gestore eventi per questo evento e aggiornare la UserProfiles tabella al termine del passaggio "Impostazioni".

Aggiungere un gestore eventi per l'evento ActiveStepChanged CreateUserWizard e aggiungere il codice seguente:

protected void NewUserWizard_ActiveStepChanged(object sender, EventArgs e)
{
     // Have we JUST reached the Complete step?
     if (NewUserWizard.ActiveStep.Title == "Complete")
     {
          WizardStep UserSettings = NewUserWizard.FindControl("UserSettings") as
          WizardStep;
 
          // Programmatically reference the TextBox controls
          TextBox HomeTown = UserSettings.FindControl("HomeTown") as TextBox;
          TextBox HomepageUrl = UserSettings.FindControl("HomepageUrl") as TextBox;
          TextBox Signature = UserSettings.FindControl("Signature") as TextBox;
 
          // Update the UserProfiles record for this user
          // Get the UserId of the just-added user
          MembershipUser newUser = Membership.GetUser(NewUserWizard.UserName);
          Guid newUserId = (Guid)newUser.ProviderUserKey;
 
          // Insert a new record into UserProfiles
          string connectionString = 
               ConfigurationManager.ConnectionStrings["SecurityTutorialsConnectionString"].ConnectionString;
          string updateSql = "UPDATE UserProfiles SET HomeTown = @HomeTown, HomepageUrl
               = @HomepageUrl, Signature = @Signature WHERE UserId = @UserId";
 
          using (SqlConnection myConnection = new SqlConnection(connectionString))
          {
               myConnection.Open();
               SqlCommand myCommand = new SqlCommand(updateSql, myConnection);
               myCommand.Parameters.AddWithValue("@HomeTown", HomeTown.Text.Trim());
               myCommand.Parameters.AddWithValue("@HomepageUrl", HomepageUrl.Text.Trim());
               myCommand.Parameters.AddWithValue("@Signature", Signature.Text.Trim());
               myCommand.Parameters.AddWithValue("@UserId", newUserId);
               myCommand.ExecuteNonQuery();
               myConnection.Close();
          }
     }
}

Il codice precedente inizia determinando se è stato appena raggiunto il passaggio "Completa". Poiché il passaggio "Completa" si verifica immediatamente dopo il passaggio "Impostazioni", quindi quando il visitatore raggiunge il passaggio "Completa", significa che ha appena completato il passaggio "Impostazioni".

In questo caso, è necessario fare riferimento a livello di codice ai controlli TextBox all'interno di UserSettings WizardStep. Questa operazione viene eseguita usando innanzitutto il FindControl metodo per fare riferimento UserSettings WizardStepa livello di codice a , e quindi di nuovo per fare riferimento a TextBoxes dall'interno di WizardStep. Dopo aver fatto riferimento alle caselle di testo, è possibile eseguire l'istruzione UPDATE . L'istruzione UPDATE ha lo stesso numero di parametri dell'istruzione INSERT nel CreatedUser gestore eventi, ma in questo caso vengono usati i valori della città principale, della home page e della firma forniti dall'utente.

Con questo gestore eventi sul posto, visitare la EnhancedCreateUserWizard.aspx pagina tramite un browser e creare un nuovo account utente specificando i valori per la città principale, la home page e la firma. Dopo aver creato il nuovo account, si dovrebbe essere reindirizzati alla AdditionalUserInfo.aspx pagina, in cui vengono visualizzate le informazioni sulla città principale, sulla home page e sulla firma appena immesse.

Nota

Il nostro sito Web ha attualmente due pagine da cui un visitatore può creare un nuovo account: CreatingUserAccounts.aspx e EnhancedCreateUserWizard.aspx. La pagina di accesso e la mappa del sito Web puntano alla CreatingUserAccounts.aspx pagina, ma la CreatingUserAccounts.aspx pagina non richiede all'utente le informazioni relative alla città principale, alla home page e alla firma e non aggiunge una riga corrispondente a UserProfiles. Pertanto, aggiornare la CreatingUserAccounts.aspx pagina in modo che offra questa funzionalità o aggiornare la pagina della mappa del sito e di accesso in modo che faccia riferimento EnhancedCreateUserWizard.aspx invece di CreatingUserAccounts.aspx. Se si sceglie quest'ultima opzione, assicurarsi di aggiornare il Membership file della Web.config cartella in modo da consentire agli utenti anonimi di accedere alla EnhancedCreateUserWizard.aspx pagina.

Riepilogo

In questa esercitazione sono stati esaminati le tecniche per la modellazione dei dati correlati agli account utente all'interno del framework di appartenenza. In particolare, sono stati esaminati i modelli di entità che condividono una relazione uno-a-molti con gli account utente, nonché i dati che condividono una relazione uno-a-uno. Inoltre, è stato illustrato come visualizzare, inserire e aggiornare queste informazioni correlate, con alcuni esempi che usano il controllo SqlDataSource e altri usando ADO.NET codice.

Questa esercitazione completa l'analisi degli account utente. A partire dall'esercitazione successiva verrà rivolta l'attenzione ai ruoli. Nelle prossime esercitazioni verrà esaminato il framework Ruoli, verrà illustrato come creare nuovi ruoli, come assegnare ruoli agli utenti, come determinare i ruoli a cui appartiene un utente e come applicare l'autorizzazione basata sui ruoli.

Buon programmatori!

Altre informazioni

Per altre informazioni sugli argomenti descritti in questa esercitazione, vedere le risorse seguenti:

Informazioni sull'autore

Scott Mitchell, autore di più libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, lavora con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Scott può essere raggiunto all'indirizzo mitchell@4guysfromrolla.com o tramite il suo blog all'indirizzo http://ScottOnWriting.NET.

Grazie speciale...

Questa serie di esercitazioni è stata esaminata da molti revisori utili. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, rilasciami una riga in mitchell@4GuysFromRolla.com.