• Asp.net MVC WebApi 中使用ELMAH


    ELMAH(The Error Logging Modules And Handlers)错误日志模块和处理,它提供了一个用于集中记录和通知错误日志的机制。

    一、添加程序集引用

    打开VS2012新建一个asp.net mvc 4 web应用程序项目。右键项目【管理NuGet程序包】,搜索ELMAH如图:

    注意:要选择“Elmah.MVC”然后安装,第一个“ELMAH”只是在传统的webform中用到的。

    二、配置web.config

    安装完成之后在配置文件中会自动添加一些配置项目:

     <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>

    <appSettings>节中添加

        <add key="elmah.mvc.disableHandler" value="false" />
        <add key="elmah.mvc.disableHandleErrorFilter" value="false" />
        <add key="elmah.mvc.requiresAuthentication" value="false" />
        <add key="elmah.mvc.allowedRoles" value="*" />
        <add key="elmah.mvc.route" value="elmah" />

    <system.web>节中添加

        <httpModules>
          <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
          <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
          <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
        </httpModules>

    <system.webServer>节中添加

        <modules runAllManagedModulesForAllRequests="true">
          <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
          <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
          <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
        </modules>
        <handlers>
          <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
          <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
          <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
          <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
          <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
          <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
        </handlers>

    <elmah>节,注意,这个地方要修改为日志保存方式为 Sql server 数据库,连接字符串为 DefaultConnection,

      <elmah>
        <security allowRemoteAccess="false" />
        <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />
      </elmah>

       <connectionStrings>
        <add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Data Source=(local);Initial Catalog=iCareSer;Integrated Security=True" />
      </connectionStrings>

    手动添加以下代码

      <location path="elmah.axd" inheritInChildApplications="false">
        <system.web>
          <httpHandlers>
            <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
          </httpHandlers>
        </system.web>
        <system.webServer>
          <handlers>
            <add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
          </handlers>
        </system.webServer>
      </location>

    Web.config 修改完毕

    三、配置数据库表

    如果配置为数据库保存日志记录,则需要配置数据库的表和存储过程,代码如下:

    View Code
    /* 错误管理工具 SQL代码             */
    CREATE TABLE dbo.ELMAH_Error
    (
        ErrorId     UNIQUEIDENTIFIER NOT NULL,
        Application NVARCHAR(60) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        Host        NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        Type        NVARCHAR(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        Source      NVARCHAR(60) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        Message     NVARCHAR(500) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        [User]      NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        StatusCode INT NOT NULL,
        TimeUtc     DATETIME NOT NULL,
        Sequence    INT IDENTITY (1, 1) NOT NULL,
        AllXml      NTEXT COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    GO
    /*创建主键 */
    ALTER TABLE dbo.ELMAH_Error WITH NOCHECK ADD
        CONSTRAINT PK_ELMAH_Error PRIMARY KEY NONCLUSTERED
        (
            ErrorId
        ) ON [PRIMARY]
    GO
    /*创建默认约束  */
    ALTER TABLE dbo.ELMAH_Error ADD
        CONSTRAINT DF_ELMAH_Error_ErrorId DEFAULT (newid()) FOR [ErrorId]
    GO
    /*创建非聚集索引  */
    CREATE NONCLUSTERED INDEX IX_ELMAH_Error_App_Time_Seq ON dbo.ELMAH_Error
    (
        [Application] ASC,
        [TimeUtc] DESC,
        [Sequence] DESC
    ) ON [PRIMARY]
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_NULLS ON
    GO
    
    /*创建存储过程,得到单个错误xml */
    CREATE PROCEDURE dbo.ELMAH_GetErrorXml
    (
        @Application NVARCHAR(60),
        @ErrorId UNIQUEIDENTIFIER
    )
    AS
    SET NOCOUNT ON
     SELECT
        AllXml
    FROM
        ELMAH_Error
    WHERE
        ErrorId = @ErrorId
    AND
        Application = @Application
    GO
    
    SET QUOTED_IDENTIFIER OFF
    GO
    SET ANSI_NULLS ON
    GO
    /*创建存储过程,得到错误总记录*/
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_NULLS ON
    GO
    CREATE PROCEDURE dbo.ELMAH_GetErrorsXml
    (
        @Application NVARCHAR(60),
        @PageIndex INT = 0,
        @PageSize INT = 15,
        @TotalCount INT OUTPUT
    )
    AS
    SET NOCOUNT ON
    DECLARE @FirstTimeUTC DateTime
    DECLARE @FirstSequence int
    DECLARE @StartRow int
    DECLARE @StartRowIndex int
    -- Get the ID of the first error for the requested page
    SET @StartRowIndex = @PageIndex * @PageSize + 1
    SET ROWCOUNT @StartRowIndex
    SELECT 
        @FirstTimeUTC = TimeUTC,
        @FirstSequence = Sequence
    FROM
        ELMAH_Error
    WHERE  
        Application = @Application
    ORDER BY
        TimeUTC DESC,
        Sequence DESC
    -- Now set the row count to the requested page size and get
    -- all records below it for the pertaining application.
    SET ROWCOUNT @PageSize
    SELECT
        @TotalCount = COUNT(1)
    FROM
        ELMAH_Error
    WHERE
        Application = @Application
    SELECT
        errorId,
        application,
        host,
        type,
        source,
        message,
        [user],
        statusCode,
        CONVERT(VARCHAR(50), TimeUtc, 126) + 'Z' time
    FROM
        ELMAH_Error error
    WHERE
        Application = @Application
    AND
        TimeUTC <= @FirstTimeUTC
    AND
        Sequence <= @FirstSequence
    ORDER BY
        TimeUTC DESC,
        Sequence DESC
    FOR
        XML AUTO
    GO
    
    SET QUOTED_IDENTIFIER OFF
    
    GO
    
    SET ANSI_NULLS ON
    
    GO
    
    /*存储过程:插入数据 */
    SET QUOTED_IDENTIFIER ON
    GO
    SET ANSI_NULLS ON
    GO
    CREATE PROCEDURE dbo.ELMAH_LogError
    (
        @ErrorId UNIQUEIDENTIFIER,
        @Application NVARCHAR(60),
        @Host NVARCHAR(30),
        @Type NVARCHAR(100),
        @Source NVARCHAR(60),
        @Message NVARCHAR(500),
        @User NVARCHAR(50),
        @AllXml NTEXT,
        @StatusCode INT,
        @TimeUtc DATETIME
    )
    AS
    SET NOCOUNT ON
    INSERT
    INTO
        ELMAH_Error
        (
            ErrorId,
            Application,
            Host,
            Type,
            Source,
            Message,
            [User],
            AllXml,
            StatusCode,
            TimeUtc
        )
    VALUES
        (
            @ErrorId,
            @Application,
            @Host,
            @Type,
            @Source,
            @Message,
            @User,
            @AllXml,
            @StatusCode,
            @TimeUtc
        )
    GO
    SET QUOTED_IDENTIFIER OFF
    GO
    SET ANSI_NULLS ON
    GO

    在DefaultConnection配置的数据库中执行代码。

    四、测试

    1. 运行新建的asp.net mvc4 应用程序项目,正常运行显示页面“

    欢迎使用 ASP.NET Web API!

    修改此模板中的代码以快速开始您的 ASP.NET Web API 开发。

    2.写一段错误的代码,在Controllers里面HomeController.cs 文件中加一段代码

    public ActionResult Index()
    {
      int x = int.Parse("b");
      return View();
    }

    然后执行,肯定会报错,你会看到

    “/”应用程序中的服务器错误。


    输入字符串的格式不正确。

    说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

    异常详细信息: System.FormatException: 输入字符串的格式不正确。

    源错误:

    行 11:         public ActionResult Index()
    行 12:         {
    行 13:                  int x = int.Parse("b");
    行 14:             return View();
    行 15:         }


    源文件: d:\VS2012代码\MvcApplication1\MvcApplication1\Controllers\HomeController.cs    行: 13             

    3. 在地址栏输入 http://localhost:1702/elmah.axd 端口号自己改,会看到以下页面

    OK,成功了!

    4. 还没完,还没有在WebApi中测试呢,打开默认的ValuesController.cs 这是一个ApiController,通常情况下我们是用jquery 异步方式调用ApiController的。

        在ValuesController.cs修改Get()方法,让他发出错误:

            // GET api/values/5
            public string Get(int id)
            {
                int k = 0;
                int i = 2/k;
                return "value";
            }

       然后用javascript 调用这个方法,在View/homn/index.cshtml文件最后加上js代码:

    <div><input type="button" value="测试" onclick="test()" /> </div>
    <script type="text/javascript"> function test() { $.getJSON("api/values/", {id : 2}, function (data) { alert(data); }); } </script>

     然后编译运行,要去掉之前测试HomeController.cs 中的错误代码,要不然运行不了。

    点击“测试”按钮无反应,用firebug查看有错误信息,再在浏览器中 http://localhost:1702/elmah.axd 查看,但是发现没有记录到错误信息,为什么?

    这就是开头说的要添加ELMAH.MVC而不是ELMAH,在WebApi中还要做另外的工作。

    在App_Start文件夹中添加 ElmahErrorAttribute.cs类,代码:

        public class ElmahErrorAttribute :System.Web.Http.Filters.ExceptionFilterAttribute
        {
            public override void OnException(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
            {
                if (actionExecutedContext.Exception != null)
                {
                    Elmah.ErrorSignal.FromCurrentContext().Raise(actionExecutedContext.Exception);
                }
                base.OnException(actionExecutedContext);
            }
        }

    然后在 Global.asax 文件Application_Start方法中添加一句:GlobalConfiguration.Configuration.Filters.Add(new ElmahErrorAttribute());

            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
    
                WebApiConfig.Register(GlobalConfiguration.Configuration);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
                GlobalConfiguration.Configuration.Filters.Add(new ElmahErrorAttribute());
            }

    然后再编译,运行点击“测试”,打开http://localhost:1702/elmah.axd,发现已经记录了错误信息。  

    五、注意事项和待解决问题

    1.如果异常通过catch被捕获了就无法记录了,除非捕获后又throw。也就是在异常链上,最终的异常必须抛给了ASP.NET运行时,才可以被捕获。

    2.ELMAH配置的数据库连接字符串无法加密,或者无法指定为加密了的connectionstring;

    3.日志内容是增长的,但ELMAH没有提供清空日志的功能;

    4.http://localhost:1702/elmah.axd 访问权限问题,在后续文章中阐述。

  • 相关阅读:
    javascript获取url参数的代码
    SharePoint最简母版页
    添加 <identity impersonate="true" userName="username" password="password"/>,解决问题!
    使用SPD自定义MOSS导航
    浮动图标代码
    十五种网站最差的用户体验
    div flash firefox div层总是被flash层遮盖
    压缩数据库扩展名为.ldf的日志文件
    版本的签入签出策略
    用CSS制作的圆角层
  • 原文地址:https://www.cnblogs.com/liquanchun/p/2827724.html
Copyright © 2020-2023  润新知