Quote for the Week

"Learn to enjoy every moment of your life"

Tuesday, June 27, 2017

ELMAH Exception Logging Integration in MVC

In this article, Let us see what is ELMAH..

WHAT IS ELMAH?

ELMAH stands for Error Logging Modules And Handlers that provide functionality to logging run time ASP.NET errors.

  •  Enables logging of all unhandled exceptions.
  •  logs all errors in many storages, like - SQL Server, MySQL, Random Access Memory (RAM), SQL Lite, and Oracle.
  • It has functionality to download all errors in CSV file.
  • RSS feed for the last 15 errors
  • Get all error data in JSON or XML format
  • Get all errors to our mailbox
  • Send error log notification to your application
  • Customize the error log by customizing some code.

Implementing into MVC Application

1. Install ELMAH using Nuget package manager into your application.



2.  Configure your web.config with  ELMAH attributes like below:


<?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=.;Initial Catalog=ExceptionLog;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>  
            <authentication mode="None" />  
            <compilation debug="true" targetFramework="4.5.1" />  
            <httpRuntime targetFramework="4.5.1" />  
  
            <!--add this-->  
            <httpHandlers>  
                <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />  
            </httpHandlers>  
  
            <!--add this-->  
            <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>  
            <!--add this-->  
            <handlers>  
                <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />  
            </handlers>  
            <!--add this-->  
            <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" publicKeyToken="31bf3856ad364e35" />  
                    <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
                </dependentAssembly>  
                <dependentAssembly>  
                    <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />  
                    <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
                </dependentAssembly>  
                <dependentAssembly>  
                    <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />  
                    <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
                </dependentAssembly>  
                <dependentAssembly>  
                    <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />  
                    <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.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.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.2.0" newVersion="5.2.2.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="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />  
                    <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.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>  
            </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>  
  
            <!--add this-->  
            <!--. If allowRemoteAccess value is set to 0, then the error log web page can only be viewed locally. If this attribute is set to 1 then the error log web page is enabled for both remote and local visitors.-->  
            <security allowRemoteAccess="0" />  
            <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />  
            <!--add this-->  
        </elmah>  
  
    </configuration>  


3. Now, Let us create a table to log the errors :

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  
  
)  


Create below Stored Procedures :

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  
  
)  


That's it, Now your application is ready to track run time errors or exception by your site.

www.<sitename>.com/elmah.axd


No comments: