2009-03-25 11 views
0

utilisant ASP.NET 2.0 SqlMembershipProvider Pour illustrer problème avec MSSQL 2005.contrôle de connexion ASP.NET et ADO.NET connexion mise en commun

:

1) Créer une application simple ASP.NET avec un System.Web. Contrôle UI.WebControls.Login sur une page. Modifiez Web.config pour utiliser l'authentification par formulaires et System.Web.Security.SqlMembershipProvider.

2) Exécutez l'application Web dans le navigateur et connectez-vous. Fermer le navigateur

3) À l'aide d'un outil SQL (tel que SQL Server Management Studio), exécutez sp_who2 pour voir les connexions. Trouvez SPID pour la connexion utilisée par le SqlMembershipProvider à l'étape 2, et exécuter

kill <the found SPID> 

(Suppose mise en commun de connexion est utilisé, ce qui est par défaut).

4) Réexécutez l'application Web dans le navigateur. Essayez de vous reconnecter. Cette fois-ci un SqlException comme ce qui suit est élevé:

[SqlException (0x80131904): A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)] 
    System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +925466 
    System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +800118 
    System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) +186 
    System.Data.SqlClient.TdsParserStateObject.ThrowExceptionAndWarning() +13 
    System.Data.SqlClient.TdsParserStateObject.WriteSni() +682631 
    System.Data.SqlClient.TdsParserStateObject.WritePacket(Byte flushMode) +265 
    System.Data.SqlClient.TdsParserStateObject.ExecuteFlush() +51 
    System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc) +4163 
    System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +1005 
    System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +132 
    System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32 
    System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +122 
    System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior) +62 
    System.Web.Security.SqlMembershipProvider.GetPasswordWithFormat(String username, Boolean updateLastLoginActivityDate, Int32& status, String& password, Int32& passwordFormat, String& passwordSalt, Int32& failedPasswordAttemptCount, Int32& failedPasswordAnswerAttemptCount, Boolean& isApproved, DateTime& lastLoginDate, DateTime& lastActivityDate) +1121 
    System.Web.Security.SqlMembershipProvider.CheckPassword(String username, String password, Boolean updateLastLoginActivityDate, Boolean failIfNotApproved, String& salt, Int32& passwordFormat) +105 
    System.Web.Security.SqlMembershipProvider.CheckPassword(String username, String password, Boolean updateLastLoginActivityDate, Boolean failIfNotApproved) +42 
    System.Web.Security.SqlMembershipProvider.ValidateUser(String username, String password) +83 
    System.Web.UI.WebControls.Login.OnAuthenticate(AuthenticateEventArgs e) +160 
    System.Web.UI.WebControls.Login.AttemptLogin() +105 
    System.Web.UI.WebControls.Login.OnBubbleEvent(Object source, EventArgs e) +99 
    System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35 
    System.Web.UI.WebControls.Button.OnCommand(CommandEventArgs e) +115 
    System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +163 
    System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +7 
    System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +11 
    System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33 
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1746 

Maintenant, je comprends pourquoi cela se passe - à savoir son dû à une connexion mis en commun qui a été tué, et est donc invalide lorsque le contrôle de connexion essaie de réutiliser. La commande de session "kill" est exécutée à l'étape 3 pour simuler ce qui se passerait, par exemple, lorsque vous devez restaurer une base de données. Vous devez supprimer toutes les connexions à une base de données avant de pouvoir la restaurer.

Forcer le redémarrage de l'application Web après la commande kill résout le problème, mais je me demande s'il existe un moyen relativement simple de rendre le processus de connexion plus robuste. Ce serait idéal si d'une manière ou d'une autre, je pouvais attraper cette exception pendant le processus d'authentification, et réessayer le login (puisque ADO.NET semble effacer le pool de connexions après un échec comme celui-ci, je pense que la tentative fonctionnerait).

+0

Je devrais ajouter: désactiver la mise en commun des connexions n'est pas une option viable ici –

+0

Cher dieu, utilisez le langage de balisage intégré! –

Répondre

1

Vous pouvez possiblly créer un nouveau contrôle de connexion qui hérite de la asp: contrôle de connexion puis passer outre la méthode ValidateUser, un peu comme:

public override bool ValidateUser(string strName, string strPassword) 
{  
    bool boolReturn = false; 

    UserProvider oUserProvider = new UserProvider(); 
    User oUser = oUserProvider.FindUser(strName); 

    if (oUser == null) 
     return boolReturn; 

    boolReturn = oUser.ValidateUsersPasswordForLogon(strPassword); 

    return boolReturn; 
} 

Ensuite, mettre un try/catch autour de la création de la classe utilisateur (attraper une SqlException) puis réessayer la connexion?

Je havnt fait trop de travail avec les classes d'adhésion de réSEAU si im pas trop sûr

0

Est-ce pour la production ou le développement? Je ne vois pas le gros problème dans le redémarrage du serveur web en développement. Et pour la production, je redémarrerais tout de même le serveur web pour m'assurer que toutes les données mises en cache soient effacées car la base de données restaurée pourrait très bien avoir des données différentes.

Questions connexes