browse by category or date

Recently I was tasked to develop an application to keep track the outgoing items from the warehouse. Since it was style like a POS machine, I need to limit the instance of Windows Form application to only one.

To do this we’re going to need a “locking” mechanism. So before launching the Form, we need to check whether the lock is ON or OFF. We can use Mutex object as the lock.

public Mutex(
	bool initiallyOwned,
	string name
)
initiallyOwned
Type: System.Boolean

true to give the calling thread initial ownership of the named system mutex if the named system mutex is created as a result of this call; otherwise, false.

name
Type: System.String

The name of the Mutex. If the value is null, the Mutex is unnamed.

To ensure the unique-ness of Mutex’s name, I used GUID as name (in Visual Studio, Tools -> Create GUID)

vs-guid

This is the final code:

using System;
using System.Threading;
using System.Windows.Forms;

namespace MyPOS
{
	static class Program
	{
		static Mutex mutex = new Mutex(true, "{37D26ECE-1F4F-42BC-9C23-11A9DAA8DCCA}");

		[STAThread]
		static void Main()
		{
			//Grab the lock
			if (mutex.WaitOne(TimeSpan.Zero, true))			
				Application.EnableVisualStyles();
				Application.SetCompatibleTextRenderingDefault(false);
				Application.Run(new Form1());

				//when the application is finished, release the lock
				mutex.ReleaseMutex();
			}
			else
			{
				//Lock is already used
				MessageBox.Show("Only one instance allowed");
			}
		}
	}
}

I hope it helps, cheers!

About Hardono

Howdy! I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.

Possibly relevant:

Singapore public holidays information is available at Ministry of Manpower (MOM) website. Currently we can get them from 3 locations:

  1. ICS File http://www.mom.gov.sg/Documents/employment-practices/public-holidays/public_holidays.sg.YYYY.ics
  2. Web page http://www.mom.gov.sg/employment-practices/leave-and-holidays/Pages/public-holidays-YYYY.aspx
  3. Web page beta version http://www.mom.gov.sg/beta/public-holidays.html

For the sake of brevity, I will only make use the data from the beta version website. If you interested in parsing ICS file, the wheel is already created.

Alright, first we need to add HtmlAgilityPack to our project

PM> Install-Package HtmlAgilityPack

Next, we view the source of http://www.mom.gov.sg/beta/public-holidays.html

singapore-ph

<!---- Lots of other stuffs -->
<div id=Public-holidays-2013 class=tab>
	<!---- other stuffs -->
	<tbody>
		<tr>
			<td>1 January 2014</td>
			<td>Wednesday</td>
			<td><img src="assets/images/public-holiday/new_year.png" alt="" width=52></td>
			<td class=cell-holiday-name>New Year’s Day<span class=text-date-mobile>1 January 2014, Wednesday</span></td>
		</tr>
		<tr>
			<td>31 January 2014 <br>1 February 2014</td>
			<td>Friday <br>Saturday</td>
			<td><img src="assets/images/public-holiday/cny.png" alt="" width=52></td>
			<td class=cell-holiday-name>Chinese New Year<span class=text-date-mobile>31 January 2014 - 1 February 2014, Friday - Saturday	</span></td>
		</tr>
<!---- Lots of other stuffs -->

From code above we can take note that:

  1. The public holidays for each year are located under div with id Public-Holidays-YYYY
  2. Each public holiday is under tr
  3. The first td will contain the date, with the exception of Chinese New Year, it will contain two dates
  4. The last td will contain the public holiday name

With that in mind, we can now configure how our parsing would be. Before that let’s create the class to hold the data:

public class PublicHoliday
{
	public DateTime Date { get; set; }
	public String Name { get; set; }
}

And now let’s construct the method to parse the HTML:

private List<PublicHoliday> RetrievePublicHolidays(DateTime dt, HtmlDocument doc)
{
	var yearID = "Public-holidays-" + dt.Year.ToString();
	var result = new List<PublicHoliday>();
	
	foreach (var tr in doc.DocumentNode.SelectNodes("//div[@id='" + yearID + "']/table/tbody/tr"))
	{		
		DateTime curDt;
		if (DateTime.TryParse(tr.ChildNodes.First(x => x.Name == "td").InnerText, out curDt))
		{
			
			var td = tr.ChildNodes.Last(x => x.Name == "td");
			var pb = new PublicHoliday{
				Date = curDt,
				Name = td.ChildNodes.First().InnerText
			};			
			result.add(pb);
		}
		else
		{
			//Special treatment for Chinese New Year
			if (td.InnerHtml.Contains("<br>"))
			{
				var lastTd = tr.ChildNodes.Last(x => x.Name == "td");
				var Name = lastTd.ChildNodes.First().InnerText;
				if (DateTime.TryParse(td.ChildNodes.First().InnerText, out curDt))
				{
					var pb = new PublicHoliday
					{
						Date = curDt,
						Name = Remarks
					};
					result.add(pb);
				}
				if (DateTime.TryParse(td.ChildNodes.Last().InnerText, out curDt))
				{
					var pb = new PublicHoliday
					{
						Date = curDt,
						Remarks = Remarks
					};
					result.add(pb);
				}
			}
		}
	}	
	return result;
}

Finally, let above method take into action:

var request = WebRequest.Create("http://www.mom.gov.sg/beta/public-holidays.html");
var response = request.GetResponse();
var resStream = response.GetResponseStream();

if (resStream == null)
{
	throw new Exception ("Response Stream is empty");
}

var reader = new StreamReader(resStream);
var content = reader.ReadToEnd();
reader.Close();

//Now Load the HTML
var doc = new HtmlDocument();
doc.LoadHtml(content);

//Retrieve last year Public Holidays
RetrievePublicHolidays(DateTime.Now.AddYear(-1), doc);

//Retrieve this year Public Holidays
RetrievePublicHolidays(DateTime.Now, doc);

//Retrieve next year Public Holidays
RetrievePublicHolidays(DateTime.Now.AddYear(1), doc);

That’s all folks. I hope it helps, cheers!

About Hardono

Howdy! I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.

Possibly relevant:

You can use this trick to protect your Windows Form or Console application connection strings. In order to work, you need to have the database information under ConnectionStrings section.

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source= MyDBServer;initial catalog=MyDatabase;user id=MyUserId;password=MyPassword;" providerName="System.Data.SqlClient" />
    <add name="PostalCodeEntities" connectionString="metadata=res://*/PostalCodeModel.csdl|res://*/PostalCodeModel.ssdl|res://*/PostalCodeModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=MyDBServer;initial catalog=MyDatabase;persist security info=True;user id=MyUserId;password=MyPassword;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />    
</connectionStrings>

Add the following method in Program.cs file

using System.Configuration;
using System.Reflection;

//.... 

private static void SecureConfig()
{
	var name = "";
	if (Environment.GetCommandLineArgs().Length > 0)
		name = Environment.GetCommandLineArgs()[0];
	else
		name = Assembly.GetExecutingAssembly().CodeBase;
	if (!name.ToLower().EndsWith(".exe"))
		name = name + ".exe";
	if (!name.Contains(Environment.CurrentDirectory))
		name = Environment.CurrentDirectory + "\\" + name;

	var reader = ConfigurationManager.OpenExeConfiguration(name);
	var section = reader.GetSection("connectionStrings");
	if (!section.SectionInformation.IsProtected)
	{
		section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
	}
	reader.Save();
}

//.... 

Then call above method in your Main before you do anything else.

Example in Windows Form application:

using System;
using System.Windows.Forms;
using System.Configuration;
using System.Reflection;

namespace MyNamespace
{
	static class Program
	{        
		/// 
		/// The main entry point for the application.
		///        

		[STAThread]
		static void Main()
		{            
			SecureConfig();
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.Run(new Form1()); 
		}
		
		private static void SecureConfig()
		{
			// Code as shown above ....
		}
	}
}

You can add this to any of your existing program. Once you executed the program once, the ConnectionStrings content will become something like this

<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
	<EncryptedData>
	  <CipherData>
		<CipherValue>....Very Long Base64 String ...=</CipherValue>
	  </CipherData>
	</EncryptedData>
</connectionStrings>

I hope it helps, cheers!

About Hardono

Howdy! I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.

Possibly relevant: