Archiviazione di informazioni utente aggiuntive (VB)
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
, Email
e IsLockedOut
e 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 DeliveryPreferences
PastOrders
. 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 dellaGuestbookComments
tabella
Per acquisire i commenti del guestbook, è necessario creare una tabella di database denominata GuestbookComments
con colonne come CommentId
, Subject
, Body
e 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.
Figura 1: Aggiungere una nuova tabella al SecurityTutorials
database (fare clic per visualizzare l'immagine full-size)
Definire quindi le GuestbookComments
colonne 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 INSERT
oggetto , è 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.
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 Subject
Body
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.UserId
aspnet_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.
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.
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.
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 viene stabilito al meglio 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 verranno visualizzati nei commenti del suo guestbook. Esistono diversi modi per eseguire questa operazione:
Aggiungere nuove colonne all'oggetto
aspnet_Users
Oaspnet_Membership
Tabelle. Non è consigliabile usare questo approccio perché modifica lo schema usato daSqlMembershipProvider
. Questa decisione può tornare a infestarti lungo la strada. Ad esempio, cosa accade se una versione futura di ASP.NET usa uno schema diversoSqlMembershipProvider
. Microsoft può includere uno strumento per eseguire la migrazione dei dati ASP.NET 2.0SqlMembershipProvider
al nuovo schema, ma se è stato modificato lo schema ASP.NET 2.0SqlMembershipProvider
, 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 profilo progettato per archiviare dati aggiuntivi specifici dell'utente. Analogamente al framework di appartenenza, il framework del profilo viene creato in cima al modello di provider. .NET Framework viene fornito con un oggetto
SqlProfileProvider
che archivia i dati del profilo in un database SQL Server. Infatti, il database include già la tabella usata daSqlProfileProvider
(aspnet_Profile
), come è stato aggiunto quando sono stati aggiunti di nuovo 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 inWeb.config
: non è necessario scrivere codice 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 di controllo delle versioni, quindi se si dispone di un'applicazione in cui si prevede di aggiungere nuove proprietà specifiche dell'utente in un secondo momento o quelle esistenti da rimuovere o modificare, il framework del profilo potrebbe non essere l'opzione migliore. Inoltre,SqlProfileProvider
archivia le proprietà del profilo in modo altamente denormalizzato, rendendolo accanto a impossibile eseguire query direttamente sui dati del profilo (ad esempio, quanti utenti hanno una città natale di New York).
Per altre informazioni sul framework del profilo, vedere la sezione "Altre 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 e
aspnet_Users
. Questo approccio implica un po' di più rispetto al framework profile, ma offre la 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 denominata 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. Denominare la prima colonna UserId
e impostarne il tipo su uniqueidentifier
. Non consentire NULL
valori e contrassegnare 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.
Figura 6: Creare la tabella (fare clic per visualizzare l'immagineUserProfiles
a dimensione intera)
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
, questo vincolo viene eliminato a catena. Poiché il UserId
campo in UserProfiles
è la 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 esamineremo come l'utente attualmente connesso può visualizzare e modificare la propria città natale, la home page e le informazioni sulla 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à natale, la home page e le informazioni sulla firma. È possibile creare manualmente l'interfaccia utente con i controlli TextBox e Label oppure è possibile usare uno dei controlli Web dati, ad esempio il controllo DetailsView. Per eseguire il database SELECT
e UPDATE
le istruzioni, è possibile scrivere ADO.NET codice nella classe code-behind della pagina o, in alternativa, usare un approccio dichiarativo con SqlDataSource. Idealmente, l'applicazione conterrà un'architettura a livelli, che è possibile richiamare a livello di codice dalla classe code-behind della pagina o in modo dichiarativo tramite il controllo ObjectDataSource.
Poiché questa serie di esercitazioni è incentrata sull'autenticazione basata su moduli, autorizzazione, account utente e ruoli, non verrà esaminata in dettaglio queste diverse opzioni di accesso ai dati o il motivo per cui è preferibile un'architettura a livelli rispetto all'esecuzione di istruzioni SQL direttamente dalla pagina ASP.NET. Si passerà attraverso l'uso di detailsView e SqlDataSource, l'opzione più rapida e più semplice, ma i concetti illustrati possono essere certamente applicati a controlli Web alternativi e logica di accesso ai dati. Per altre informazioni sull'uso dei dati in ASP.NET, vedere l'esercitazione Uso dei dati in ASP.NET serie di esercitazioni 2.0 .
Aprire la AdditionalUserInfo.aspx
pagina nella Membership
cartella e aggiungere un controllo DetailsView alla pagina, impostando la relativa proprietà ID 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 ID
UserProfileDataSource
.
Figura 7: Aggiungere un nuovo controllo SqlDataSource denominato UserProfileDataSource
(fare clic per visualizzare l'immagine a dimensione intera)
Nella schermata successiva viene richiesto di usare il database. Per il SecurityTutorials
database è già stato definito un stringa di connessioneWeb.config
. Questo stringa di connessione nome: SecurityTutorialsConnectionString
deve essere nell'elenco a discesa. Selezionare questa opzione e fare clic su Avanti.
Figura 8: Scegliere SecurityTutorialsConnectionString
dall'elenco Drop-Down (fare clic per visualizzare l'immagine a dimensione intera)
Nella schermata successiva viene chiesto di specificare la tabella e le colonne su cui eseguire la query. Scegliere la UserProfiles
tabella dall'elenco a discesa e selezionare tutte le colonne.
Figura 9: Ripristinare tutte le colonne dalla UserProfiles
tabella (fare clic per visualizzare l'immagine a dimensione intera)
La query corrente nella figura 9 restituisce tutti i record in UserProfiles
, ma si è interessati solo al record dell'utente attualmente connesso. Per aggiungere una WHERE
clausola, fare clic sul WHERE
pulsante per visualizzare la finestra di dialogo Aggiungi WHERE
clausola (vedere la figura 10). Qui è possibile selezionare la colonna per filtrare, l'operatore e l'origine del parametro di filtro. Selezionare UserId
come colonna e "=" come Operatore.
Sfortunatamente non esiste un'origine di 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.
Figura 10: Aggiungere un parametro di filtro nella UserId
colonna (fare clic per visualizzare l'immagine a dimensione intera)
Dopo aver fatto clic su OK, si tornerà 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 "Test query". Qui è possibile eseguire la query e visualizzare i risultati. Fare clic su Fine per completare la procedura guidata.
Al termine della Configurazione guidata origine dati, Visual Studio crea il controllo SqlDataSource in base alle impostazioni specificate nella procedura guidata. Aggiunge inoltre manualmente BoundFields a DetailsView per ogni colonna restituita dall'oggetto SelectCommand
SqlDataSource. Non è necessario visualizzare il UserId
campo in DetailsView, perché l'utente non deve conoscere questo valore. È possibile rimuovere questo campo direttamente dal markup dichiarativo del controllo DetailsView oppure facendo clic sul collegamento "Modifica campi" dallo 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 sull'utente attualmente connesso prima che UserId
i dati vengano selezionati. A tale scopo, è possibile creare un gestore eventi per l'evento sqlDataSource Selecting
e aggiungere il codice seguente:
Protected Sub UserProfileDataSource_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceSelectingEventArgs) Handles UserProfileDataSource.Selecting
' Get a reference to the currently logged on user
Dim currentUser As MembershipUser = Membership.GetUser()
' Determine the currently logged on user's UserId value
Dim currentUserId As Guid = CType(currentUser.ProviderUserKey, Guid)
' Assign the currently logged on user's UserId to the @UserId parameter
e.Command.Parameters("@UserId").Value = currentUserId
End Sub
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 l'oggetto 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 visita la pagina, restituirà il valore Nothing
. In tal caso, ciò comporterà un oggetto NullReferenceException
nella riga di codice seguente quando si tenta di leggere la ProviderUserKey
proprietà. Naturalmente, non è necessario preoccuparsi di Membership.GetUser()
restituire Nothing nella AdditionalUserInfo.aspx
pagina perché l'autorizzazione url è stata configurata 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 l'oggetto MembershipUser
restituito dal GetUser()
metodo non sia Nothing 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 righe 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 ed espandere la cartella Tabelle. Fare clic con il pulsante destro del aspnet_Users
mouse sulla 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 affiancato verticalmente. Nel mio database ci sono attualmente aspnet_Users
record per Bruce, Fred e Tito, ma nessun record nella UserProfiles
tabella.
Figura 11: Vengono visualizzati i aspnet_Users
contenuti delle tabelle e UserProfiles
(fare clic per visualizzare l'immagine a dimensione intera)
Aggiungere un nuovo record alla UserProfiles
tabella digitando manualmente i valori per i HomeTown
campi , HomepageUrl
e 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.
Figura 12: Un record è stato aggiunto a UserProfiles
Bruce (fare clic per visualizzare l'immagine a dimensioni complete)
Tornare a AdditionalUserInfo.aspx page
, connesso come Bruce. Come illustrato nella figura 13, vengono visualizzate le impostazioni di Bruce.
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 Comando e Parametro Editor. 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.
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.
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. ID
SettingsUpdatedMessage
Impostare 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 Sub UserProfile_ItemUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs) Handles UserProfile.ItemUpdated
SettingsUpdatedMessage.Visible = True
End Sub
Tornare alla AdditionalUserInfo.aspx
pagina tramite un browser e aggiornare i dati. Questa volta viene visualizzato un messaggio di stato utile.
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.
Aggiunta di un collegamento allaAdditionalUserInfo.aspx
pagina nella pagina master
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 lnkUpdateSettings
LoggedInTemplate
. 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 Body
ID
rispettivamente su , Width
TextMode
MultiLine
Rows
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 ValidationGroup
PostCommentButton
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 InsertCommand
e 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 Imports System.Data.SqlClient
.
Creare un gestore eventi per l'evento PostCommentButton
e Click
aggiungere il codice seguente:
Protected Sub PostCommentButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles PostCommentButton.Click
If Not Page.IsValid Then Exit Sub
' Determine the currently logged on user's UserId
Dim currentUser As MembershipUser = Membership.GetUser()
Dim currentUserId As Guid = CType(currentUser.ProviderUserKey, Guid)
' Insert a new record into GuestbookComments
Dim connectionString As String =
ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString
Dim insertSql As String = "INSERT INTO GuestbookComments(Subject, Body, UserId)
VALUES(@Subject, @Body, @UserId)"
Using myConnection As New SqlConnection(connectionString)
myConnection.Open()
Dim myCommand As 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()
End Using
' "Reset" the Subject and Body TextBoxes
Subject.Text = String.Empty
Body.Text = String.Empty
End Sub
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 recuperato Web.config
il 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.
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 CommentsDataSource
risultante e fare clic su OK. Selezionare quindi il 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 GuestbookComments
tabelle , UserProfiles
e 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 GuestbookComments
tabelle , UserProfiles
e 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 Subject
colonne , Body
e CommentDate
, restituire le HomeTown
colonne , HomepageUrl
e 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.
Figura 18: Query costruita JOIN
nelle GuestbookComments
tabelle , UserProfiles
e 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
, ItemTemplate
e 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 ItemTemplate
markup risultante viene inserito nel LayoutTemplate
controllo 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.
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 delClick
pulsante in modo che richiami il metodo delDataBind()
controllo ListView dopo aver inserito il nuovo commento nel database o - Impostazione della proprietà del
EnableViewState
controllo ListView suFalse
. 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 GuestbookComments
tabelle , UserProfiles
e 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 GuestbookComments
INNER 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 HomeTown
colonne , HomepageUrl
e 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 NewUserWizard
di CreatedUser
e aggiungere il codice seguente:
Protected Sub NewUserWizard_CreatedUser(ByVal sender As Object, ByVal e As System.EventArgs) Handles NewUserWizard.CreatedUser
' Get the UserId of the just-added user
Dim newUser As MembershipUser = Membership.GetUser(NewUserWizard.UserName)
Dim newUserId As Guid = CType(newUser.ProviderUserKey, Guid)
' Insert a new record into UserProfiles
Dim connectionString As String =
ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString
Dim insertSql As String = "INSERT INTO UserProfiles(UserId, HomeTown, HomepageUrl,
Signature) VALUES(@UserId, @HomeTown, @HomepageUrl, @Signature)"
Using myConnection As New SqlConnection(connectionString)
myConnection.Open()
Dim myCommand As 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()
End Using
End Sub
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à.
Viene quindi recuperato il stringa di connessione 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 @HomeTown
parametri , @HomepageUrl
e @Signature
, che ha l'effetto di inserire valori di database NULL
per i HomeTown
campi , HomepageUrl
e 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
, HomepageUrl
e Signature
).
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 da inviare all'utente quando il pulsante Continua viene fatto clic tramite la proprietà del ContinueDestinationPageUrl
controllo CreateUserWizard. Impostare la ContinueDestinationPageUrl
proprietà su "~/Membership/AdditionalUserInfo.aspx". In questo modo il nuovo utente viene visualizzato AdditionalUserInfo.aspx
e aggiornato.
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 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à di casa, 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 spostamento 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 WizardSteps
: 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
, CreateUserWizardStep
esegue il rendering dell'interfaccia che richiede il nome utente, la password, la posta elettronica e così via. Dopo che il visitatore fornisce queste informazioni e fa clic su "Crea utente", viene visualizzata , CompleteWizardStep
che mostra il messaggio di esito positivo e un pulsante Continua.
Per personalizzare l'interfaccia del controllo CreateUserWizard per includere campi modulo aggiuntivi, è possibile:
Creare uno o più nuovi
WizardStep
s per contenere gli elementi aggiuntivi dell'interfaccia utente. Per aggiungere un nuovoWizardStep
oggetto a CreateUserWizard, fare clic sul collegamento "Aggiungi/RimuoviWizardStep
s" dal relativo Smart Tag per avviare l'EditorWizardStep
raccolta. Da qui è possibile aggiungere, rimuovere o riordinare i passaggi della procedura guidata. Questo è l'approccio che verrà usato per questa esercitazione.Convertire l'oggetto
CreateUserWizardStep
in un oggetto modificabileWizardStep
. Questo sostituisce l'oggetto con un equivalente il cui markup definisce un'interfacciaCreateUserWizardStep
WizardStep
utente corrispondente a quellaCreateUserWizardStep
di . Convertendo in un oggettoWizardStep
è possibile riposizionare i controlli o aggiungere altri elementi dell'interfacciaCreateUserWizardStep
utente a questo passaggio. Per convertire oCreateUserWizardStep
CompleteWizardStep
in un oggetto modificabileWizardStep
, fare clic sul collegamento "Personalizza passaggio utente" o "Personalizza passaggio completo" dal smart tag del controllo.Usare una combinazione delle due opzioni precedenti.
Una cosa importante da tenere presente è che il controllo CreateUserWizard esegue il processo di creazione dell'account utente quando il pulsante "Crea utente" viene fatto clic dall'interno del relativo CreateUserWizardStep
controllo . Non importa se ci sono altri WizardStep
elementi dopo o CreateUserWizardStep
meno.
Quando si aggiunge un oggetto personalizzato al controllo CreateUserWizard per raccogliere un input utente aggiuntivo, è possibile inserire l'oggetto personalizzato WizardStep
WizardStep
prima o dopo .CreateUserWizardStep
Se viene prima dell'oggetto CreateUserWizardStep
, l'input utente aggiuntivo raccolto dall'oggetto personalizzato WizardStep
è disponibile per il CreatedUser
gestore eventi. Tuttavia, se la personalizzazione WizardStep
viene eseguita dopo CreateUserWizardStep
l'ora in cui viene WizardStep
visualizzato il nuovo account utente è già stato creato e l'evento CreatedUser
è già stato attivato.
La figura 21 mostra il flusso di lavoro quando l'aggiunta WizardStep
precede .CreateUserWizardStep
Poiché le informazioni utente aggiuntive sono state raccolte al momento CreatedUser
dell'attivazione dell'evento, è necessario aggiornare il CreatedUser
gestore eventi per recuperare questi input e usarli per i INSERT
valori dei parametri dell'istruzione anziché DBNull.Value
.
Figura 21: Flusso di lavoro CreateUserWizard Quando un'altra WizardStep
precede CreateUserWizardStep
(fare clic per visualizzare l'immagine full-size)
Se la personalizzata WizardStep
viene inserita dopo il CreateUserWizardStep
processo di creazione dell'account utente, tuttavia, prima che l'utente abbia avuto la possibilità di immettere la propria città, la home page o la firma. In tal caso, queste informazioni aggiuntive devono essere inserite nel database dopo la creazione dell'account utente, come illustrato nella figura 22.
Figura 22: Flusso di lavoro CreateUserWizard quando viene aggiunto dopo (Fare clic per visualizzare l'immagineWizardStep
CreateUserWizardStep
a dimensioni complete)
Il flusso di lavoro illustrato nella figura 22 attende di inserire un record nella tabella fino al completamento del UserProfiles
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'avere CreatedUser
un record con NULL
o valori predefiniti inseriti UserProfiles
nel gestore eventi (che viene generato dopo il passaggio 1) e quindi aggiornare questo record dopo il completamento del passaggio 2. Ciò garantisce che un UserProfiles
record venga aggiunto per l'account utente anche se l'utente interrompe il processo di registrazione a metà strada.
Per questa esercitazione verrà creato un nuovo WizardStep
che si verifica dopo l'oggetto CreateUserWizardStep
ma prima di CompleteWizardStep
. Si otterrà prima di tutto la procedura guidata e configurata e quindi si esaminerà il codice.
Dal controllo Smart Tag CreateUserWizard selezionare la finestra di dialogo "Aggiungi/RimuoviWizardStep
", che visualizza la WizardStep
finestra di dialogo Raccolta Editor. Aggiungere un nuovo WizardStep
oggetto , impostandone UserSettings
ID
su , Title
su "Impostazioni" e su StepType
Step
. Posizionarla quindi in modo che venga eseguita dopo l'opzione ("Iscriversi per il nuovo account") e prima di CreateUserWizardStep
CompleteWizardStep
("Completa"), come illustrato nella figura 23.
Figura 23: Aggiungere un nuovo WizardStep
al controllo CreateUserWizard (fare clic per visualizzare l'immagine full-size)
Fare clic su OK per chiudere la WizardStep
finestra di dialogo Raccolta Editor. 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 la città principale, la home page e la firma del nuovo utente qui. È possibile immettere questo contenuto nella sintassi dichiarativa o tramite il Designer. Per usare la Designer, selezionare il passaggio "Impostazioni" dall'elenco a discesa in Smart Tag per visualizzare il passaggio nel Designer.
Nota
Selezionando un passaggio nell'elenco a discesa di Smart Tag viene aggiornata la proprietà del controllo ActiveStepIndex
CreateUserWizard, che specifica l'indice del passaggio iniziale. Pertanto, se si usa questo elenco a discesa per modificare il passaggio "Impostazioni" nella Designer, assicurarsi di impostarlo su "Iscriversi per il nuovo account" in modo che questo passaggio venga visualizzato quando gli utenti visitano la EnhancedCreateUserWizard.aspx
pagina.
Creare un'interfaccia utente all'interno del passaggio "Impostazioni" che contiene tre controlli TextBox denominati HomeTown
, HomepageUrl
e 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>
Vai avanti e visita questa pagina tramite un browser e crea 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
, HomepageUrl
e Signature
. I valori immessi per la città principale, la home page e la firma non vengono mai usati. Il risultato netto è un nuovo account utente con un UserProfiles
record il cui HomeTown
oggetto , HomepageUrl
e Signature
i campi devono ancora essere specificati.
È necessario eseguire il codice dopo il passaggio "Impostazioni" che esegue la città principale, l'honepage e i valori di firma immessi dall'utente e aggiornano il record appropriato UserProfiles
. Ogni volta che l'utente si sposta tra i passaggi in un controllo Procedura guidata, viene generato l'evento della ActiveStepChanged
procedura guidata. È possibile creare un gestore eventi per questo evento e aggiornare la tabella al termine del UserProfiles
passaggio "Impostazioni".
Aggiungere un gestore eventi per l'evento ActiveStepChanged
CreateUserWizard e aggiungere il codice seguente:
Protected Sub NewUserWizard_ActiveStepChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles NewUserWizard.ActiveStepChanged
' Have we JUST reached the Complete step?
If NewUserWizard.ActiveStep.Title = "Complete" Then
Dim UserSettings As WizardStep = CType(NewUserWizard.FindControl("UserSettings"),WizardStep)
' Programmatically reference the TextBox controls
Dim HomeTown As TextBox = CType(UserSettings.FindControl("HomeTown"), TextBox)
Dim HomepageUrl As TextBox = CType(UserSettings.FindControl("HomepageUrl"), TextBox)
Dim Signature As TextBox = CType(UserSettings.FindControl("Signature"), TextBox)
' Update the UserProfiles record for this user
' Get the UserId of the just-added user
Dim newUser As MembershipUser = Membership.GetUser(NewUserWizard.UserName)
Dim newUserId As Guid = CType(newUser.ProviderUserKey, Guid)
' Insert a new record into UserProfiles
Dim connectionString As String = ConfigurationManager.ConnectionStrings("SecurityTutorialsConnectionString").ConnectionString
Dim updateSql As String = "UPDATE UserProfiles SET HomeTown = @HomeTown, HomepageUrl
= @HomepageUrl, Signature = @Signature WHERE UserId = @UserId"
Using myConnection As New SqlConnection(connectionString)
myConnection.Open()
Dim myCommand As 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()
End Using
End If
End Sub
Il codice precedente inizia determinando se è stato appena raggiunto il passaggio "Complete". Poiché il passaggio "Completa" si verifica immediatamente dopo il passaggio "Impostazioni", quindi quando il visitatore raggiunge il passaggio "Completa" che 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 prima usando il FindControl
metodo per fare riferimento a livello di codice a livello di codice a , e quindi di nuovo per fare riferimento UserSettings WizardStep
alle Caselle di testo 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 INSERT
dell'istruzione nel CreatedUser
gestore eventi, ma qui vengono usati i valori home town, homepage e signature forniti dall'utente.
Con questo gestore eventi sul posto, visitare la pagina tramite un browser e creare un nuovo account utente specificando i valori per la città principale, la EnhancedCreateUserWizard.aspx
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 home town, sulla home page e sulla firma appena immesse.
Nota
Il nostro sito Web include 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 pagina, ma la CreatingUserAccounts.aspx
pagina non richiede all'utente le informazioni relative alla CreatingUserAccounts.aspx
città, alla home page e alla firma e non aggiunge una riga corrispondente a UserProfiles
. Pertanto, aggiornare la pagina in modo da offrire questa funzionalità o aggiornare la pagina della sitemap e l'account CreatingUserAccounts.aspx
di accesso per fare riferimento EnhancedCreateUserWizard.aspx
invece di CreatingUserAccounts.aspx
. Se si sceglie l'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 esaminate le tecniche per la modellazione dei dati correlati agli account utente all'interno del framework Di appartenenza. In particolare, sono stati esaminati le entità di modellazione 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 usando il controllo SqlDataSource e altri usando il codice ADO.NET.
Questa esercitazione completa l'analisi degli account utente. A partire dall'esercitazione successiva verrà rivolta l'attenzione ai ruoli. Nelle successive esercitazioni verrà esaminato il framework Ruoli, vedere 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.
Programmazione felice!
Altre informazioni
Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:
- Accesso e aggiornamento dei dati in ASP.NET 2.0
- controllo procedura guidata ASP.NET 2.0
- Creazione di un'interfaccia utente dettagliata con il controllo procedura guidata ASP.NET 2.0
- Creazione di parametri di controllo DataSource personalizzati
- Personalizzazione del controllo CreateUserWizard
- Guida introduttiva al controllo DetailsView
- Visualizzazione dei dati con il controllo ListView
- Analisi dei controlli di convalida in ASP.NET 2.0
- Modifica di inserimento ed eliminazione di dati
- Convalida dei moduli in ASP.NET
- Raccolta di informazioni di registrazione utente personalizzate
- Profili in ASP.NET 2.0
- Controllo asp:ListView
- Guida introduttiva ai profili utente
Informazioni sull'autore
Scott Mitchell, autore di più libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, allenatore 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 speciali a...
Questa serie di esercitazioni è stata esaminata da molti revisori utili. Interessati a esaminare i prossimi articoli MSDN? In tal caso, lasciami una riga in mitchell@4GuysFromRolla.com.