使用加密连接字符串配置 ELMAH 与 SQL Server 日志记录

5

我正在尝试在使用SQL Server 2008 R2的ASP.NET 4应用程序中配置ELMAH错误日志记录。有没有办法告诉ELMAH在我们提供的连接字符串上调用我们内部的解密函数?我需要修改ELMAH源代码并重新构建吗?

<configSections>
  <sectionGroup name="elmah">
    <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
    <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
    <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
    <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
  </sectionGroup>
</configSections>

<elmah>
  <security allowRemoteAccess="1" />
  <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ELMAH" />
</elmah>

<connectionStrings>
  <add name="ELMAH" connectionString="EncryptedConnectionString" providerName="System.Data.SqlClient" />
</connectionStrings>

<system.webServer>
  <handlers>
    <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
  </handlers>
  <modules>
    <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
  </modules>
</system.webServer>
2个回答

12
您不能直接告诉ELMAH要使用您的连接字符串做些什么。但是,您可以告诉ELMAH在需要ErrorLog时回调您,从而在运行时更加可控。然后,您可以使用内部函数解密加密的连接字符串,并返回已初始化为其的SqlErrorLog。
要实现这一点,您需要提供一个与 ServiceProviderQueryHandler委托兼容的方法。以下是定义:
public delegate IServiceProvider ServiceProviderQueryHandler(object context); 
该方法的实现必须返回一个实现了IServiceProvider接口的对象实例。如果您不想自己编写,可以从.NET Framework免费获取一个。请参见System.ComponentModel.Design.ServiceContainer。服务提供程序的GetService方法必须响应对ErrorLog类型的请求,然后您可以返回已在运行时处理过连接字符串初始化的SqlErrorLog对象。以下是可能的实现方式:
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; 
  } ;

该代码段捕获了当前服务点并替换为您自己的服务点。创建的lambda/delegate在无法直接满足服务请求时将其传递给捕获的服务点,从而创建一个链。您需要在应用程序初始化期间设置ServiceCenter.Current来告诉ELMAH您的实现方式,因此以上代码将需要放置在那里。

请注意,这是一个非常简单的实现,但足以让您开始并在需要时进行优化。

在1.2版之前添加此功能之前,唯一类似的方式需要子类化和其他技巧,并且仍然只能得到部分结果。现在,您只需要实现一个方法并将其交给ELMAH,该方法仅响应基于其服务类型的对象查询。


3
作为Atif Aziz帖子的补充,这里是VB.NET版本(.NET 2.0版本[不包含lambda]的InitializeElmah_VB9,以及.NET 4.0的VB.NET的InitializeElmah)。
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: Create Table + Functions '
        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: Create Table + Functions '
        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)
        ' Wird beim Starten der Anwendung ausgelöst
    End Sub


    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' Wird beim Starten der Sitzung ausgelöst
    End Sub


    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' Wird zu Beginn jeder Anforderung ausgelöst
    End Sub


    Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' Wird beim Versuch der Benutzerauthentifizierung ausgelöst
    End Sub


    Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
        ' Wird bei einem Fehler ausgelöst
    End Sub


    Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
        ' Wird beim Beenden der Sitzung ausgelöst
    End Sub


    Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
        ' Wird beim Beenden der Anwendung ausgelöst
    End Sub


End Class

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接