Monday, April 2, 2012

Quartz.NET

Quartz.NET is a very popular and widely used open source shedular framework. You can easily shedule thousands of complex job with Quartz.NET. Generally, we used timer feature in .net when need to develop sheduling based application. The limitation of times is that, we can not shedule a job by a specified month, day or year etc based and Timer does not have persistence mechanishm as well as it does not utilized the tread-pool. We can specify each job in a specified thread in the Quartz.NET. Here the example explain how to use the Quartz.NET in .net. Here I am using the Visual Studio 2010.

Steps:
1. Download the Quartz.NET dll of Quartz.NET 2.0 beta 1 from the following link  http://sourceforge.net/projects/quartznet/files/quartznet/
2. Created a Console application.
3. Add the refernce of Common.Logging.dll and Quartz.dll to the application from the downloaded folder Quartz.NET-2.0-beta1\bin\4.0\release\Quartz.
4. Add the app.config file and add the following configuration.

<configuration>
   <configSections>
     <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
   </configSections>
   <startup>
     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
   </startup>
 </configuration>

5. Add the following code in the Main() function.

        static void Main(string[] args)
        {
            ISchedulerFactory obSchedulerFactory = new StdSchedulerFactory();
            IScheduler obIScheduler = obSchedulerFactory.GetScheduler();
            DateTimeOffset runTime = DateBuilder.EvenSecondDateAfterNow();
            IJobDetail job = JobBuilder.Create<MYJob>()
                .WithIdentity("job1""group1")
                .Build();
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1""group1")
                .StartAt(runTime)
                .EndAt(runTime.AddMinutes(1))
                .WithCronSchedule("0/5 * * * * ?")
                .Build();

            obIScheduler.ScheduleJob(job, trigger);
            obIScheduler.Start();
        }
      
6. Creat a MyJob class.

    public class MYJob : IJob
    {
        public MYJob()
        {
        }
        public virtual void Execute(IJobExecutionContext context)
        {
            Console.WriteLine(string.Format("My Job! - {0}", System.DateTime.Now.ToString("r")));
        }
    }
   
7. Open the property of the application and select the Target Framework to .NET Framework 4 from .NET Framework 4 Client Profile.

8. Run the application. The output will be as follow

My Job! - Mon, 02 Apr 2012 12:16:10 GMT
My Job! - Mon, 02 Apr 2012 12:16:15 GMT
My Job! - Mon, 02 Apr 2012 12:16:20 GMT
My Job! - Mon, 02 Apr 2012 12:16:25 GMT

The Execute() function of the MyJob class will run in each 5 second, since we had set the shedular for 5 second.
There are 3 main component of the Quartz.NET : Trigger, Scheduler and Jobs.

Jobs:   Job is an executable task, which is sheduled and trigger in a regular interval. To specify the executable task, you have to inherit the IJob Interface and implement the Execute() function. This Execute() method will be called in each interval. In this example, I have used MYJob class and inherited the IJob interface. In the Main() function I have created the instance of IJobDetail instance with the identity name "job1" and group name "group1" and specified the MyJob class to be called.

Trigger: Trigger refers the start, end and sheduler interval for the job. Here I have created the instance of ITrigger instance with the identity name "trigger1" and group name "group1".  The group name for both the job and trigger should be same, so that it can identify that which job is used for which shedule when there are more than one job and trigger. Here I have set the StartAt() to the current datetime and EndAt() after the one minute of current time. The expression "0/5 * * * * ?" specifies the Crone experession, which is used to tell the sheduling time. Here I 0/5 specify that this job will be executing in each 5 second.

Cron Expressions Allowed Fields and Values
Name
Required
Allowed Values
Allowed Special Characters
Seconds
Y
0-59
, - * /
Minutes
Y
0-59
, - * /
Hours
Y
0-23
, - * /
Day of month
Y
1-31
, - * ? / L W C
Month
Y
0-11 or JAN-DEC
, - * /
Day of week
Y
1-7 or SUN-SAT
, - * ? / L C #
Year
N
empty or 1970-2099
, - * /

Cron Expressions
Cron expressions can be as simple as * * * * ? * or as complex as 0 0/5 14,18,3-39,52 ? JAN,MAR,SEP MON-FRI 2002-2010.
Here are some more examples:
Expression
Means
0 0 12 * * ?
Fire at 12:00 PM (noon) every day
0 15 10 ? * *
Fire at 10:15 AM every day
0 15 10 * * ?
Fire at 10:15 AM every day
0 15 10 * * ? *
Fire at 10:15 AM every day
0 15 10 * * ? 2005
Fire at 10:15 AM every day during the year 2005
0 * 14 * * ?
Fire every minute starting at 2:00 PM and ending at 2:59 PM, every day
0 0/5 14 * * ?
Fire every 5 minutes starting at 2:00 PM and ending at 2:55 PM, every day
0 0/5 14,18 * * ?
Fire every 5 minutes starting at 2:00 PM and ending at 2:55 PM, AND fire every 5 minutes starting at 6:00 PM and ending at 6:55 PM, every day
0 0-5 14 * * ?
Fire every minute starting at 2:00 PM and ending at 2:05 PM, every day
0 10,44 14 ? 3 WED
Fire at 2:10 PM and at 2:44 PM every Wednesday in the month of March
0 15 10 ? * MON-FRI
Fire at 10:15 AM every Monday, Tuesday, Wednesday, Thursday and Friday
0 15 10 15 * ?
Fire at 10:15 AM on the 15th day of every month
0 15 10 L * ?
Fire at 10:15 AM on the last day of every month
0 15 10 ? * 6L
Fire at 10:15 AM on the last Friday of every month
0 15 10 ? * 6L
Fire at 10:15 AM on the last Friday of every month
0 15 10 ? * 6L 2002-2005
Fire at 10:15 AM on every last friday of every month during the years 2002, 2003, 2004, and 2005
0 15 10 ? * 6#3
Fire at 10:15 AM on the third Friday of every month
0 0 12 1/5 * ?
Fire at 12 PM (noon) every 5 days every month, starting on the first day of the month
0 11 11 11 11 ?
Fire every November 11 at 11:11 AM

Sheduler: Sheduler is used to grouped the job and trigger both in a group and start and end the sheduling. Here I have created the instance of ISheduler and grouped both the job and trigger and then started the sheduler.
Download: 

Thursday, March 22, 2012

Part 2 : How to use log4net in .net


In Part 1 : How to use log4net in .net you have learnt the basic of log4net. Here I am going to tell you some more details about it.

Create Date based log file

Yes, you can also create your log files date vise. If you want to create a separate file for every day then you can also do that in the log4net. You need to set the <staticLogFileName value="false">
 in the appender.
 The appender section will be

  <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="d:\"/>
      <staticLogFileName value="false"/>
      <appendToFile value="true" />
      <rollingStyle value="Date" />
      <datePattern value="yyyy-MM-dd'.log'" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
      </layout>
  </appender>

Here the value of the file section specify the path of the log file. I have specify the "D:\ "then the file will be created in the "D" drive. If you specify the "d:\log_" then the log file will be "log_2012-03-22.log".


Create separate log file for specified log level

Here I would like to let you know how you can log the information according to their log level (Debug, Info, Warning, Error, Fatal) in different files. For example, if you want to log Debug log into a file and Error log to another file, you can achieve this through the log4net. For that you just have to add the two appender according to their log level. Each appender will have different log file.

<appender name="ErrorLogFileAppender" type="log4net.Appender.FileAppender">
<param name="File"value="D:\ErrorLogFile.txt"/>
<param name="AppendToFile" value="true"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
</layout>
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="ERROR"/>
</filter
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
    <appender name="DebugLogFileAppender" type="log4net.Appender.FileAppender">
<param name="File" value="D:\DebugLogFile.txt"/>
<param name="AppendToFile" value="true"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c %m%n"/>
</layout>
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="DEBUG"/>
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="DebugLogFileAppender" />
<appender-ref ref="ErrorLogFileAppender" />
</root>
 
Here I have created two appender ErrorLogFileAppender and DebugLogFileAppender. ErrorLogFileAppender logs the Error level log and store the log information into the ErrorLogFile.txt and DebugLogFileAppender logs the Debug log and store the log information into the DebugLogFile.txt.


Appenders

We can log the information into differenct destination output through the Appender.  In Previous examples we have seen the FileAppender which is used to log the information into a file. However, log4net provides numbers of Appenders to log the information, you can customized as per your need.

FileAppender
                See the previous examples.


SmtpAppender
 SmtpAppender is used when you want to get the specified event log through the email. The following example will show how to use the SmtpAppender.

    <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
      <to value="to@domain.com" />
      <from value="from@domain.com" />
      <subject value="my logging message" />
      <smtpHost value="SMTPServer.domain.com" />
      <bufferSize value="512" />
      <lossy value="false" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" />
      </layout>
    </appender>

 Here to specifies the address where log event should be send. The from is the address from which account email should be send. The subject specifies the subject of the email. You can also customise this subject. The bufferSize specifies the size of the email. As soon as log event information reached that size, it sends the email.

<subject type="log4net.Util.PatternString" value="%property{log4net:HostName} Error: %appdomain" />

Here I have customised the subject. The HostName and appdomain represents the your host name and application domain of your application.

In the above appender all the log events will be sent to the specified email address, however you can also mentioned which log event you want in email. For that you have to use the following configuration.

<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">     
<to value="to@domain.com" />     
<from value="from@domain.com" />     
<subject value="my logging message" />     
<smtpHost value="SMTPServer.domain.com" />     
<bufferSize value="512"/>     
<lossy value="true" />     
<evaluator type="log4net.Core.LevelEvaluator">       
<threshold value="ERROR"/>     
</evaluator>      
<layout type="log4net.Layout.PatternLayout">       
<conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" />     
</layout>
</appender>
 
Here you will get only Errro log event through the email. For that you have to set the lossy to "true" and evaluator to "ERROR".

ConsoleAppender
 Basically ConsoleAppender is used to show the log event information into the console output. The following configuration is used for the ConsoleAppender.

 <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"/&agt;     
<layout type="log4net.Layout.PatternLayout"/&gt       
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />     
</layout>    </appender>
   

Monday, February 27, 2012

Insert multipal rows into database

 Sometimes we need to insert or update multipal records in a single call using c# code . Here I am going to tell how you can achive this throw the new features of SQL Server 2008. In Sql Server 2008, we can pass table type variable in the parameters of the stored procedrue. So, we can create a table type object in the .net code and pass that object in parameter. Let me give you an example step by step.

Steps:

1.      1. Create a table named Employee.
2.      

CREATE TABLE [dbo].[Employee](
      [EmpId] [nvarchar](20) NULL,
      [Name] [nvarchar](50) NULL,
      [Salary] [decimal](18, 0) NULL
     ) ON [PRIMARY]
     GO
     

3.      2. Create a table type variable named EmployeeTable


CREATE TYPE EmployeeTable AS TABLE
      (    
        [EmpId][nvarchar](20) NULL,
        [Name][nvarchar](50) NULL,
        [Salary][decimal](18, 0) NULL
      )
      GO


    3.  Create a stored procedure to insert/update the data.         

ALTER PROCEDURE SaveEmployee
      @EmployeeTable as EmployeeTable READONLY
