Thursday, November 6, 2014

c# - Send alerts when database table row value is changed

Requirement:
Send an alert when any column value in a given list of rows in a table changes.

There are different ways to build an alert system when a row's column value changes but in this case I am using C# to write a program that tracks these changes and send an email report with the changes.

The C# program is scheduled to run every minute to check whether the row value changed.

Few things to note.The table has primary key so all rows are unique.The table rows do not change often  and the size of the table is small with only a few thousand rows.Also we want to only track a subset of rows in the table.


Step 1: Create a file or table that holds the rows from the original table that will be tracked.The primary key list that will be tracked is stored in the configuration file.In this case I will be using a file to store these rows.


Step 2: Extract the rows based on the primary key list in configuration file from the original table and compare with the rows in the file or table created in the Step 1.


Step 3: If the column values are different add the primary key,column name,old value,new value to the report.


Step 4: Send an email with the report created in Step 3


Step 5: If the primary key count in the configuration file has changed or does not match with the rows in the file created in Step 1,then overwrite the file with the new list of rows that will be tracked.


Below is the entire code


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Text;
using NLog;

namespace MyCompany.MyDept.MyProject.TableRowEditAlert

{
    class Program
    {
        static void Main(string[] args)
        {
            Logger oLog = LogManager.GetCurrentClassLogger();
            try
            {
                string sConnectionString = ConfigurationManager.AppSettings["MY_DB"];
                string sIdList = ConfigurationManager.AppSettings["ID_LIST"];
                string sFilePath = ConfigurationManager.AppSettings["FILE_PATH"];

                DataSet ds = GetIdDetails(sConnectionString, sIdList);

                if (ds != null)
                {
                    if (!File.Exists(sFilePath))
                    {
                        CreateIdDetailsFile(sFilePath, ds,true);
                    }
                    else
                    {
                        string [] sFileLines = File.ReadAllLines(sFilePath);
                        if ((sFileLines.Length - 1) != ds.Tables[0].Rows.Count)
                        {
                            CreateIdDetailsFile(sFilePath, ds, false);
                        }
                        else
                        {
                            StringBuilder sDiff = new StringBuilder();
                            string [] sCols = sFileLines[0].Split('\t');
                           
                            for (int iIndex = 1; iIndex < sFileLines.Length; iIndex++)
                            {
                                string[] sFileLineItems = sFileLines[iIndex].Split('\t');
                                for (int jIndex = 0; jIndex < sFileLineItems.Length; jIndex++)
                                {
                                    if (ds.Tables[0].Rows[iIndex -1][jIndex] != null && ds.Tables[0].Rows[iIndex-1][jIndex].ToString() != sFileLineItems[jIndex])
                                    {
                                        sDiff.Append(sFileLineItems[0]);
                                        sDiff.Append('\t');
                                        sDiff.Append(sFileLineItems[6]);
                                        sDiff.Append('\t');
                                        sDiff.Append(sFileLineItems[1]);
                                        sDiff.Append('\t');
                                        sDiff.Append(sCols[jIndex]);
                                        sDiff.Append('\t');
                                        sDiff.Append(sFileLineItems[jIndex]);
                                        sDiff.Append('\t');
                                        sDiff.Append(ds.Tables[0].Rows[iIndex-1][jIndex].ToString());
                                        sDiff.Append('\n');
                                    }
                                }
                            }
                             if (!string.IsNullOrEmpty(sDiff.ToString()))
                            {
                                SendMail(GenerateReport(sDiff.ToString()).ToString(), ConfigurationManager.AppSettings["EMAIL_SUBJECT"], true, ConfigurationManager.AppSettings["NOTIFICATION_LIST"].Split(','));

                                CreateIdDetailsFile(sFilePath, ds, false);

                            }
                        }
                    }
                }
                
            }
            catch (Exception ex)
            {
                oLog.Error(ex.Message);
                oLog.Error(ex.StackTrace);
            }
        }

        private static void CreateIdDetailsFile(string sFilePath, DataSet ds,bool bAppend)

