zoukankan      html  css  js  c++  java
  • 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 访问权限问题,在后续文章中阐述。

  • 相关阅读:
    Palindrome Partitioning
    Minimum Path Sum
    Maximum Depth of Binary Tree
    Minimum Depth of Binary Tree
    Unique Binary Search Trees II
    Unique Binary Search Trees
    Merge Intervals
    Merge Sorted Array
    Unique Paths II
    C++ Primer Plus 笔记第九章
  • 原文地址:https://www.cnblogs.com/liquanchun/p/2827724.html
Copyright © 2011-2022 走看看