Je tente de configurer la journalisation des erreurs ELMAH dans une application ASP.NET 4 en utilisant SQL Server 2008 R2. Existe-t-il un moyen de dire à ELMAH d'appeler notre fonction de décryptage interne sur la chaîne de connexion que nous lui fournissons ? Dois-je modifier la source ELMAH et la reconstruire ?
Réponses
Trop de publicités?Vous ne pouvez pas simplement dire à ELMAH quoi faire avec votre chaîne de connexion. Ce que vous pouvez faire, cependant, est dire à ELMAH de vous rappeler quand il a besoin d'un ErrorLog
, vous donnant ainsi plus de contrôle à l'exécution. Vous pouvez ensuite lire la chaîne de connexion chiffrée, la décrypter avec votre fonction interne et retourner un SqlErrorLog initialisé avec celle-ci.
Pour ce faire, vous devez fournir une méthode compatible avec le ServiceProviderQueryHandler
délégué. Voici la définition :
public delegate IServiceProvider ServiceProviderQueryHandler(object context);
L'implémentation de la méthode doit retourner une instance d'un objet qui implémente IServiceProvider
. Si vous ne voulez pas en écrire un vous-même pour commencer, vous pouvez en obtenir un gratuitement à partir du .NET Framework. Voir System.ComponentModel.Design.ServiceContainer
. Le fournisseur de services GetService
doit répondre aux demandes du type ErrorLog
et vous pouvez alors, par exemple, retourner un objet SqlErrorLog
initialisé avec une chaîne de connexion manipulée à l'exécution. Voici une implémentation possible :
var parent = ServiceCenter.Current;
ServiceCenter.Current = context => {
var container = new ServiceContainer(parent(context));
var connectionSettings = ConfigurationManager.ConnectionStrings["FOOBAR"];
var connectionString = Decrypt(connectionSettings.ConnectionString);
var log = new SqlErrorLog(connectionString);
container.AddService(typeof(ErrorLog), log);
return container;
} ;
Cela capture le point de service actuel et installe le vôtre à la place. Le lambda/délégué créé transmet les demandes de service au point de service capturé lorsqu'il ne peut pas les satisfaire directement, créant ainsi une chaîne. Vous indiquez à ELMAH votre implémentation en définissant ServiceCenter.Current
quelque part lors de l'initialisation de votre application, donc c'est là que le code ci-dessus devra se trouver.
Gardez à l'esprit que ceci est une implémentation très simple mais cela devrait être suffisant pour vous permettre de démarrer et d'optimiser ultérieurement si nécessaire.
Avant cet ajout dans la version 1.2, la seule façon de faire quelque chose de similaire nécessitait le sous-classement et d'autres gymnastiques et donnait encore des résultats partiels. Maintenant, vous avez juste besoin de mettre en œuvre une méthode et de la remettre à ELMAH qui répond simplement aux requêtes d'ELMAH pour des objets basés sur leur type de service.
En complément du post de Atif Aziz, voici la version VB.NET (InitializeElmah_VB9 pour la version .NET 2.0 [sans lambda], InitializeElmah pour VB.NET pour .NET 4.0)
Imports System.Web.SessionState
Public Class Global_asax
Inherits System.Web.HttpApplication
Public Overrides Sub Init()
MyBase.Init()
InitializeElmah_VB9()
'InitializeElmah()'
End Sub
Public parent As Elmah.ServiceProviderQueryHandler = Nothing
Sub InitializeElmah_VB9()
' TODO: Créer Tableau + Fonctions '
parent = Elmah.ServiceCenter.Current
Elmah.ServiceCenter.Current = AddressOf ElmahCallback
End Sub
Function ElmahCallback(objContext As Object) As System.IServiceProvider
Dim container As New System.ComponentModel.Design.ServiceContainer(parent(objContext))
Dim connectionSettings As System.Configuration.ConnectionStringSettings = ConfigurationManager.ConnectionStrings("FOOBAR")
Dim strConnectionString As String = connectionSettings.ConnectionString
Dim x As New System.Data.SqlClient.SqlConnectionStringBuilder(strConnectionString)
x.Password = CryptStrings.DeCrypt(x.Password)
strConnectionString = x.ConnectionString
Dim log As Elmah.SqlErrorLog = New Elmah.SqlErrorLog(strConnectionString)
container.AddService(GetType(Elmah.ErrorLog), log)
Return container
End Function
Sub InitializeElmah()
' TODO: Créer Tableau + Fonctions '
Dim parent As Elmah.ServiceProviderQueryHandler = Elmah.ServiceCenter.Current
Elmah.ServiceCenter.Current = Function(context)
Dim container As New System.ComponentModel.Design.ServiceContainer(parent(context))
Dim connectionSettings As System.Configuration.ConnectionStringSettings = ConfigurationManager.ConnectionStrings("Foobar")
Dim connectionString As String = connectionSettings.ConnectionString
Dim x As New System.Data.SqlClient.SqlConnectionStringBuilder(connectionString)
x.Password = CryptStrings.DeCrypt(x.Password)
connectionString = x.ConnectionString
Dim log As Elmah.SqlErrorLog = New Elmah.SqlErrorLog(connectionString)
container.AddService(GetType(Elmah.ErrorLog), log)
Return container
End Function
End Sub
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' Déclenché au démarrage de l'application '
End Sub
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' Déclenché au démarrage de la session '
End Sub
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
' Déclenché au début de chaque demande '
End Sub
Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
' Déclenché lors de la tentative d'authentification de l'utilisateur '
End Sub
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Déclenché en cas d'erreur '
End Sub
Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
' Déclenché à la fin de la session '
End Sub
Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
' Déclenché à la fin de l'application '
End Sub
End Class