        {
            using (StreamWriter oWriter = new StreamWriter(sFilePath,bAppend))
            {
                StringBuilder sb = new StringBuilder();
                foreach (DataColumn col in ds.Tables[0].Columns)
                {
                    sb.Append(col.ColumnName);
                    if (col.Ordinal != ds.Tables[0].Columns.Count-1)
                        sb.Append('\t');
                }
                sb.Append(Environment.NewLine);

                foreach (DataRow row in ds.Tables[0].Rows)

                {
                    foreach (DataColumn col in ds.Tables[0].Columns)
                    {
                        sb.Append(row[col] != null ? row[col].ToString() : "");
                        if(col.Ordinal != ds.Tables[0].Columns.Count - 1)
                            sb.Append('\t');
                    }
                    sb.Append(Environment.NewLine);
                }
                oWriter.Write(sb.ToString());
            }
        }

        private static DataSet GetIdDetails(string sConnectionString, string sIdList)

        {
            using (SqlConnection oConn = new SqlConnection(sConnectionString))
            {
                oConn.Open();
                SqlCommand oCmd = new SqlCommand("select * from dbo.my_table where id in (" + sIdList + ") order by id", oConn);
                oCmd.CommandType = CommandType.Text;
                SqlDataAdapter oDataAdapter = new SqlDataAdapter(oCmd);
                DataSet ds = new DataSet();
                oDataAdapter.Fill(ds);
                return ds;
            }
        }

        public static void SendMail(String message, String subject, Boolean p_bIsHtml, String[] notificationList)

        {
            try
            {
                MailMessage MyMessage = new MailMessage();
                MyMessage.From = new MailAddress(ConfigurationManager.AppSettings["EMAIL_FROM"]);
                foreach (String email in notificationList)
                    MyMessage.To.Add(new MailAddress(email));
                MyMessage.IsBodyHtml = p_bIsHtml;
                MyMessage.Subject = subject;
                MyMessage.Body = message;

                SmtpClient emailClient = new SmtpClient("smtp.office.mycompany.com");

                emailClient.Send(MyMessage);
            }
            catch
            {
            }
        }

        private static StringBuilder GenerateReport(string sDiff)

        {
            string [] sLines = sDiff.Split('\n');
            StringBuilder sbHtml = new StringBuilder();
            sbHtml.AppendLine(@"<style type='text/css'>td{font-size: 9px;font-family: verdana} </style>");
            sbHtml.AppendLine("<table><border=1><tr bgcolor=Orange align=center><td colspan=6><b>Table Row Edit Alert</b></td></tr><tr bgcolor=LightBlue align=center><td><b>ID</b></td><td><b> Name</b></td><td><b> URL</b></td><td><b>Column</b></td><td><b>Old Value</b></td><td><b>New Value</b></td></tr>");
            foreach (string  s in sLines)
            {
                if(!string.IsNullOrEmpty(s))
                {
                    string[] sLineItems = s.Split('\t');
                    sbHtml.AppendLine("<tr bgcolor=LightGreen align=center><td><b>" + sLineItems[0] + "</b></td><td><b>" + sLineItems[1] + "</b></td><td><b>" + sLineItems[2] + "</b></td><td><b>" + sLineItems[3] + "</b></td><td><b>" + sLineItems[4] + "</b></td><td><b>" + sLineItems[5] + "</b></td></tr>");
                }
            }
            sbHtml.AppendLine("</table");
            sbHtml.AppendLine("<br/>");
            sbHtml.AppendLine("<br/>");
            return sbHtml;
        }
    }
}

Configuration File

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="MY_DB" value="server=server_name;database=database_name;uid='my_id';pwd='my_password';"/>
    <add key="ID_LIST" value="100,101,102,103,500,501,501,701,703,704" />
    <add key="FILE_PATH" value="C:\Data\Id.txt"/>
    <add key="EMAIL_FROM" value="admin@mycompany.com"/>
    <add key="EMAIL_SUBJECT" value="Table Row Edit Alert"/>
    <add key="NOTIFICATION_LIST" value="my_email@mycompany.com"/>
  </appSettings>
</configuration>

No comments: