گزارش گیری خطاها با استفاده از Elmah در MVC

در این مقاله قصد داریم نحوه استفاده از Elmah را به همراه یک نمونه شرح دهیم . Elmah یک کتابخانه رایگان است که برای ارائه گزارش از خطاهای وب سایتی که نوشته اید به شما کمک می کند .

گزارش گیری خطاها با استفاده از Elmah در MVC

Elmah خطاهای رخ داده در برنامه شما را گزارش می گیرد.کار با Elmah بسیار ساده است .باید آن را به طریقی به برنامه اضافه کنید .روش های مختلفی برای افزودن آن به برنامه وجود دارد که یکی از این روش ها می تواند افزودن Dll آن از پروژه ای دیگر باشد و یا اینکه از طریق NUGET آن را به برنامه خود اضافه کنید .

به هر حال پس از افزودن آن به پروژه ، فقط کافی است تا تغییرات کمی در Web.config بدهید .پس از راه اندازی Elmah می توانید از طریق آدرس Domain خود و سپس افزودن /Elmah.axd به صفحه ای بروید که خطا ها در آن نمایش داده می شود . Elmah این قابلیت را  هم دارد که خطاها را برای شما ایمیل کند .

حال برای شروع کار ابتدا یک پروژه از نوع Asp.net MVC ایجاد می کنیم .

نوع این نمونه از نوع mvc است

بعد از ایجاد نمونه باید از طریق nugget امکان Elmah  را اضافه کنیم .

حال در داخل web.config تغییرات زیر را در قسمت <system.web> </system.web> اعمال می کنیم .

    <!--add this-->  
        < httpHandlers >  
        < add verb = "POST,GET,HEAD"path = "elmah.axd"type = "Elmah.ErrorLogPageFactory, Elmah" / >  
        < /httpHandlers>  
    <!--add this-->  

و همچنین در قسمت <system.webServer></system.webServer> تغییرات زیر را انجام می دهیم

    <!--add this-->  
        < handlers >  
        < add name = "Elmah"verb = "POST,GET,HEAD"path = "elmah.axd"type = "Elmah.ErrorLogPageFactory, Elmah" / >  
        < /handlers>  
    <!--add this-->  

بعد از افزودن Elmah و اعمال برخی تغییرات در داخل web.congig لازم است که در دیتابیس به ساخت جدولی بپردازیم که خطاها در آن ذخیره شود .

اسکریپت ساخت جدول به صورت زیر است

CREATE TABLE[dbo].[ELMAH_Error]  
(  
  
    [ErrorId][uniqueidentifier] NOT NULL,  
  
    [Application][nvarchar](60) NOT NULL,  
  
    [Host][nvarchar](50) NOT NULL,  
  
    [Type][nvarchar](100) NOT NULL,  
  
    [Source][nvarchar](60) NOT NULL,  
  
    [Message][nvarchar](500) NOT NULL,  
  
    [User][nvarchar](50) NOT NULL,  
  
    [StatusCode][int] NOT NULL,  
  
    [TimeUtc][datetime] NOT NULL,  
  
    [Sequence][int] IDENTITY(1, 1) NOT NULL,  
  
    [AllXml][ntext] NOT NULL  
  
) 

برای ذخیره اطلاعات در داخل این جدول روال هایی نوشته شده اند که در زیر می بینید

روال ذخیره شده و یا Stored Procedure مربوط به گرفتن همه خطا ها به صورت زیر است

    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  
    SELECT  
      
    @TotalCount = COUNT(1)  
      
    FROM  
      
        [ELMAH_Error]  
      
    WHERE  
      
        [Application] = @Application  
    SET @StartRowIndex = @PageIndex * @PageSize + 1  
    IF @StartRowIndex <= @TotalCount  
      
    BEGIN  
      
    SET ROWCOUNT @StartRowIndex  
      
    SELECT  
      
    @FirstTimeUTC = [TimeUtc],  
      
        @FirstSequence = [Sequence]  
      
    FROM  
      
        [ELMAH_Error]  
      
    WHERE  
      
        [Application] = @Application  
      
    ORDER BY  
      
        [TimeUtc] DESC,  
        [Sequence] DESC  
      
    END  
      
    ELSE  
      
    BEGIN  
      
    SET @PageSize = 0  
      
    END  
      
    SET ROWCOUNT @PageSize  
      
    SELECT  
      
    errorId = [ErrorId],  
      
        application = [Application],  
        host = [Host],  
        type = [Type],  
        source = [Source],  
        message = [Message],  
        [user] = [User],  
        statusCode = [StatusCode],  
        time = CONVERT(VARCHAR(50), [TimeUtc], 126) + 'Z'  
      
    FROM  
      
        [ELMAH_Error] error  
      
    WHERE  
      
        [Application] = @Application  
      
    AND  
      
        [TimeUtc] <= @FirstTimeUTC  
      
    AND  
      
        [Sequence] <= @FirstSequence  
      
    ORDER BY  
      
        [TimeUtc] DESC,  
      
        [Sequence] DESC  
      
    FOR  
      
    XML AUTO  

روال ذخیره شده برای دریافت یک خطای خاص به صورت زیر است

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 

و در نهایت روال ذخیره شده در دیتابیس برای ذخیره خطا به صورت زیر است

    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  
      
    )  

بعد از اجرای اسکریپت های بالا شکل دیتابیس ما به صورت زیر خواهد بود

دوباره به فایل web.config برمی گریم و تغییر زیر را هم اعمال می کنیم .

    </configuration>  
    <elmah>  
        <!--. If allowRemoteAccess value is set to 0, then the error log web page can only be viewed locally. If allowRemoteAccess attribute is set to 1 then the error log web page is enabled for both remote and local visitors.-->  
        <!--add this-->  
        <security allowRemoteAccess="0" />  
        <!--  DefaultConnection is the name of database connection string -->  
        <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />  
        <!--add this-->  
    </elmah>  

در داخل تگ Elmah تنظیمات مختلفی مانند اینکه آیا خطاها توسط کاربران راه دور مشاهده شود یا خیر وجود دارد.اینکه خطاها در کجا ذخیره شوند را هم در این تگ مشخص می کنیم .

شکل نهایی فایل web.config به صورت زیر است

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=301880
  -->
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  <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>
  <connectionStrings>
    <!--<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-MVCExceptionLog-20160102095730.mdf;Initial Catalog=aspnet-MVCExceptionLog-20160102095730;Integrated Security=True" providerName="System.Data.SqlClient" />-->
    <add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=ELMAH_Errore;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  <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.IgnoreDefaultRoute" value="false" /><add key="elmah.mvc.allowedRoles" value="*" /><add key="elmah.mvc.allowedUsers" value="*" /><add key="elmah.mvc.route" value="elmah" /><add key="elmah.mvc.UserAuthCaseSensitive" value="true" /></appSettings>
  <system.web>
     <httpHandlers >  
    <add verb = "POST,GET,HEAD" path ="elmah.axd" type ="Elmah.ErrorLogPageFactory, Elmah" />  
    </httpHandlers>  
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules></system.web>
  <system.webServer>
       <handlers >  
    <add name = "Elmah" verb ="POST,GET,HEAD" path ="elmah.axd" type ="Elmah.ErrorLogPageFactory, Elmah" />  
    </handlers>  
    <modules>
      <remove name="FormsAuthentication" />
    <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>
  <validation validateIntegratedModeConfiguration="false" /></system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
<elmah>
   <security allowRemoteAccess="0" />  
    <!--  DefaultConnection is the name of database connection string -->  
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />  
  </elmah>
</configuration>

حال به صورت عمد در داخل کنترلر مربوط به Home و در داخل Action به نام contact یک کد اشتباه می نویسیم تا خطا تولید کند .کد کنترلر به صورت زیر است

  public ActionResult Index()
        {
            return View();
        }
        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";
            return View();
        }
        public ActionResult Contact()
        {
            int a = 0;
            int b;
            b = 1 / a;
            ViewBag.Message = "Your contact page.";
            return View();
        } 

اگر برنامه را با آدرس …../Home/contact اجرا کنید صفحه خطای زیر را خواهید دید

به مسیر …/Account/Register رفته و F5 را فشار دهید تا برنامه در این مسیر اجرا شود

برای دیدن خطاهای رخ داده شده به آدرس Domain/Elmah.axd بروید .همان طور که می بینید کلیه خطاهای کاربران در این صفحه گزارش شده است.اما در صفحه register اگر پسورد را اشتباه وارد کنید همانجا Regular Expression به شما پیغام می دهد و دیگر جزو خطاهای exception نیست که به شما پیغام خطا در داخل elmah بدهد در واقع خطاهای سیستمی گزارش گیری می شوند.

در داخل دیتابیس هم خطاها ذخیره شده است

 

فایل های ضمیمه
دانلود نسخه ی PDF این مطلب