Exception Logging In MVC Using Elmah

What is Elmah

According to Scott Mitchell, Error Logging Modules And Handlers (ELMAH) offers another approach to log runtime errors in a production environment. ELMAH is a free, open source error logging library that includes features like error filtering and the ability to view the error log from a web page, as an RSS feed, or to download it as a comma-delimited file.

What we will achieve through Elmah

  • Logging of nearly all unhandled exceptions.

  • Email notification of each error at the time error occurs.

  • View the error log from a web page.

  • RSS feed .

Step 1: Create a MVC web Application

Open Visual Studio create new project or press CTRL +SHIFT +N. Go to Web tab, select ASP.NET Web Application template. Give name as MVCExceptionLog as in the following screenshot,
 



Step 2: Add Elmah Package from Nuget,

Right click on project solution go to Manage NuGetPackages for Solution, click on it and search elmah and install it,

 

 
Step 3: Now open web config file and add the following code inside <system.web> </system.web>,

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

Also, add the following code inside <system.webServer></system.webServer>,

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

Step 4:  Create table and Stored Procedure,

Here I am using SQL Server database to log the exception.  I have already created database SQL Server named ExceptionLog. Open SQL Server Management Studio, run the following code in ExceptionLog database one by one.

For Table

  1. CREATE TABLE[dbo].[ELMAH_Error]  
  2. (  
  3.   
  4.     [ErrorId][uniqueidentifier] NOT NULL,  
  5.   
  6.     [Application][nvarchar](60) NOT NULL,  
  7.   
  8.     [Host][nvarchar](50) NOT NULL,  
  9.   
  10.     [Type][nvarchar](100) NOT NULL,  
  11.   
  12.     [Source][nvarchar](60) NOT NULL,  
  13.   
  14.     [Message][nvarchar](500) NOT NULL,  
  15.   
  16.     [User][nvarchar](50) NOT NULL,  
  17.   
  18.     [StatusCode][intNOT NULL,  
  19.   
  20.     [TimeUtc][datetime] NOT NULL,  
  21.   
  22.     [Sequence][int] IDENTITY(1, 1) NOT NULL,  
  23.   
  24.     [AllXml][ntext] NOT NULL  
  25.   
  26. )  

Stored procedure

    1. Create PROCEDURE[dbo].[ELMAH_GetErrorsXml]  
    2.   
    3. (  
    4.     @Application NVARCHAR(60),  
    5.     @PageIndex INT = 0,  
    6.     @PageSize INT = 15,  
    7.     @TotalCount INT OUTPUT  
    8.   
    9. )  
    10.   
    11. AS  
    12.   
    13. SET NOCOUNT ON  
    14.   
    15. DECLARE @FirstTimeUTC DATETIME  
    16. DECLARE @FirstSequence INT  
    17. DECLARE @StartRow INT  
    18. DECLARE @StartRowIndex INT  
    19. SELECT  
    20.   
    21. @TotalCount = COUNT(1)  
    22.   
    23. FROM  
    24.   
    25.     [ELMAH_Error]  
    26.   
    27. WHERE  
    28.   
    29.     [Application] = @Application  
    30. SET @StartRowIndex = @PageIndex * @PageSize + 1  
    31. IF @StartRowIndex <= @TotalCount  
    32.   
    33. BEGIN  
    34.   
    35. SET ROWCOUNT @StartRowIndex  
    36.   
    37. SELECT  
    38.   
    39. @FirstTimeUTC = [TimeUtc],  
    40.   
    41.     @FirstSequence = [Sequence]  
    42.   
    43. FROM  
    44.   
    45.     [ELMAH_Error]  
    46.   
    47. WHERE  
    48.   
    49.     [Application] = @Application  
    50.   
    51. ORDER BY  
    52.   
    53.     [TimeUtc] DESC,  
    54.     [SequenceDESC  
    55.   
    56. END  
    57.   
    58. ELSE  
    59.   
    60. BEGIN  
    61.   
    62. SET @PageSize = 0  
    63.   
    64. END  
    65.   
    66. SET ROWCOUNT @PageSize  
    67.   
    68. SELECT  
    69.   
    70. errorId = [ErrorId],  
    71.   
    72.     application = [Application],  
    73.     host = [Host],  
    74.     type = [Type],  
    75.     source = [Source],  
    76.     message = [Message],  
    77.     [user] = [User],  
    78.     statusCode = [StatusCode],  
    79.     time = CONVERT(VARCHAR(50), [TimeUtc], 126) + 'Z'  
    80.   
    81. FROM  
    82.   
    83.     [ELMAH_Error] error  
    84.   
    85. WHERE  
    86.   
    87.     [Application] = @Application  
    88.   
    89. AND  
    90.   
    91.     [TimeUtc] <= @FirstTimeUTC  
    92.   
    93. AND  
    94.   
    95.     [Sequence] <= @FirstSequence  
    96.   
    97. ORDER BY  
    98.   
    99.     [TimeUtc] DESC,  
    100.   
    101.     [SequenceDESC  
    102.   
    103. FOR  
    104.   
    105. XML AUTO  

    1. Create PROCEDURE[dbo].[ELMAH_GetErrorXml]  
    2.   
    3. (  
    4.   
    5.     @Application NVARCHAR(60),  
    6.     @ErrorId UNIQUEIDENTIFIER  
    7.   
    8. )  
    9.   
    10. AS  
    11.   
    12. SET NOCOUNT ON  
    13. SELECT  
    14.   
    15.     [AllXml]  
    16. FROM  
    17.   
    18.     [ELMAH_Error]  
    19. WHERE  
    20.   
    21.     [ErrorId] = @ErrorId  
    22. AND  
    23.     [Application] = @Application  

    1. Create PROCEDURE[dbo].[ELMAH_LogError]  
    2.   
    3. (  
    4.   
    5.     @ErrorId UNIQUEIDENTIFIER,    
    6.     @Application NVARCHAR(60),    
    7.     @Host NVARCHAR(30),    
    8.     @Type NVARCHAR(100),  
    9.     @Source NVARCHAR(60),    
    10.     @Message NVARCHAR(500),  
    11.     @User NVARCHAR(50),   
    12.     @AllXml NTEXT,    
    13.     @StatusCode INT  
    14.     @TimeUtc DATETIME  
    15.   
    16. )  
    17.   
    18. AS  
    19.   
    20. SET NOCOUNT ON  
    21.   
    22. INSERT  
    23.   
    24. INTO  
    25.   
    26.     [ELMAH_Error]
    27. (  
    28.   
    29.     [ErrorId],   
    30.     [Application],   
    31.     [Host],  
    32.     [Type],  
    33.     [Source],  
    34.     [Message],    
    35.     [User],    
    36.     [AllXml],    
    37.     [StatusCode],    
    38.     [TimeUtc]  
    39.   
    40. )  
    41.   
    42. VALUES  
    43.   
    44.     (  
    45.   
    46.     @ErrorId,  
    47.     @Application,    
    48.     @Host,    
    49.     @Type,    
    50.     @Source,   
    51.     @Message,    
    52.     @User  
    53.     @AllXml,   
    54.     @StatusCode,   
    55.     @TimeUtc  
    56.   
    57. )  

After creating the database table and stored procedure. The schema will look like the following:


Now again  open web config file, add the following code inside in <configuration>, 
  1. </configuration>  
  2. <elmah>  
  3.     <!--. 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.-->  
  4.     <!--add this-->  
  5.     <security allowRemoteAccess="0" />  
  6.     <!--  DefaultConnection is the name of database connection string -->  
  7.     <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />  
  8.     <!--add this-->  
  9. </elmah>  
Now my final webconfig file look like the following, 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.     <!--  
  3. For more information on how to configure your ASP.NET application, please visit  
  4. http://go.microsoft.com/fwlink/?LinkId=301880  
  5. -->  
  6.     <configuration>  
  7.         <configSections>  
  8.             <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->  
  9.             <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />  
  10.             <sectionGroup name="elmah">  
  11.                 <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />  
  12.                 <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />  
  13.                 <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />  
  14.                 <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />  
  15.             </sectionGroup>  
  16.         </configSections>  
  17.         <connectionStrings>  
  18.             <add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=ExceptionLog;Integrated Security=True" providerName="System.Data.SqlClient" />  
  19.         </connectionStrings>  
  20.         <appSettings>  
  21.             <add key="webpages:Version" value="3.0.0.0" />  
  22.             <add key="webpages:Enabled" value="false" />  
  23.             <add key="ClientValidationEnabled" value="true" />  
  24.             <add key="UnobtrusiveJavaScriptEnabled" value="true" />  
  25.             <add key="elmah.mvc.disableHandler" value="false" />  
  26.             <add key="elmah.mvc.disableHandleErrorFilter" value="false" />  
  27.             <add key="elmah.mvc.requiresAuthentication" value="false" />  
  28.             <add key="elmah.mvc.IgnoreDefaultRoute" value="false" />  
  29.             <add key="elmah.mvc.allowedRoles" value="*" />  
  30.             <add key="elmah.mvc.allowedUsers" value="*" />  
  31.             <add key="elmah.mvc.route" value="elmah" />  
  32.             <add key="elmah.mvc.UserAuthCaseSensitive" value="true" />  
  33.         </appSettings>  
  34.         <system.web>  
  35.             <authentication mode="None" />  
  36.             <compilation debug="true" targetFramework="4.5.1" />  
  37.             <httpRuntime targetFramework="4.5.1" />  
  38.   
  39.             <!--add this-->  
  40.             <httpHandlers>  
  41.                 <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />  
  42.             </httpHandlers>  
  43.   
  44.             <!--add this-->  
  45.             <httpModules>  
  46.                 <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />  
  47.                 <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />  
  48.                 <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />  
  49.             </httpModules>  
  50.         </system.web>  
  51.         <system.webServer>  
  52.             <!--add this-->  
  53.             <handlers>  
  54.                 <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />  
  55.             </handlers>  
  56.             <!--add this-->  
  57.             <modules>  
  58.                 <remove name="FormsAuthentication" />  
  59.                 <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />  
  60.                 <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />  
  61.                 <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />  
  62.             </modules>  
  63.             <validation validateIntegratedModeConfiguration="false" />  
  64.   
  65.         </system.webServer>  
  66.         <runtime>  
  67.             <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">  
  68.                 <dependentAssembly>  
  69.                     <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" />  
  70.                     <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
  71.                 </dependentAssembly>  
  72.                 <dependentAssembly>  
  73.                     <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />  
  74.                     <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
  75.                 </dependentAssembly>  
  76.                 <dependentAssembly>  
  77.                     <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" />  
  78.                     <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
  79.                 </dependentAssembly>  
  80.                 <dependentAssembly>  
  81.                     <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" />  
  82.                     <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
  83.                 </dependentAssembly>  
  84.                 <dependentAssembly>  
  85.                     <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />  
  86.                     <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />  
  87.                 </dependentAssembly>  
  88.                 <dependentAssembly>  
  89.                     <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />  
  90.                     <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
  91.                 </dependentAssembly>  
  92.                 <dependentAssembly>  
  93.                     <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />  
  94.                     <bindingRedirect oldVersion="0.0.0.0-5.2.2.0" newVersion="5.2.2.0" />  
  95.                 </dependentAssembly>  
  96.                 <dependentAssembly>  
  97.                     <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />  
  98.                     <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />  
  99.                 </dependentAssembly>  
  100.                 <dependentAssembly>  
  101.                     <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />  
  102.                     <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />  
  103.                 </dependentAssembly>  
  104.                 <dependentAssembly>  
  105.                     <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />  
  106.                     <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />  
  107.                 </dependentAssembly>  
  108.             </assemblyBinding>  
  109.         </runtime>  
  110.         <entityFramework>  
  111.             <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">  
  112.                 <parameters>  
  113.                     <parameter value="mssqllocaldb" />  
  114.                 </parameters>  
  115.             </defaultConnectionFactory>  
  116.             <providers>  
  117.                 <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />  
  118.             </providers>  
  119.         </entityFramework>  
  120.         <elmah>  
  121.   
  122.             <!--add this-->  
  123.             <!--. 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.-->  
  124.             <security allowRemoteAccess="0" />  
  125.             <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />  
  126.             <!--add this-->  
  127.         </elmah>  
  128.   
  129.     </configuration>  
Step 5: Let us create some exception
  1. Suppose I want to open a page that are not in our application. Let us say About2 page: localhost:55776/Home/About2
  2. Create divide by zero exception in contact page
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. namespace MVCExceptionLog.Controllers  
  7. {  
  8.     public class HomeController: Controller  
  9.     {  
  10.         public ActionResult Index()  
  11.         {  
  12.             return View();  
  13.         }  
  14.         public ActionResult About()  
  15.         {  
  16.             ViewBag.Message = "Your application description page.";  
  17.             return View();  
  18.         }  
  19.         public ActionResult Contact()  
  20.         {  
  21.             int a = 0;  
  22.             int b;  
  23.             b = 1 / a;  
  24.             ViewBag.Message = "Your contact page.";  
  25.             return View();  
  26.         }  
  27.     }  
  28. }  

 
Step 5: Run the application,

Click on F5 and register a user.
 


Step 6: View the Error Log from a Web Page,

You can view the error log web page through the url localhost:portno/elmah.axd like, localhost:55776/elmah.axd.
 

Check the error log in database.
 
 
Point of Interest

In this article we learned how to log Exception in SQL Server and  view error log details from web page.


Similar Articles