65.9K
CodeProject 正在变化。 阅读更多。
Home

ELMAH 在 GAC 中 – 从全局程序集缓存中使用 ELMAH

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.25/5 (6投票s)

2011年8月2日

CPOL

13分钟阅读

viewsIcon

40928

一个启用 ELMAH(错误日志记录模块和处理程序)全站使用的分步指南。

引言

您可能听说过,甚至可能使用过 ELMAH,这是一个开源的 ASP.NET 项目,用于记录 Web 应用程序的未处理异常。还有一种方法可以将其提供给由不同团队成员开发的整个网站中的所有 Web 应用程序。但是,除非一个人已经对 ELMAH 之外使其正常工作所需的组件有足够的了解,否则这不是一项容易完成的任务。开发人员可能会花费很多时间(至少我花了)从不同的来源追寻零散的信息,直到它们最终汇集在一起。到目前为止,我还没有看到一份关于设置 ELMAH 以实现灵活、全站使用的完整文档。

这是一个分步指南,介绍如何在您的 Web 服务器上设置 ELMAH,以便给定 .NET Framework 版本的​​所有 ASP.NET WebForms 应用程序都能被 ELMAH 默默监控,并且所有未处理的异常都会被记录。我将展示如何选择性地编码单个应用程序的web.config,以便将其错误通知(对于 ELMAH 捕获和记录的未处理异常)发送到特定的电子邮件地址。这会将应用程序的错误电子邮件消息的传递限制为仅对该应用程序的感兴趣方(开发人员),而不是对甚至没有参与该特定应用程序开发的开发人员。

背景

许多 .NET 开发人员已经发现了 ELMAH(错误日志记录模块和处理程序),这是记录和查看 Web 应用程序未处理异常的绝佳方法。ELMAH 由 Atif Aziz 开发,该项目 在 Google Code 上。除了 ELMAH DLL 和使用示例外,ELMAH 的 Google Code 主页还包含讨论、一个问题部分和一个包含 ELMAH 文章列表的 Wiki。事实上,这个操作指南的灵感来自于该网站上 Atif Aziz 和 Bart Hermans 之间的一次讨论

ELMAH 可以轻松地按应用程序安装,只需在项目中添加引用(将 Elmah.dll 放入项目的 bin 文件夹)并在项目的 web.config 文件中添加特定行。为什么要使用 ELMAH?您不太可能通过 Try/Catch 块来预期和捕获 Web 应用中的所有可能错误。ELMAH 会让您了解“溜走”的每个异常的详细信息。这也是在测试过程中了解 WebForms 应用程序中 bug 的绝佳方式。

即使您不想尝试实现全站 ELMAH,也值得您从上面的链接下载 ELMAH。您可以快速设置它来记录单个 Web 应用程序项目的未处理异常。一旦您看到它如何捕获并向您报告每个未处理的异常,您可能会沉迷其中。然后,您会想回到这里并遵循“操作指南”,将其添加到您的整个网站中,这样您就不需要在每个项目的 /bin 文件夹中放置 ELMAH 的 DLL,并且您不需要在每个应用程序的 web.config 中放置相同的 ELMAH 部分。

步骤 1 - 从 ELMAH Google Code 网站下载示例 web.config 和源代码

官方 ELMAH 示例 web.config 向您展示了应放入自己 web.config 文件中的 ELMAH 部分。它们都有很好的注释。对于单个 Web 应用程序,您只需要从下载页面下载预编译的二进制文件(根据您的环境选择 32 位或 64 位)。其中包含一个示例 web.config。但是,对于全站使用,请仅下载二进制文件以尝试单个 Web 应用程序。您真正需要下载的是源代码,以便您可以编译一个强命名的 Elmah.dll 以用于您的全局程序集缓存。如果您不下载二进制文件,则有一个示例 web.config 可供下载。

步骤 2 - 使用强命名密钥编译源代码

放置在 GAC(全局程序集缓存)中的所有程序集都必须进行强命名,这要归功于强名称工具对其进行的签名所使用的私钥,从而确保了它们的全局唯一性。

解压缩您下载的“Sources”,然后导航到 src\Solutions 并打开适用于您要安装 ELMAH 的 .NET Framework 版本的​​解决方案文件。在撰写本文时,.NET 2.0 及以上版本的唯一解决方案是 Visual Studio 2010。如果您只有 VS2005 或 VS2008,您可能可以使用免费的 Visual Studio 2010 Express 或 Visual C# 2010 Express(源代码文件为 C#)来编译源代码。

在 Visual Studio 2010 中打开解决方案后,右键单击解决方案资源管理器中的项目,然后选择“属性”。现在,选择“签名”并选中“签名程序集”。

从下拉列表中,选择 <新建...> 并输入您选择的密钥文件名。取消选中“用密码保护我的密钥文件”复选框。保存属性。像往常一样构建项目。您的 bin 文件夹现在应该有一个已进行强命名签名的 Elmah.dll。要验证它确实是强命名的,您可以使用强名称工具(sn.exe)或 Microsoft 中间语言反汇编器(ILDASM.EXE)。这篇博客展示了如何执行其中任何一种。或者,您可以简单地相信它是强命名的。如果不是,下一步将无法进行,那将告诉您!

步骤 3 - 将强命名的 Elmah.dll 程序集安装到全局程序集缓存

您可以通过创建安装项目并使用 MSI 进行安装来将程序集放入全局程序集缓存。尽管这是微软的官方方法(如果您的服务器具有非常严格的访问控制,这可能是唯一的方法),但它超出了本文的范围。一种更简单的方法是这样做:将强命名的 Elmah.dll 复制到 Web 服务器上某个文件夹中的临时位置。然后登录到该服务器,无论是在其控制台还是通过远程桌面,然后再尝试将程序集(Elmah.dll)添加到 GAC。我提到这一点是因为我喜欢使用一种方法,即在一个 Windows Explorer 实例之间拖放 DLL。(我根据个人经验得知,当我想通过网络查看 Web 服务器的 GAC 时,Windows Explorer 中的 GAC 视图(这是一个外壳扩展)显示的是我自己的 PC 的 GAC 文件,而不是 Web 服务器的 GAC 文件!)

一旦您在 Web 服务器上打开了两个 Windows Explorer 实例(一个用于您临时放置强命名 Elmah.dll 的文件夹,另一个用于 GAC,通常位于 C:\Windows\Assembly),您会注意到 GAC 的 Windows Explorer 视图看起来与您预期的不同。那是因为您正在通过我提到的外壳扩展查看 GAC。它会显示程序集名称、版本和公钥令牌等属性。

Elmah.dll 从您的临时位置拖放到 GAC 的 Windows Explorer 视图中。如果它确实是强命名的,Elmah.dll 现在将出现在 GAC 视图中(尽管您可能需要刷新视图才能看到它)。

恭喜 - 最难的部分完成了!现在,右键单击“程序集名称”列中的 ELMAH,然后选择“属性”。选择“公钥令牌”值,并将其复制/粘贴到安全的地方,例如文本文件,供您下一步使用。

步骤 4 - 修改服务器的 web.config

正如您从 ELMAH 网站下载的示例 web.config 中所见,它包含一些 ELMAH 特定的部分。您至少需要将其中一些添加到您自己的 web.config。您可以将它们放在 Web 应用程序的 web.config 中,ELMAH 也可以正常工作,即使您的 Web 应用程序的 bin 文件夹中没有 Elmah.dll。这是因为您已将强命名的 Elmah.dll 放置在全局程序集缓存中。如果您只想记录特定应用程序的错误,这样做就可以了。但是,如果您想记录使用特定版本 .NET Framework 的每个 Web 应用程序的未处理异常,更好的方法是修改“根”web.config,例如 .NET 2.0 Framework。

每个 .NET Framework 版本(3.0 和 3.5 除外,它们依赖于 2.0 框架)都有自己的“CONFIG”文件夹,其中包含 machine.configweb.config。在我们的示例中,查找位于 C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIGweb.config。将其副本保存起来作为备份,尤其是在生产服务器上。

打开上面提到的服务器框架 web.config,并进行编辑,以包含您从 ELMAH 网站下载的示例 web.config 中的 ELMAH 部分。我将在下面展示一些示例代码,这些代码足以满足记录错误和设置页面处理程序以向查看特定 Web 应用程序错误的所有已登录用户显示的最低要求。请注意,我喜欢在“ELMAH 特定部分”周围添加注释,以便以后找到它们。此外,我使用了垂直省略号来简单地表示 web.config 中不需要在此示例中显示的现有部分。不要将这些省略号编码到您的 web.config 中!

