Sunday, 7 September 2014

Create Simple Windows Service and Self Install in C# & VB

Feeling troublesome for using installutil to install Windows Service? Having to navigate to C:\Windows\Microsoft.NET\Framework\<your framework version> or C:\Windows\Microsoft.NET\Framework64\<your framework version> just to install or uninstalling Windows Service in server environment? Well, there's a more convenient way to perform installation and uninstallation, which is to write code for the Windows Service to self install / uninstall.

Before we go into that, let's create a simple Windows Service Project.

1) Select Windows Service and fill up your desired project name.

Visual Studio 2013 New Project


2) For this demo, Timer will be used to write to event log for every 10 seconds. So, open up the service in View Code mode or click on F7. 

Include the following namespace
[C#]
using System.Timers;
using System.Diagnostics;

[VB]
Imports System.Timers
Imports System.Diagnostics


Create a Timer variable
[C#]
private Timer _timer = null;

[VB]
Private _timer As Timer


OnStart Method - Initialize the timer that will write to event log for every 10 seconds. This method will run when the service started.
[C#]
_timer = new Timer();
_timer.Enabled = true;
_timer.Interval = 10000;
_timer.Elapsed += (sender, e) => {
    EventLog eventLog = new EventLog();
    eventLog.Source = "Windows Service Self Install Demo";
    eventLog.WriteEntry(DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss") + " - Windows Service Self Install Demo.");
};

[VB]
_timer = New Timer
_timer.Enabled = True
_timer.Interval = 10000

AddHandler _timer.Elapsed, AddressOf OnTimedEvent


Private Sub OnTimedEvent(source As Object, e As ElapsedEventArgs)
        Dim eventLog As EventLog = New EventLog()
        eventLog.Source = "Windows Service Self Install Demo VB"
        eventLog.WriteEntry(DateTime.Now.ToString("dd-MM-yyyy HH:mm:ss") + " - Windows Service Self Install Demo.")
End Sub


OnStop Method - To stop and release resource used by the timer. This method will run when the service is stopped.
[C#]
_timer.Close();

[VB]
_timer.Close()


3) Create a ProjectInstaller by double click or shift + F7 or open service in View Designer mode, right click on any gray area and click Add Installer. A ProjectInstaller file will be created in your project.

Windows Service Designer

4) Double click or shift + F7 or open ProjectInstaller in View Designer mode. Choose your desired properties for both serviceProcessInstaller1 and serviceInstaller1. In my case, this is what i set.

serviceProcessInstaller1
- Account : LocalSystem

serviceInstaller1
- StartType : Automatic
- Description : Demo Self Install Windows Service
- DisplayName : Windows Service Demo
- ServiceName : Windows Service Demo

Service Process Installer

Service Installer


With this, the windows service is created. Next would be to create a self install windows service. In the main method, add the following lines of code to pass in argument. In C# the main method is located in "Program.cs" file, whereas for VB, it is located in your service file.


[C#]
if (System.Environment.UserInteractive)
{
    if (args.Count() == 1)
    {
        if (args[0] == "-install")
            ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });

        if (args[0] == "-uninstall")
            ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
    }
    return;
}

[VB]
If System.Environment.UserInteractive Then
    If args.Count() = 1 Then
        If args(0) = "-install" Then
            ManagedInstallerClass.InstallHelper(New String() {Assembly.GetExecutingAssembly().Location})
        End If

        If args(0) = "-uninstall" Then
            ManagedInstallerClass.InstallHelper(New String() {"/u", Assembly.GetExecutingAssembly().Location})
        End If
    End If
    Exit Sub
End If


Once it is done, compile your project. Next is to show how to install or uninstall the windows service. Here are the couple of ways to install / uninstall the windows service.


[Command Prompt]
1) In command prompt window, navigate to your bin folder that contain the service executable file. 

2) To install, type and run [Windows Service Assembly Name].exe -install. To uninstall, just change -install to -uninstall and execute.


path.exe -install

path.exe -uninstall


[Shortcut]
1) Navigate to your bin folder that contain the service executable file. 

2) Create a shortcut from the service executable file. Right click on it and select Properties

3) Select Shortcut tab.

4) In the target field, for installation, add -install after your executable path. For uninstallation, just change -install to -uninstall or you can create 2 different shortcut for install and uninstall respectively.

5) Run the shortcut.

path -install

path.exe -uninstall


[Visual Studio]
1) Right click on your Windows Service project and click Properties.

2) Select Debug tab.

3) Under Start Options. For installation, type -install in Command line arguments field. For uninstallation, just change -install to -uninstall.

4) Start / debug your project.

-install

-uninstall


By using one of the methods above to install, the windows service should appear in the Service window. If you are unsure how to open the service window, you can do one of the following.
- At Run window, Type services.msc and click OK button, or
- Control Panel > Administrative Tools > Services.

Services Window

That's all for creating a Self Install.

Here's the source code : https://onedrive.live.com/redir?resid=E6612168B803803D!358&authkey=!AE6WfmdHMIoWpTg&ithint=file%2czip

If you would like to find out more on what else you can do during Self Install other than just installing windows service, then you may want to consider take a look here http://jaryl-lan.blogspot.com/2015/11/list-of-additional-funtionality-to.html




Sunday, 10 August 2014

[LocalDB] Connecting to LocalDB failed [Error Code 52]

Have you been using LocalDB for your development machine and it works perfectly fine. But when you deploy your application together with LocalDB to another machine, it just failed to connect to the LocalDB.

You may see a similar error message as follows.

System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 52 - Unable to locate a Local Database Runtime installation. Verify that SQL Server Express is properly installed and that the Local Database Runtime feature is enabled.)

What the above message meant is that the machine you deployed does not have a Local Database Runtime installed. So before we proceed to solve the above issue, let's look through certain things.

If your localDB is created from Visual Studio 2013, then your localDB would have version 11.0. To view the version in detail, just execute the query "SELECT @@VERSION". You can execute the query through SQL Server Management Studio or Visual Studio 2013.

Microsoft SQL Server 2012 (SP1) - 11.0.3000.0 (X64)
    Oct 19 2012 13:38:57
    Copyright (c) Microsoft Corporation
    Express Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: ) (Hypervisor)

Next, we have to download the SqlLocalDB.msi from http://www.microsoft.com/en-us/download/details.aspx?id=29062. Depending on your server machine, pick 32Bit or 64Bit.

If your LocalDB version is version 12.0 or SQL Server 2014, then you may need to get the SqlLocalDB.msi from this link instead http://www.microsoft.com/en-my/download/details.aspx?id=42299.

UPDATE: With the release of SQL Server 2016, you can now get the LocalDB version 13.0 here https://www.microsoft.com/en-us/download/details.aspx?id=52679.

After you have downloaded it, install it to the machine that contains your application that is facing the above error. The installation is pretty much straightforward and remember to read the terms and condition before proceed with the installation

After you have done the installation, your application should now be able to connect to the LocalDB.

For more details : http://www.mssqltips.com/sqlservertip/2694/getting-started-with-sql-server-2012-express-localdb/

If you do hit with another error when your web application is deployed to IIS and is accessing to LocalDB, you may want to check it out here http://jaryl-lan.blogspot.com/2016/06/localdb-connecting-to-localdb-failed.html

Tuesday, 29 July 2014

[Windows Server 2012 R2] Enable Ping in Hyper-V Windows Server 2012 R2

You have installed Windows Server 2012 R2 on Hyper-V. Added a network adapter. Depending on situation, you have also configured static IP address to your network adapter. Then finally when you tried to run ping command to the Hyper-V, it shows "Request timed out.".

Command Prompt - Ping

At that point of time you might have been wandering is it something when wrong with the network configuration. But fear not, it was actually by default the windows firewall prevent ping command issued to the server.

This obviously can be solved by turning off your windows firewall. But you won't want to do that due to some security concern. So, without actually turning off your firewall, you can change the existing windows firewall inbound rules.

1) Open up your Windows Firewall with Advanced Security. It is located at,
- Control Panel > Windows Firewall > Advanced Settings, or
- Control Panel > Administrative Tools > Windows Firewall with Advanced Security, or
- Run the command "wf.msc" in your command prompt, or
- Run the command "wf.msc" in your Run window.

Windows Firewall with Advanced Security Window

3) Select Inbound Rules located at the left panel. At middle panel, look for File and Printer Sharing (Echo Request - ICMPv4-In). Right click on it and select Enable Rule. If you require to ping through IPv6, then you can enable rule for File and Printer Sharing (Echo Request - ICMPv6-In). Wait for the icon beside the rule to turn green.


That's all for the configuration. By now you should be able to run ping command to your Windows running in Hyper-V.

Command Prompt - Ping

For more details, visit http://blog.blksthl.com/2012/11/20/how-to-enable-ping-in-windows-server-2012/

Saturday, 26 July 2014

[Windows Server 2012 R2] Configure Remote Access to Hyper-V with Multiple Session per User

It is possible to configure same user to have different session when remote access to the same server in Hyper-V. This is of course can be done on a real physical server, but it is advisable to try it out in Hyper-V before messing up the physical server.

Before proceed, ensure that your Hyper-V have network connection and have enabled remote access. Enable Remote Access : http://jaryl-lan.blogspot.com/2014/07/windows-server-2012-r2-enable-disable.html
Enable Internet Access : http://jaryl-lan.blogspot.com/2014/07/configure-internet-access-for-hyper-v.html

To enable multiple session per user.
1) In your Hyper-V Server, open up registry editor.

Registry Editor Window

2) Navigate to the following, HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TerminalServer.

Registry Editor - Terminal Server Selection
  
3) Look for fSingleSessionPerUser. If it does not exist, create DWORD with the name fSingleSessionPerUser.

4) Right click on fSingleSessionPerUser and click modify.

Registry Editor - Terminal Server - Edit DWORD (32-bit) Value Window

5) Set the value to 0 and click OK. It will then enable same user to have different session.

6) If you want to revert back the setting for each user to have only one session, then just change the value to 1.

For more detail can be found here http://remotedesktoprdp.com/force-single-session-allow-multiple-sessions-per-user

After you have done configure. You can then open up 2 remote desktop window accessing to the same Hyper-V Server with the same user.

If you have previously remote access but did not log off the user session. The next time when you remote access with the same user, a Windows sign-in window will prompt to choose which session to access.

Windows sign-in Window

In the task manager under Users tab, you can see the number of user's session that have previously log on without logging off and its current status.

Task Manager - Users Tab

[Windows Server 2012 R2] Enable / Disable Remote Access to Hyper-V Windows Server 2012 R2

To enable / disable remote access to Hyper-V Windows Server 2012 R2, it is actually quite simple. But it is also essential for your Hyper-V to have network connection to be able to remote access, or else enabling remote access will still not be able remote access to the server since there's no connection.

There are couple of ways to enable / disable remote access and the settings are pretty much similar across different windows server version and edition.

Alternative 1 : Execute command in command prompt.

1) In your Hyper-V Server, open up a command prompt. Up to you to use the run command or navigate to the command prompt location to open up the command prompt.

Command Prompt Window

2) To enable, type "C:\Windows\System32\scregedit.wsf /ar 0" without double quote and click enter. If your installed windows is not in C drive, just change C to the drive letter that contain your installed windows.

Command Prompt - scregedit.wcf command

3) To disable, just change 0 to 1 "C:\Windows\System32\scregedit.wsf /ar 1" without double quote and click enter. If your installed windows is not in C drive, just change C to the drive letter that contain your installed windows.

For more detail can be found here http://technet.microsoft.com/en-us/library/jj647785.aspx


Alternative 2 : Using Graphical User Interface.

1) In your Hyper-V Server, navigate to your System window. It can be located from
This PC > System Properties, or
Control Panel > System, or
any other possible way which is more convenient for you.

System Window

2) Click Advance system settings located at left panel in your System window. System Properties window will appear.

System Window - System Properties - Remote Tab

3) Click on Remote Tab. Under Remote Desktop, to enable remote access, select "Allow remote connections to this computer", leave the default check box checked and click OK button. If you want to define which user are allowed to remote access, you can define it at the Select Users... button.

4) To disable remote access, select "Don't allow remote connections to this computer" and click OK button.

That's all for the configuration part and now you can try remote access to your Hyper-V Server.

1) From your server that hosted the Hyper-V Server, open up the remote desktop connection window.

Remote Desktop Connection Window

2) Fill in your Hyper-V Server's computer name and click connect.

Remote Desktop Connection - Windows Security Window

3) Fill up the necessary credentials and click OK button. You will then successfully access to your Hyper-V Server with remote access.

Wednesday, 23 July 2014

Configure Internet Access for Hyper-V in Windows Server 2012 R2

If you owned a Windows Server 2012 R2 and have Installed Windows Server 2012 R2 into your Hyper-V and want to have internet access, you may follow the following steps to setup the network configuration.

Step 1 : At Hyper-V Manager window click on Virtual Switch Manager... located at right side of the panel.

Hyper-V Manager Window

Step 2 : At Virtual Switch Manager window, select New virtual network switch on the left panel, select External on the right panel and click Create Virtual Switch.

Hyper-V Manager - Virtual Switch Manager for - New virtual network switch Selection

Step 3 : Fill in the name field with your desired name. Under Connection type category, select External network radio button and choose your LAN network card in the drop down menu. Leave the check box "Allow management operating system to share this network adapter" checked and click OK button.

Hyper-V Manager - Virtual Switch Manager for - External Selection

Step 4 : By now you will have one additional adapter in your Network Connections window Located at Control Panel\Network and Internet\Network Connections.

Network Connection - Network Adapter

Step 5 (Optional) : You will now need to enable Internet connection sharing by checking the option "Allow other network users to connect through this computer's Internet connection". Enable it from the adapter that have internet connection.

Network Connection - Network Adapter - Properties - Sharing Tab

Step 6 : Back to your Hyper-V Manager window. Right click on the virtual machine that you want to have internet connection and click Settings...

Settings for New Virtual Machine - Add Hardware

Step 7 : Select Add Hardware on the left panel, select Network Adapter at right panel and click Add button.

Settings for New Virtual Machine - Network Adapter

Step 8 : For your Virtual Switch drop down menu, select your created external network adapter that you have done in Step 2 and 3. Click on OK button. By now your virtual machine should have internet connection. If end up like the figure below or no internet connection, proceed to step 9.

Network Connection - Network Adapter - Network Connection Details Window


Step 9 : In your Virtual Machine, configure a static IP address for your adapter. Located at your adapter's properties > Internet Protocol Version 4 (TCP/IPv4) > Click Properties button. Set the Default gateway [192.168.137.1] (Since the shared internet connection pre-configure the IP address to be 192.168.137.1). Set Subnet mask [255.255.255.0]. Set IP address [192.168.137.XX] (XX - Any value other than 1). You may leave the DNS as blank or any of your desired DNS server. The figure below is using google DNS. After done fill up the fields, apply your settings by clicking on OK button. Now you will have Internet connection.

Network Connection - Network Adapter - Properties - Internet Protocol Version 4 (TCP/IPv4) Properties

That's all for the configuration.

Saturday, 19 July 2014

Publish Database Project from Microsoft Visual Studio 2013 to Microsoft SQL Server 2014 [Unable to connect to target server]

Update: This post also applies to solving issue for publishing database project to Microsoft SQL Server 2016.

You may have wanted to publish your database project to your newly installed Microsoft SQL Server 2014, but end up with this message "Unable to connect to target server". This is due to your current SQL Server Data Tools does not support publishing to SQL Server 2014. [Thanks to Sylvester Lee for pointing out that the current version Data Tools needs to update.] To solve this, you need to update your SQL Server Data Tools.

Visual Studio - Data Tools Operations Window

In your Visual Studio, navigate to your database project properties by right click on your database project and select properties. Select Project Settings tab. Under Target platform, check the drop down list whether it contain SQL Server 2014 selection. If it is not there, then you need to install SQL Server Data Tools.

Database Project - Properties - Project Settings Tab

Go to Extensions and Updates by select Tools at menu bar, which is located at the top of your Visual Studio window and click Extensions and Updates...

Visual Studio - TOOLS - Extensions and Updates Menu

At Extensions and Updates Window, select Updates tab and select Product Updates sub tab. At middle of the window, select Microsoft SQL Server Update for database... and click Update button.

Extensions and Updates Window

You will then be prompt to download SQL Server Data Tools.

View Downloads - Internet Explorer Window

Save it to keep a copy in your local machine to install it on a later date or run it immediately. The installation is pretty much straightforward and remember to read the terms and conditions before proceed with the installation.

Once you have done the installation, exit all your visual studio. Open back your project that contain the database project. You may have receive a prompt window to upgrade your project. Accept it by select OK button.

Review Project and Solution Changes Window

Check on the target platform at your database project properties. It should have contain SQL Server 2014 in the selection. Select the SQL Server 2014, save your properties and publish your project. By now your database project should be able to successfully publish to SQL Server 2014.


You may want to verify it in SQL Server Management Studio.


That all you have to do.

Thursday, 17 July 2014

Openfire BlowFish Encryption/Decryption Implementation Converted From Java to C#

Have you been using Openfire and requires to create XMPP users using C# but kind of unable to encrypt/decrypt the password? Openfire is actually using blowfish for encryption/decryption of password and you can pretty much find a few blowfish implementation on C# out there. But when you actually tried to decrypt the password obtained from the Openfire database, you will notice that you will not be able to obtain the original password. This is due to Openfire implementation of blowfish is different.

So to deal with this, I have converted the blowfish class from the Openfire source project, which is in java language and you can obtain from here http://www.igniterealtime.org/downloads/source.jsp.

It is actually pretty simple to use.

Initialize with key.
Blowfish blowfish = new Blowfish("Your Key Here");

Encrypt plain text.
string cipherText = blowfish.encryptString("Your Plain Text Here");

Decrypt cipher text.
string plainText = blowfish.decryptString("Your Cipher Text Here");

Do take note that the encrypted text will always be different, but it will still be able to decrypt back to the original text.

Here's the source file in C# https://onedrive.live.com/redir?resid=E6612168B803803D!353&authkey=!AA3SEAg16NdoiZ0&ithint=file%2czip

Tuesday, 1 July 2014

Self Define Data Type for Each Columns from Reading Text Files with Schema.ini using OleDB in C# & VB

Have you been using Oledb to read text files and come across a situation where you want to define each of the columns data types instead of letting it auto define for you. You can actually use a file called Schema.ini and place it in the same folder with the text file that you want to read.

Here's what your schema.ini should contain.

- File name including extension but excludes folder path. The file name is enclosed in a square bracket.
- Whether your file contain header or only data.
- The file format type [csv, tab, etc...]
- The list of columns and its data type.

So let's say in a case where you want all your data types to be in a string format, it will look like the following in your schema.ini.

[Tables.csv]
ColNameHeader=True
Format=CSVDelimited
Col1="Description" Text
Col2=Red Text
Col3=Green Text
Col4=Blue Text

The column defined are in sequences from left to right based on the columns in your text file. So if you did not specify the column sequence correctly, then schema.ini will define the data type wrongly. Also, The column name need to be enclosed in double quotation if it contains a space.

Once finish construct the schema.ini, place it together with the text file that you going to read. Then just read your text file like what you normally did with Oledb. You will notice that the value obtained for each columns are in string.

The following are the code for reading the comma delimited file with header and display it out. It will loop through the comma delimited file content and populate it to the Table class.

[C#]
static void Main(string[] args)
{
    var tables = ListTables(Path.Combine(Environment.CurrentDirectory, "TestFile", "Tables.csv"));

    foreach (var table in tables)
    {
        Console.WriteLine(string.Format("Description: {0}", table.Description));
        Console.WriteLine(string.Format("Red: {0}", table.Red));
        Console.WriteLine(string.Format("Green: {0}", table.Green));
        Console.WriteLine(string.Format("Blue: {0}\n", table.Blue));
    }
    Console.ReadKey();
}


private static List<Table> ListTables(string fileName)
{
    var tables = new List<Table>();
    var fileInfo = new FileInfo(fileName);
    const string SQL_STATEMENT = "SELECT * FROM [{0}]";

    using (var con = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='text; HDR=YES;'", fileInfo.DirectoryName)))
    {
        con.Open();

        using (var cmd = new OleDbCommand(string.Format(SQL_STATEMENT, fileInfo.Name), con))
        {
            using (var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    var table = new Table();
                    table.Description = reader.GetValue(reader.GetOrdinal("Description")).ToString();
                    table.Red = reader.GetValue(reader.GetOrdinal("Red")).ToString();
                    table.Green = reader.GetValue(reader.GetOrdinal("Green")).ToString();
                    table.Blue = reader.GetValue(reader.GetOrdinal("Blue")).ToString();

                    tables.Add(table);
                }
            }
        }
    }
    return tables;
}

[VB]
Sub Main()
    Dim tables As List(Of Table) = ListTables(Path.Combine(Environment.CurrentDirectory, "TestFile", "Tables.csv"))

    For Each table As Table In tables
        Console.WriteLine(String.Format("Description: {0}", table.Description))
        Console.WriteLine(String.Format("Red: {0}", table.Red))
        Console.WriteLine(String.Format("Green: {0}", table.Green))
        Console.WriteLine(String.Format("Blue: {0}" + Environment.NewLine, table.Blue))
    Next
    Console.ReadKey()
End Sub


Private Function ListTables(ByVal fileName As String) As List(Of Table)
    Dim tables As List(Of Table) = New List(Of Table)
    Dim fileInfo As FileInfo = New FileInfo(fileName)
    Const SQL_STATEMENT As String = "SELECT * FROM [{0}]"

    Using con As OleDbConnection = New OleDbConnection(String.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='text; HDR=YES;'", fileInfo.DirectoryName))
            con.Open()

        Using cmd As OleDbCommand = New OleDbCommand(String.Format(SQL_STATEMENT, fileInfo.Name), con)
            Using reader As OleDbDataReader = cmd.ExecuteReader()
                While reader.Read
                    Dim table As Table = New Table()
                    table.Description = reader.GetValue(reader.GetOrdinal("Description")).ToString()
                    table.Red = reader.GetValue(reader.GetOrdinal("Red")).ToString()
                    table.Green = reader.GetValue(reader.GetOrdinal("Green")).ToString()
                    table.Blue = reader.GetValue(reader.GetOrdinal("Blue")).ToString()

                    tables.Add(table)
                End While
            End Using
        End Using
    End Using
    Return tables
End Function

This example is just to demonstrate how you can define each of the columns' data type. It is advisable to define a correct data type for the column, so that you don't have to do unnecessary data conversion.

If you get hit with the error "The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.". Please install Microsoft Access Database Engine 2010 x86.

More on how to construct your own Schema.ini can be found on the following link : http://msdn.microsoft.com/en-us/library/ms709353(VS.85).aspx

Source code can be obtained here: https://onedrive.live.com/redir?resid=E6612168B803803D!355&authkey=!AOcpGnFSW310zJ0&ithint=file%2czip

Github: https://github.com/Jaryllan/Demonstration-Oledb-With-Schema