Shiman’s Weblog

Collecting stones from the sea-shore.

Log4Net Cofiguration

I had to post this one long days ago as I promised in one of my earlier post about Log4Net. Sorry for this late. I am not a man of words. Thanks to Chris, for reminding me about this post. There are lots of things in the configuration of Log4Net. I will only about the commonly used sections.

<log4net>
	<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
		<param name="File" value="D:\Temp\ApplicationLog.log" />
		<param name="AppendToFile" value="true" />
		<layout type="log4net.Layout.PatternLayout">
			<param name="Header" value="" />
			<param name="Footer" value="" />
			<param name="ConversionPattern" value="%d [%t] %-5p %m%n" />
		</layout>
	</appender>
	<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
		<layout type="log4net.Layout.PatternLayout">
			<param name="Header" value="[Header]\r\n" />
			<param name="Footer" value="[Footer]\r\n" />
			<param name="ConversionPattern" value="%d [%t] %-5p %m%n" />
		</layout>
	</appender>
	<root>
		<level value="DEBUG" />
		<appender-ref ref="LogFileAppender" />
		<appender-ref ref="ConsoleAppender" />
	</root>
</log4net>

Log4Net is configured in the configuration section “log4net”, specified with the tag <log4net>. Under this tag, you can find two tags, <appender> and <root>. (There could be more actually. but I did not need them yet.)

<appender> section says where and how the log should be written. It could be in the console, in a file, or database. Logs can even be sent to an email address. So, depending on you needs, you have to configure the appender. Under <log4net> element one or more appenders can be defined. I am interested to describe some of the appenders. Please remind me if I forget to do so.

<root> section is to say, which appender will be used to log, and what types of log will be written.Only one root logger element may only be defined and it must be a child of <log4net> element. To define te log-level, you have to specify your desired log-level in the <level> element. You can set the ‘value’ attribute to any of the five log-levels. The levels are as follows hierarchically:

  1. FATAL
  2. ERROR
  3. WARN
  4. INFO
  5. DEBUG

Once you specify the level of the log in the ‘value’ attribute, logs for that level and the levels above will be written.

November 13, 2008 Posted by shiman | .NET, Computer Science, OOP, Programming, S/W Engineering | , , , , , | No Comments Yet

Why Log4Net?

Microsoft has its own application block for logging. So, why should we use Log4Net instead of that?

Log4Net has some advantages over Enterprise Library Logging Application Block. These made Log4Net more preferable.

Works with .NET 1.0 & 1.1 - The much improved logging of EntLib 2.0 and above is only available if your application is running on .NET 2.0 or greater. log4net however works on all versions of .NET.

Simpler install - When using the Enterprise Library there are some services you really should install. This is as simple as running a bat file included with EntLib but it does complicate your deployment process.

Slightly faster - log4net was significantly quicker than EntLib 1.1 logging. EntLib 2.0 onwards has improved its performance but log4net remains slightly faster. A benchmark I found while researching my presentation had EntLib taking approximately 5-6 seconds to log 100,000 entries while log4net took about 3 seconds. Does the speed difference matter? Probably not. However log4net net does support…

Appender Buffering - Buffering support with some appenders lets log4net queue up log entries and write them in a single go. If you are writing entries to the database then buffering is a good way to improve performance.

More platforms - Enterprise Library does not support the .NET Compact Framework while log4net does.

November 6, 2008 Posted by shiman | Computer Science, Programming, S/W Engineering | , , , , , , , , , | No Comments Yet

Application Exceptions in C# .NET

Application exceptions are custom exceptions and are thrown by the application, not by the CLR. Application exceptions are derived from System.ApplicationException or System.Exception. System.ApplicationException adds nothing to System.Exception. While System.SystemException is a marker for system exceptions, System.ApplicationException brands application exceptions. A custom exception derived from System.Exception accomplishes the same feat. When several custom exceptions are planned, create a custom base exception class to categorize the exceptions. For convenience and maintainability, deploy application exceptions together in a separate assembly.

Do not create an application exception for an existing exception. Research the available system exceptions to avoid replicating an existing exception.

These are the steps for creating an application exception:

  1. Name the application exception. As a best practice, the class name should have the Exception suffix, as in ApplicationException.
  2. Derive the application exception from System.Exception.
  3. Define constructors that initialize the state of the application exception. This includes initializing members inherited from the base class.
  4. Within the application exception, refine System.Exception as desired, such as by adding attributes that further delineate this specific exception.

To raise an application exception, use the throw statement. You can also throw system exceptions. Thrown exceptions are considered software exceptions. The CLR treats software exceptions as standard exceptions.

throw syntax:

throw exceptioninstance1;

throw2; 

The second syntax is specialized: It is available in the catch block, but nowhere else. This version of the throw statement rethrows as an exception caught in the catch block. However, the best policy is to add additional context to an exception before propagating the exception object. Propagating exceptions is reviewed later in this chapter.

Application exceptions are typically prompted by an exceptional event. What is an exceptional event? A strict definition does not exist. You define the basis of the event using whatever criteria are appropriate. Remember, raising an exception simply for transfer of control or a nonexceptional event is bad policy. In an application, the following could be considered exceptional events where throwing an application exception is warranted:

  • Constructor fails to initialize the state of an object.
  • A property does not pass validation.
  • Null parameters.
  • An exceptional value is returned from a function.

ConstructorException is an application exception. Throw this exception when a constructor fails. It refines the System.Exception base class with name of the type and time of exception. In addition, the Message property is assigned a congruous message. This is the code for the ConstructorException class:

using System;

namespace Examples.Exceptions
{
    public class ConstructorException : Exception
    {

        public ConstructorException(object origin) : this(origin, null)
        {
        }

        public ConstructorException(object origin, Exception innerException) : base("Exception in constructor", innerException)
        {
            prop_Typename = origin.GetType().Name;
            prop_Time = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString();
        }

        protected string prop_Typename = null;
        public string Typename
        {
            get
            {
                return prop_Typename;
            }
        }

        protected string prop_Time = null;
        public string Time
        {
            get
            {
                return prop_Time;
            }
        }
    }
}

This code uses the ConstructorException class:

using System;

namespace Examples.Exceptions
{
    public class Program
    {
        public static void Main()
        {
            try
            {
                ZClass obj = new ZClass();
            }
            catch (ConstructorException except)
            {
                Console.WriteLine(except.Message);
                Console.WriteLine("Typename: " + except.Typename);
                Console.WriteLine("Occured: " + except.Time);
            }
            Console.ReadKey();
        }
    }

    class ZClass
    {
        public ZClass()
        {
            // initialization fails
            throw new ConstructorException(this);
        }
    }
}

November 2, 2008 Posted by shiman | C#.Net, Computer Science, OOP, Programming, S/W Engineering | , , , , , , , , , | No Comments Yet

Enumeration in C# .NET : Best Practices

Enumerable objects implement the IEnumerable interface. The GetEnumerator method is the only member of this interface. It returns an enumerator, which is used to enumerate nongeneric collections.

This is the IEnumerable interface:

public interface IEnumerable

{

    IEnumerator GetEnumerator();

}

Each invocation of the GetEnumerator method returns a unique enumerator. The enumerator is a state machine that minimally maintains a snapshot of the target collection and a cursor. The cursor points to the current item of the collection. The snapshot is a static copy of the collection. What happens if a collection is modified while being enumerated? An exception occurs. You could lock the collection during enumeration, but it might cause substantial performance degradation. As a best practice, an enumerator should capture the collection as a snapshot. This isolates the enumerator from changes to the original collection. In addition, the snapshot collection is read-only. The GetEnumerator method should be thread-safe, guaranteeing that a unique enumerator is returned, which references an isolated collection regardless of the thread context.

July 24, 2008 Posted by shiman | C#.Net, Computer Science, OOP, Programming, S/W Engineering | , , , , , , , , | No Comments Yet

How to Log in C# .NET with log4net : A Tutorial with Practical Example

While developing software, you will always have to keep it in your mind that your software is going to be crashed someday. And when you are about to fix the bugs, you have to have something in your hand, which will give you a hint from where to start. This is why you need the logging service to log the software’s functionalities. You can build your own library for this purpose. But, for the beginning, I will recommend you to use the assembly, ‘log4net ‘, a free assembly developed by Apache.

As the first step you need to download the log4net.dll file. You can download it either from my shared files on your right hand side bar, or from here.

Now, you need to follow the steps to develop a logging service.

·         Add the reference of log4net.dll.

·         Add a new class Named CLogger.cs in the project you want to add logging.

·         Add an Application Configuration File named App.config to your application if you do not have one.

·         Add the following code segment under <configuration>…</configuration> tag.

<?xml version=1.0 encoding=utf-8 ?>

<configuration>

       <configSections>

              <section name=log4net type=log4net.Config.Log4NetConfigurationSectionHandler, log4net />

       </configSections>

       <log4net>

              <appender name=LogFileAppender type=log4net.Appender.FileAppender>

                     <param name=File value=D:\Temp\ApplicationLog.log />

                     <param name=AppendToFile value=true />

                     <layout type=log4net.Layout.PatternLayout>

                           <param name=Header value=“” />

                           <param name=Footer value=“” />

                           <param name=ConversionPattern value=%d [%t] %-5p %m%n />

                     </layout>

              </appender>

              <appender name=ConsoleAppender type=log4net.Appender.ConsoleAppender >

                     <layout type=log4net.Layout.PatternLayout>

                           <param name=Header value=[Header]\r\n />

                           <param name=Footer value=[Footer]\r\n />

                           <param name=ConversionPattern value=%d [%t] %-5p %m%n />

                     </layout>

              </appender>

              <root>

                     <level value=DEBUG />

                     <appender-ref ref=LogFileAppender />

                     <appender-ref ref=ConsoleAppender />

              </root>

       </log4net>

</configuration>

The configuration file has included two appenders, i) Console Appender and ii) File Appender. You can use either or both. The <level> tag specify the log-level. By assigning its value to “DEBUG”, we enabled the logging service to write logs of all levels. Here is a little discussion on it.

In an earlier post, I said that utility classes should be static. Our CLogger is also a utility class. So, we are going to declare this class as a static class. But before that, we will make an enum. We can do without this enum, but it will make our program flawless.

·         Add a new class named ELogLevel.cs to your project.

·         Write the following code segment in ELogLevel.cs.

using System;

using System.Collections.Generic;

using System.Text;

 

namespace Utility

{

    namespace LoggingService

    {

        public enum ELogLevel

        {

            DEBUG = 1,

            ERROR,

            FATAL,

            INFO,

            WARN

        }

    }

}

Log4Net supports five levels of logs with five methods. In the CLogger class we are going to call those methods depending on the passed parameters from the application. It is so likely that you will make a spelling mistake and the logging service will not work. This is why we are giving our service a professional touch by having this enum.

·         Now, write the following code in CLogger.cs.

using System;

using System.Collections.Generic;

using System.Text;

using log4net;

using log4net.Config;

using System.Diagnostics;

using System.Reflection;

 

namespace Utility

{

    namespace LoggingService

    {

        public static class CLogger

        {

            #region Members

            private static readonly ILog logger = LogManager.GetLogger(typeof(CLogger));

           

            #endregion

 

            #region Constructors

            static CLogger()

            {

                XmlConfigurator.Configure();

            }

            #endregion

 

            #region Methods

 

            public static void WriteLog(ELogLevel logLevel, String log)

            {

                if (logLevel.Equals(ELogLevel.DEBUG))

                {

                    logger.Debug(log);

                }

                else if (logLevel.Equals(ELogLevel.ERROR))

                {

                    logger.Error(log);

                }

                else if (logLevel.Equals(ELogLevel.FATAL))

                {

                    logger.Fatal(log);

                }

                else if (logLevel.Equals(ELogLevel.INFO))

                {

                    logger.Info(log);

                }

                else if (logLevel.Equals(ELogLevel.WARN))

                {

                    logger.Warn(log);

                }

            }

            #endregion

        }       

    }

}

YO! Your logging service is ready to serve. Just write logs from your application as you need.

CLogger.WriteLog(ELogLevel.DEBUG, “This is a Debug log.”);

CLogger.WriteLog(ELogLevel.INFO, “This is a Information log.”);

CLogger.WriteLog(ELogLevel.WARN, “This is a Warning log.”);

CLogger.WriteLog(ELogLevel.ERROR, “This is a Error log.”);

CLogger.WriteLog(ELogLevel.FATAL, “This is a Fatal Error log.”);

Nice work! You have created a log file for your application.Find your log file in “D:\Temp” directory. You configured this location in your configuration file, remember? If not, take a close look. In later post I will discuss about the configuration file for Log4Net. So, stay tuned.

July 9, 2008 Posted by shiman | C#.Net, Computer Science, OOP, Programming, S/W Engineering | , , , , , | 15 Comments

A Very Practical Example of Boxing and Unboxing in C# .NET

Boxing and Unboxing – these two techniques are two of the most commonly used techniques in software development in a team. It is quite obvious that one developer is developing a class or method that is dependent on classes or methods being developed by other developers not knowing anything about their code base and vice versa. So, how will you pass a parameters to their method or what will they return to your call? Boxing and Unboxing are the two techniques to answer this question.

The term Boxing refers to an implicit casting and the term Unboxing refers to explicit casting. Let’s look at them:

//Boxing
int i = 5;
object o = i; // Implicit Casting 
//Unboxing
int j = (int)o; //Explicit Casting

Assume that you are working on a project with a team of three developers. According to your design, you need to develop three classes – MyPoint, My3DPoint and MyPrinter The responsibilities and the developers of the classes are:

  • MyPoint – Define a 2D point – Developer1.
  • My3DPoint – Define a 3D point – Developer2.
  • MyPrinter – Print the information of the other two classes – You.

The basic idea that everyone knows, is this: Developer1 and Developer2 will define their objects and pass to the PrintInfo() method of MyPrinter class to print their information. So, the codes of Developer1 and Developer2 will be something like this:

//Developer1
namespace Points
{
public class MyPoint
{
public int x;
public int y;           
}
 
public class Starter
{
public static void Main(string[] args)
{
MyPoint p = new MyPoint();
p.x = 4;
p.y = 5;
Utility.PrintInfo(p);
}
}
}

//Developer2
namespace Points
{
public class My3DPoint
{
public int x;
public int y;           
public int z;
}
 
public class Starter
{
public static void Main(string[] args)
{
MyPoint p = new MyPoint();
p.x = 4;
p.y = 5;
p.z = 5; 
Utility.PrintInfo(p);
}
}
}

Now, what will you do? Of course, you have a way towards method overloading. But, what if there are hundreds of types you have to deal with? Is it possible to make hundreds of overloads? So, here comes the Boxing and Unboxing to rescue developers like you. Simply, write your code like this:

namespace Printer
{
public class MyPrinter
{
public void PrintInfo(Object o) //Boxing is done here
{
if(o is MyPoint)
{
MyPoint p = new MyPoint();
p = (MyPoint)o; // Unboxing
Console.Writeline(“The point is ({0}, {1})”, p.x, p.y);
}
else if(o is My3DPoint)
{
My3DPoint p = new My3DPoint();
p = (My3DPoint)o; // Unboxing
Console.Writeline(“The point is ({0}, {1}, {2})”, p.x, p.y, p.z);
} 
}
}
}

Pretty easy, isn’t it?

June 5, 2008 Posted by shiman | C#.Net, Computer Science, OOP, Programming, S/W Engineering | , , , , | 2 Comments

A Practical Example of Static Costructor in C# .NET (Singletons)

Singletons provide an excellent example of private and static constructors. A singleton is an object that appears once in the problem domain. Singletons are limited to one instance, but that instance is required. This requirement is enforced in the implementation of the singleton.

The singleton presented in this chapter has two constructors. The private constructor means that an instance cannot be created outside the class. That would require calling the constructor publicly. However, an instance can be created inside the class. The single instance of the class is exposed as a static member, which is initialized in the static constructor. The instance members of the class are accessible through the static instance. Because the static constructor is called automatically, one instance—the singleton—always exists.

A chess game is played with a single board—no more or less. This is the singleton for a chess board:

using System;
namespace Examples.Singleton
{
public class Chessboard
{

public static Chessboard board=null;
public string player1;
public string player2;
public string start

private Chessboard() {} 
static Chessboard() 
{
board=new Chessboard();
board.start=DateTime.Now.ToShortTimeString();
}
} 
public class Game
{
public static void Main()
{
Chessboard game=Chessboard.board;
game.player1="Sally";
game.player2="Bob";
Console.WriteLine("{0} played {1} at {2}", game.player1, game.player2, game.start);
}
}
}

In Main, game is an alias for the ChessBoard.board singleton. The local variable is not another instance of Chessboard. The alias is simply a convenience. I preferred game.player1 to Chess-Board.board.player1.

June 3, 2008 Posted by shiman | C#.Net, Computer Science, Design Patterns, OOP, Programming, S/W Engineering | , , , , , , | 2 Comments