AS
BEGIN
      SET NOCOUNT ON;
    DECLARE @InsertEmployeeTable as EmployeeTable,
            @UpdateEmployeeTable as EmployeeTable
       
    /* Insert those records which are not exist in the Employee table  */
    INSERT INTO @InsertEmployeeTable
    SELECT * FROM @EmployeeTable  WHERE [@EmployeeTable].[EmpId] NOT IN (SELECT EmpId FROM Employee)
   
    /* Insert those records which are exist in the Employee table  */
    INSERT INTO @UpdateEmployeeTable
    SELECT * FROM @EmployeeTable WHERE [@EmployeeTable].[EmpId] IN (SELECT EmpId FROM Employee)
   
    /* Insert the new records in the Employee table */
    INSERT INTO Employee
    SELECT * FROM @InsertEmployeeTable
   
    /* update the existing records in the Employee table */
    UPDATE Employee
    SET Name = [@UpdateEmployeeTable].[Name]
        Salary = [@UpdateEmployeeTable].[Salary]   
   FROM Employee INNER JOIN @UpdateEmployeeTable ON Employee.EmpId = [@UpdateEmployeeTable].[EmpId]
      
END
GO


       Here I am passing EmployeeTable type variable @EmployeeTable in the parameter.  Created two EmployeTable variable @InsertEmployeeTable and  @UpdateEmployeeTable. @InsertEmployeeTable is used to stored those records which are     going to be insert and  @UpdateEmployeeTable to update records.

 4. Create a console application and add an app.cofig file and add the connection string.

 5. Add a class Employee.cs.Here I have created the Save() method which takes the collectios of Employee object. This function basically convert the IList collection to the datatable and pass that datable into the parameter of the stored procedure.  Here you have to very careful when converting the Employee collection to the DataTable. The datatable should have the same same as EmployeeTable type in the Sql Server.



     public void Save(IList<Employee>obEmployees)
        {
            SqlConnection connection =new SqlConnection(ConfigurationManager.AppSettings["Emp.Connection"].ToString());
           
            SqlCommand obCommand = new SqlCommand();
            obCommand.Connection = connection;
            obCommand.Connection.Open();
            obCommand.CommandText = "SaveEmployee";
            obCommand.CommandType =System.Data.CommandType.StoredProcedure;
            //Convert collection to data table
            DataTable dtEmployee = GetEmployeeTable(obEmployees);
            obCommand.Parameters.Add("@EmployeeTable", dtEmployee);
            obCommand.ExecuteNonQuery();
            obCommand.Connection.Close();
        }
        private DataTable GetEmployeeTable(IList<Employee> obEmployeeList)
        {
            var dtEmployee = new DataTable("dtEmployee");
            dtEmployee.Columns.Add(new DataColumn("EmpId"));
            dtEmployee.Columns.Add(new DataColumn("Name"));
            dtEmployee.Columns.Add(new DataColumn("Salary"));
            DataRow dataRow;
            //Assing each object to Data Row and add to Datatable
            foreach (var obEmployee in obEmployeeList)
            {
                dataRow = dtEmployee.NewRow();
                dtEmployee.Rows.Add(GetEmployeeDataRow(dataRow, obEmployee));
            }
            return dtEmployee;
        }
        private static DataRow GetEmployeeDataRow(DataRow dataRow, Employee obEmployee)
        {
            dataRow["EmpId"] = obEmployee.EmpId;
            dataRow["Name"] = obEmployee.Name;
            dataRow["Salary"] = obEmployee.Salary;
            return dataRow;
        }


  6. Add the following code in the Program.cs file.


     static void Main(string[] args)
        {
            Employee obEmployee = new Employee();
            Console.WriteLine("*********** SAVE EMP *********");
            List<Employee> obEmployees = new List<Employee>();
            obEmployees.Add(new Employee {EmpId = "EMP01", Name = "A", Salary = 6000});
            obEmployees.Add(new Employee { EmpId = "EMP02", Name = "B", Salary = 7000 });
            obEmployees.Add(new Employee { EmpId = "EMP03", Name = "C", Salary = 8000 });
            obEmployee.Save(obEmployees);
            Console.WriteLine("************************");
            Console.ReadLine();
        }


If you run this code first time then application will add those value into the table. And if you run the same code with differenct Name and Salary but same EmpId then it will update all the records.

Download :