Exception logging using Elmah - Error Logging Modules and Handlers for ASP.NET

Exception logging in ASP.NET applciation

Exception logging is one of the most important part of application maintenance. There are many open source logger application which we can use in our application to log exception details into a central repository,  send exception notification to specific peoples. Elmah -  Error Logging Modules and Handlers is one of those. For details about Elmah please visit here and details how to use it please visit here.

In this article I would also do the same thing i.e. discuss about, How to use Elmah in Asp.Net application. Before I start we need to do some ground work for instance download the source code of Elmah from here. Then I created a database named Elmah_Errorlog into the MS SQL Server for this instance I use SQL 2008. Thats all for the database for now we will create the Table and Stored Procedure later on. I unzipped the Elmah source code and open the solution via Visual Studio. after opening the Elmah via Visual Studio, there is a file named  SQLServer.sql , open this file and from this file I copied  following table and stored procedure creation sql code and run into the Sql server query window to create table and stored procedure for Elmah_Errorlog database.

CREATE TABLE [dbo].[ELMAH_Error](........)
CREATE PROCEDURE [dbo].[ELMAH_GetErrorXml](.........)
CREATE PROCEDURE [dbo].[ELMAH_GetErrorsXml](.......)
CREATE PROCEDURE [dbo].[ELMAH_LogError](........)
so after creating the database, the schema will show like below,


Fig: Elmah_Errorlog database schema and details

So I have created my database for Elmah, now I am going to create Test Harness project to show how to use Elmah to log error. In Elmah solution I created a Web project named Elmah-TestHarness, this is a simple Asp.Net web application with only Default.aspx page. I added Elmah project as reference to this test harness to consume Elmah.dll. 

The most important thing to do is modify the Web.Config file of the Elmah-TestHarness web project to use Elmah. The contents of the web.config is as below,

<?xml version="1.0"?>
<configuration>
  <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>
  </configSections>
  <connectionStrings>
    <add name="elmah-express" connectionString="Server=xxxxx-PC\SQLEXPRESS08;  Database=Elmah_Errorlog;Trusted_Connection=Yes;" />
  </connectionStrings>
  <elmah>
    <errorLog type="Elmah.SqlErrorLog, Elmah"
             connectionStringName="elmah-express" />
    <errorFilter>
      <test>
        <equal binding="HttpStatusCode" value="404" valueType="Int32" />
      </test>
    </errorFilter>
  </elmah>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpHandlers>
      <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
    </httpHandlers>
    <httpModules>
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
    </httpModules>
  </system.web>
</configuration>

and the contents of the Default.aspx file is below,

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Elmah_TestHarness._Default" %>
<html>
<head>
    <title>Elmah - Test Harness</title>
</head>
<body>
    <form id="frmMain" runat="server">
    <h1>
        Elmah Test Harness</h1>
    <fieldset>
        <legend>Elmah Test harness controls</legend>
        <asp:Button ID="btnTest" runat="server" OnClick="btnTest_Click" Text="Exception Test" />
    </fieldset>
    </form>
</body>
</html>

The code behind of the Default.aspx page is as below,
namespace Elmah_TestHarness
{
    using System;
 
    public partial class _Default : System.Web.UI.Page
    {
        protected void btnTest_Click(object sender, EventArgs e)
        {
            throw new Exception("test");
        }
    }
}

So now everything is ready to go, so click on the F5 (make sure Elmah_TestHarness project has been set as Startup app in the solution) and I see following output,


Fig: Elmah Test Harness.

Click on the Exception Test button will throw a exception and Elmah from the behind will catch that and log into the Elmah_Errorlog database. Elmah also expose a HttpHandler which is for to see the exception details. another tab of Chrome write the below URL localhost:28350/Elmah.asxd then it will show up as below,



Fig: Elmah Http Handler output.

On my next exception related article I will discuss about central error logging for applications using WCF.

Source code of the above article is here.

thanks mohammad.

 Few C# and Application Design books from Amazon,

Objects(same type) Deep comparison using C#

There are many situation like we need to compare objects for example, int a =7 and int b=9 so it is easy to compare like, if ( a > b) or if (a< b) or if (a ==b). But if the situation comes like


Person firstPerson = new Person { Name = "Person A", Address = "Person A's Address", IsResidence=YesNo.Yes };
Person secondPerson = new Person { Name = "Person B", Address = "Person B's Address", IsResidence = YesNo.Yes };


and we need to compare those two objects named firstPerson and secondPerson whether they are same or not. This comparison means, each of the property of the object's value has to be compare against the other one. I wrote a small program to do basic Value types comparison of  two given objects.


I wrote a class named ObjectsCompare with following code,

namespace DeepComparer
{
    using System.Reflection;
 
    public class ObjectsCompare
    {
        public bool IsEqual(object firstObject, object secondObject)
        {
            bool result = default(bool);
            foreach (PropertyInfo firstObjectPropertyInfo in firstObject.GetType().GetProperties())
            {
                foreach (PropertyInfo secondObjectPropertyInfo in secondObject.GetType().GetProperties())
                {
                    if (firstObjectPropertyInfo.Name == secondObjectPropertyInfo.Name)
                    {
                        result = firstObjectPropertyInfo.GetValue(firstObject, null).ToString() == secondObjectPropertyInfo.GetValue(secondObject, null).ToString();
                        if (!result) break;
                    }
                }
                if (!result) break;
            }
            return result;
        }
    }
}


The Test harness of the above code is as below,

namespace TestHarness
{
    using System;
    using DeepComparer;
    class Program
    {
        static void Main(string[] args)
        {
            ObjectsCompare comparer = new ObjectsCompare();
            Person firstPerson = new Person { Name = "Person A", Address = "Person A's Address", IsResidence=YesNo.Yes };
            Person firstPersonClone = firstPerson;
            Person secondPerson = new Person { Name = "Person B", Address = "Person B's Address", IsResidence = YesNo.Yes };
            Person secondPersonClone = secondPerson;
 
            if (comparer.IsEqual(firstPerson, secondPerson))
                Console.WriteLine("{0}""same");
            else
                Console.WriteLine("{0}""not same");
 
            if (comparer.IsEqual(firstPerson, firstPersonClone))
                Console.WriteLine("{0}""same");
            else
                Console.WriteLine("{0}""not same");
        }
    }
 
    public enum YesNo 
    {
        Yes=0,
        No
    }
    public class Person
    {
        public string Name { getset; }
        public string Address { getset; }
        public YesNo IsResidence { getset; }
    }
}

The out put of the above code is as below,

not same
same
Press any key to continue . . .
Thanks mohammad.

Abstract Factory and Proxy design patterns

Abstract Factory

I have many individual types and those types will be used by some other types. For the consumer types, it has to know about all the individual types, so instead of doing this, we can create a medium by which consumer can access all the individual types. For example, I have typeA, typeB and typeC, so instead of consumer create objects of all those types, if we used Abstract Factory pattern then we can used a new factory types with facility like CreateTypeA(),  CreateTypeB(), CreateTypeC() method which will return relevant objects. For details we will go through the example below,

Following class diagram will give the picture of the abstract factory pattern example project.


Fig: Abstract Factory Pattern class diagram.

and the project structure in Visual studio,



Fig: Project structure of the Abstract Factory design pattern.
Source code of the projects:

Factory class of AbstractFactory project - this class exposes two methods to the consumers.

namespace AbstractFacotry
{
    using BaseClassDefinition;
    using BaseClassImplementation;
 
    public class Factory
    {
        public ProductABaseClass CreateProductA()
        {
            return new ProductA();
        }
        public ProductBBaseClass CreateProductB()
        {
            return new ProductB();
        }
    }
}


ProductABaseClass and ProductBBaseClass of BaseClassDefinition - following classes define the definition of the concrete class.

namespace BaseClassDefinition
{

    public abstract class ProductABaseClass
    {
        public abstract int GetProductAPrice();
    }
}
namespace BaseClassDefinition
{
    public abstract class ProductBBaseClass
    {
        public abstract int GetProductBPrice();
    }
}


ProductA and ProductB of BaseClassImplementation project - ProductA and ProductB class is the implementation of the BaseClassImplementation.

namespace BaseClassImplementation
{
    using BaseClassDefinition;
    public class ProductA : ProductABaseClass
    {
 
        public override int GetProductAPrice()
        {
            return 1;
        }
    }
}

namespace BaseClassImplementation
{
    using BaseClassDefinition;
    public class ProductB : ProductBBaseClass
    {
        public override int GetProductBPrice()
        {
            return 2;
        }
    }
}


Program class of TestHarness project - this test harness will use the Factory class to instantiate the concrete classes for example in ProductA and ProductB via Factory class.

namespace TestHarness
{
    using System;
    using AbstractFacotry;
    using BaseClassDefinition;
 
    class Program
    {
        static void Main(string[] args)
        {
            ProductABaseClass childOneOfBaseClass = new Factory().CreateProductA();
            ProductBBaseClass childTwoOfBaseClass = new Factory().CreateProductB();
 
            Console.WriteLine("{0}", childOneOfBaseClass.GetProductAPrice());
            Console.WriteLine("{0}", childTwoOfBaseClass.GetProductBPrice());
        }
    }
}
 

Output of the above Test Harness program is as below,

1
2
Press any key to continue . . .


Proxy Pattern

It provides a way to access real object via another types. If we see the Service References of WCF application then we will find a real example of Proxy Pattern. 

See the below class diagram for Proxy Pattern project,


Fig: Class diagram of Proxy pattern project.
and  project structure of the proxy pattern



Fig: Project structure of the Proxy Pattern
AbstractProduct class of ProxyPattern-BaseClassDefiition project - base type of all the children.

namespace ProxyPattern_BaseClassDefinition
{
    public abstract class AbstractProduct
    {
        public abstract string GetProductName();
    }
}


ProductA class of ProxyPattern-BaseClassImplementation - Implementation of base class.

namespace ProxyPattern_BaseClassImplementation
{
    using ProxyPattern_BaseClassDefinition;
    public class ProductA : AbstractProduct
    {
        public override string GetProductName()
        {
            return "Product A";
        }
    }
}


Proxy_ProductA class of ProxyPattern-Proxy project - a proxy of ProductA class.

namespace ProxyPattern_Proxy
{
    using ProxyPattern_BaseClassDefinition;
    using ProxyPattern_BaseClassImplementation;
    public class Proxy_ProductA : AbstractProduct
    {
        private ProductA productA;
        public override string GetProductName()
        {
            if (productA == null)
                productA = new ProductA();
            return productA.GetProductName();
        }
    }
}


Program class of ProxyPattern-TestHarness where I use Proxy class Proxy_ProductA to access the real object which is ProductA.

namespace ProxyPattern_TestHarness
{
    using System;
    using ProxyPattern_Proxy;
    class Program
    {
        static void Main(string[] args)
        {
            Proxy_ProductA proxy = new Proxy_ProductA();
            Console.WriteLine("{0}", proxy.GetProductName());
        }
    }
}


The output of the Test harness is as below,

Product A
Press any key to continue . . .


Note:

always happy to learn from others and happy to get new ideas. thanks. mohammad

 Few C# and Application Design books from Amazon,

Lambda Expression in C#

I think most of .Net coder is familiar with Lambda expression. So it is basically a way to write anonymous function. According to the syntax Lambda expression can take Input and based on the Input and expression it will produce the output. The syntax of the Lambda expression is

(input parameters) => expression or statements.

For example if I have a method with the following body

int Add( int a, int b ){
      return a+b;
}
to
(a,b)=>{ return a+b; } with the contract Func<int, int>. So it will be like below,
Func<int, int> add = (a,b)=>{return a+b;}


There are lots of interesting thing about Lambda expression and Extension methods. In this article I discuss about few stuffs about Lambda and Func then do something with the Extension methods Select and Where of IEnumerable class.

The example of I am to use in this article will have basic lambda and Func along with these there will be IEnumerable class with Select and Where extension methods. In the example Program class will have few basic things about Lambda and Calculator class has few other stuff. I include the code in one chunk.

namespace TestHarness
{
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Collections;
    class Program
    {
        static void Main(string[] args)
        {
            Action<int> printer = (x) => Console.Write("{0}\t", x);
 
            Func<intintint> funcAdd = (x1, x2) => { return (x1 + x2); };
            Func<intintint> funcAddExtraLogic =
                (x1, x2) =>
                {
                    if (x1 > x2)
                        x1 = x1 * 2;
                    else
                        x2 = x2 * 2;
                    return (x1 + x2);
                };
 
            Console.WriteLine("Lamda expression test: \t{0}", funcAdd(4, 4));
            Console.WriteLine("Lambda expression test:\t{0}", funcAddExtraLogic(4, 4));
 
            Calculator calculator = new Calculator();
            Console.WriteLine("{0}", calculator.Add(4, 4));
            Console.WriteLine("{0}", calculator.Add(calculator.AddImplementator(), 4, 4));
            Console.WriteLine("{0}", calculator.AddImplementator()(4, 4));
 
            Console.WriteLine("Get the list:");
            Console.WriteLine("Using Lambda exrepession.");
            calculator.GetResultUsingExpression().ToList<int>().ForEach(printer);
            Console.WriteLine("Using Lambda exrepession with Func method.");
            calculator.GetResult().ToList<int>().ForEach(printer);
            Console.WriteLine("Using Lambda exrepession with inline delegate implementation");
            calculator.GetResult(x => { return x % 2 == 0; }, x => { return x; }).ToList<int>().ForEach(printer);
 
        }
    }
    public class Calculator
    {
        Func<intintint> mFuncAdd = (x1, x2) => { return (x1 + x2); };
 
        public int Add(int a, int b)
        {
            return mFuncAdd(a, b);
        }
        public int Add(Func<intintint> funcAdd, int a, int b)
        {
            return funcAdd(a, b);
        }
 
        public Func<intintint> AddImplementator()
        {
            return (a, b) =>
            {
                return a + b;
            };
        }
 
        public IEnumerable<int> GetResultUsingExpression()
        {
            int u = 40;
            IEnumerable<int> result = Enumerable
                .Range(0, 100)
                .Where(x => x % 2 == 0 && x > u)
                .Select((x) => x * 2);
            return result;
        }
 
        public IEnumerable<int> GetResult()
        {
            int u = 40;
            IEnumerable<int> result = Enumerable
                .Range(0, 100)
                .Where(x => Check()(x, u))
                .Select((x) => SelectCondition()(x));
            return result;
        }
 
        public IEnumerable<int> GetResult(Func<intbool> checker, Func<intint> selector)
        {
            IEnumerable<int> result = Enumerable
                .Range(0, 100)
                .Where(x => checker(x))
                .Select((x) => selector(x));
            return result;
        }
 
        private Func<intintbool> Check()
        {
            return (int a, int u) =>
            {
                return a % 2 == 0 && a > u;
            };
        }
 
        private Func<intint> SelectCondition()
        {
            return (a) =>
            {
                return a * 2;
            };
        }
    }
}



In the above code I create a delegate Func<int, int,int> funcAdd and  this (x1,x2)=>{return (x1+x2);} anonymous method using Lambda expression. and there is also another delegate named funcAddExtraLogic. I created this one to show how can I use multiple statements.


In the Calculator class I implement few methods to manipulate a list to show the usage of Where and Select extension methods. Where and Select methods have the following signature,

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,Func<TSource, bool> predicate)

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source,Func<TSource, TResult> selector)


Following methods manipulate the list using Where and Select. As the signature shows it is extension methods of the IEnumerable and as well it accept a Func with TSource as input parameter and bool as output parameter. From the beginning of this article I showed Func is a  anonymous function, so it uses x=>x%2==0 &&x>u.
public IEnumerable<int> GetResultUsingExpression()
        {
            int u = 40;
            IEnumerable<int> result = Enumerable
                .Range(0, 100)
                .Where(x => x % 2 == 0 && x > u)
                .Select((x) => x * 2);
            return result;
        }



on the other hand as Where accept a Func<int, bool> delegate so I implement a method with return type Func<int, bool> and then use that for Where. So the code is as below,

public IEnumerable<int> GetResult()
        {
            int u = 40;
            IEnumerable<int> result = Enumerable
                .Range(0, 100)
                .Where(x => Check()(x, u))
                .Select((x) => SelectCondition()(x));
            return result;
        }


private Func<intintbool> Check()
        {
            return (int a, int u) =>
            {
                return a % 2 == 0 && a > u;
            };
        }




The output of the example is as below,

Lamda expression test:  8
Lambda expression test: 12
8
8
8
Get the list:
Using Lambda exrepession.
84      88      92      96      100     104     108     112     116     120
124     128     132     136     140     144     148     152     156     160
164     168     172     176     180     184     188     192     196     Using La
mbda exrepession with Func method.
84      88      92      96      100     104     108     112     116     120
124     128     132     136     140     144     148     152     156     160
164     168     172     176     180     184     188     192     196     Using La
mbda exrepession with inline delegate implementation
0       2       4       6       8       10      12      14      16      18
20      22      24      26      28      30      32      34      36      38
40      42      44      46      48      50      52      54      56      58
60      62      64      66      68      70      72      74      76      78
80      82      84      86      88      90      92      94      96      98
Press any key to continue . . .


happy to learn from others.

Thanks
mohammad