<!-- Web server's web.config file, 
     at C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <!-- Begin an ELMAH specific section -->
        <sectionGroup name="elmah">
            <section name="security" requirePermission="false" 
               type="Elmah.SecuritySectionHandler, Elmah, 
                     Version=1.2.13605.0, Culture=neutral, 
                     PublicKeyToken=6235d7ef90b85eg2"/>
            <section name="errorLog" requirePermission="false" 
               type="Elmah.ErrorLogSectionHandler, Elmah, Version=1.2.13605.0, 
                     Culture=neutral, PublicKeyToken=6235d7ef90b85eg2"/>
        </sectionGroup>
        <!-- End an ELMAH specific section -->
    </configSections>

    <!-- Begin an ELMAH specific section -->
    <elmah>
        <security allowRemoteAccess="yes" />
        <errorLog type="Elmah.SqlErrorLog, Elmah, Version=1.2.13605.0, 
                        Culture=neutral, PublicKeyToken=6235d7ef90b85eg2" 
           connectionStringName="ELMAH_Logging" />
    </elmah>
    <!-- End an ELMAH specific section -->

    <!-- Begin an ELMAH specific section -->
    <location path="elmah.axd">
        <system.web>
            <authorization>
                <deny users="?"/>
            </authorization>
        </system.web>
    </location>
    <!-- End an ELMAH specific section -->
    .
    .
    .
    <system.web>
        .
        .
        .
        <httpHandlers>
            <!-- Begin an ELMAH specific section -->
            <add verb="POST,GET,HEAD" path="elmah.axd" 
               type="Elmah.ErrorLogPageFactory, Elmah, Version=1.2.13605.0, 
                     Culture=neutral, PublicKeyToken=6235d7ef90b85eg2"/>
            <!-- End an ELMAH specific section -->
            .
            .
            .
        </httpHandlers>

        <httpModules>
            <!-- Begin an ELMAH specific section -->
            <add name="ErrorLog" 
              type="Elmah.ErrorLogModule, Elmah, Version=1.2.13605.0, 
                    Culture=neutral, PublicKeyToken=6235d7ef90b85eg2"/>
            <!-- End an ELMAH specific section -->
            .
            .
            .
        </httpModules>
        .
        .
        .
    </system.web>

    <connectionStrings>
        <!-- Begin an ELMAH specific section -->
        <add name="ELMAH_Logging"
            connectionString="Server=OurDBServer;Database=SomeDB;
                              User ID=user;Password=ourpass;" />
        <!-- End an ELMAH specific section -->
    </connectionStrings>
    
</configuration>

上面的代码已换行以避免页面滚动

我想指出关于上面的 web.config 文件(我再说一遍,这是您整个 Web 服务器上特定框架版本的所有 Web 应用程序的“根”web.config)的几点

  • 首先,没有关于将错误消息通过电子邮件发送给开发人员的部分。我建议将这些部分放入每个 Web 应用程序的 web.config 文件中,因为这样可以让我们对谁接收每个应用程序的消息进行精细控制。您很可能不希望将服务器所有 Web 应用程序的 ELMAH 消息发送到任何一个电子邮件地址或电子邮件分发列表。
  • 其次,您必须web.config 中的每个 ELMAH 特定元素中将 VersionPublicKeyToken 部分添加到“type”属性,因为您正在 GAC 中使用强命名的 Elmah.dll 版本。我在我的版本中还添加了 Culture=neutral,但我不确定这是否是必需的。您可能也想保留您的版本,尤其是在 Windows Explorer GAC 视图显示“Culture”列中的值时。我将在此引用 ELMAH 作者 Atif Aziz 的一个提示:确保 type 属性的值不是“包装的”。它应该是(全部)在一行上…….NET Framework 对此非常挑剔。
  • 第三,请确保使用与您的强命名 Elmah.dll 相对应的 VersionPublicKeyToken。还记得我们在步骤 3 结束时,将公钥令牌值复制到文本文件了吗?您将把该值粘贴到您 web.config 中每个 ELMAH 元素的 PublicKeyToken 部分。上面示例中您看到的是我为示例生成的唯一一个。

步骤 5 - 修改测试 Web 应用程序项目及其 web.config 以便您可以接收来自 ELMAH 的电子邮件

如上所述,我们将限制来自 ELMAH 的电子邮件消息(如果配置为发送电子邮件,ELMAH 会为它记录的每个异常发送一条新消息),以便负责特定 Web 应用程序的人是错误消息的接收者。他或她不会收到关于其他人 Web 应用程序中发生的错误的邮件。而且,如果您要在单个应用程序的 web.config 中包含任何 ELMAH 部分(例如接收个性化电子邮件),您的项目就需要引用 ELMAH 程序集。

  1. 在项目中添加对 Elmah.dll 的引用
  2. 在解决方案资源管理器中,右键单击“引用”并选择“添加引用”。浏览到您保存 Elmah.dll 副本的位置,该副本的版本与您进行强命名并已放入 GAC 的版本相同。您的引用不需要指向强命名 DLL,但绝对应该指向相同版本号的 Elmah.dll 副本。

  3. 将“复制本地”设置为 False
  4. 现在您已经添加了引用,请从您的引用列表中选择它。在“属性”窗口中,找到“复制本地”条目,然后选择“False”,因为没有必要将此 Elmah.dll 包含在已部署项目的 bin 文件夹中。正如微软在如何显示“添加引用”对话框中的程序集中所述:“如果要使用全局程序集缓存中的程序集,则应将程序集放置到本地文件夹中,然后从该文件夹添加对程序集的引用。如果您不希望将程序集复制到您的项目文件夹中,您可能希望将“复制本地”属性设置为 False。在运行时,应用程序将使用全局程序集缓存中的程序集。

  5. 将一些 ELMAH 部分添加到您的 Web 应用程序的 web.config,如下所示。
<?xml version="1.0"?>
<configuration>
    <configSections>
        <!-- Begin an ELMAH specific section -->
        <sectionGroup name="elmah">
            <section name="errorMail" requirePermission="false" 
               type="Elmah.ErrorMailSectionHandler, Elmah, Version=1.2.13605.0, 
                     Culture=neutral, PublicKeyToken=6235d7ef90b85eg2"/>
        </sectionGroup>
        <!-- End an ELMAH specific section -->    
    </configSections>

    <!-- Begin an ELMAH specific section -->
    <elmah>
        <errorMail
                from="noreply@yourdomain.com"
                to="YouTheDeveloper@yourdomain.com"
                priority="high"
                smtpServer="yourSmtpServer.yourdomain.com" />
    </elmah>
    <!-- End an ELMAH specific section -->

    <system.web>
        <httpModules>
            <!-- Begin an ELMAH specific section -->
            <add name="ErrorMail" 
               type="Elmah.ErrorMailModule, Elmah, Version=1.2.13605.0, 
                     Culture=neutral, PublicKeyToken=6235d7ef90b85eg2"/>
            <!-- End an ELMAH specific section -->
        </httpModules>
        .
        .
        .
</configuration>

上面的代码已换行以避免页面滚动

这对于单个 Web 应用程序的 web.config 来说并不是太多要添加的内容,并且如果您将“Begin/End and ELMAH specific section”注释放在每个部分周围,就可以轻松跟踪 ELMAH 的添加。

步骤 6 - 测试和上线

希望这就是您所需要做的。也希望您首先在测试 Web 服务器上完成了所有这些工作!如果您在应用程序中添加了一些不良代码供 ELMAH 捕获,您将看到它是否对您有效。请参阅官方 ELMAH 网站以了解有关如何查看错误的详细信息。那里的许多文章将有所帮助。我需要根据上面的代码陈述一些假设

  • 如果您已经记录了任何异常,您可以通过在 Web 应用程序文件夹的 URL 末尾键入“/elmah.axd”来查看所有这些异常。也就是说,如果您像上面示例中的那样,在您的 web.config 中使用了 path="elmah.axd"。ELMAH 的优点之一是,服务器上使用此 .NET Framework 版本的​​任何 Web 应用程序,即使是您在使用 ELMAH 之前就已经存在的旧应用程序,并且您从未修改过其 web.config 来提及 ELMAH,它也会记录其未处理的异常。而且,是的,您只需键入“/elmah.axd”,就像上面一样,即使对于那些非 ELMAH 应用程序。由于该 Framework 版本的​​根 web.config 中存在 ELMAH 部分,ELMAH 正在为您做好这一切!
  • 我的示例假设使用 Microsoft SQL Server 作为 ELMAH 记录错误的地点。ELMAH 的文档概述了其他记录错误的方式。
  • 我的 web.config 没有提及您可以在 <customErrors> 元素中设置的默认错误页面。拥有一个默认错误页面是一个非常好的主意,这样当发生未处理的异常时,您的用户就不会看到“死亡蓝屏”(YSOD)页面。ELMAH 的伟大之处在于,即使 Web 用户只看到您在发生错误时重定向用户的无害默认错误页面,它也会通过电子邮件将 YSOD 页面的副本发送给
© . All rights reserved.