Was writing some XSLT for an Umbraco site recently, needed a copyright block in the footer so thought i’d just use the standard

©

syntax to add the copyright symbol, ©. When I tried to save the file, I got an error that the xml was invalid.

Turns out that © is not allowed so I used the numeric value instead

©

which works a treat.

I wonder how many times this has caught people out!

Speak to Simon Steed about any of the topics discussed this site.

Ever had a long webpage with validation that fails on postback but returns the user to the top of the page instead of where you want them?

Annoying isnt it. Well in .Net Framework 2.0 (yes it’s been there a while now), you can use the property:

Page.MaintainScrollPositionOnPostBack = true;

Well this will force the user to be returned back to the last point they clicked i.e. could be a control, button, checkbox etc

Very useful and helps with improving the user experience, something we should all be striving for!

Speak to Simon Steed about any of the topics discussed this site.

Need to know which specific control posted back to your page? (Original article at http://geekswithblogs.net/mahesh/archive/2006/06/27/83264.aspx)

/// <summary>
 /// Tells us which control posted back
 /// </summary>
 /// <returns></returns>
 public Control getPostBackControlName()
 {
 Control control = null;
 //first we will check the "__EVENTTARGET" because if post back made by       the controls
 //which used "_doPostBack" function also available in Request.Form collection.
 string ctrlname = Page.Request.Params["__EVENTTARGET"];
 if (ctrlname != null && ctrlname != String.Empty)
 control = Page.FindControl(ctrlname);

 // if __EVENTTARGET is null, the control is a button type and we need to
 // iterate over the form collection to find it
 else
 {
 string ctrlStr = String.Empty;
 Control c = null;
 foreach (string ctl in Page.Request.Form)
 {
 //handle ImageButton they having an additional "quasi-property" in their Id which identifies
 //mouse x and y coordinates
 if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))
 {
 ctrlStr = ctl.Substring(0, ctl.Length - 2);
 c = Page.FindControl(ctrlStr);
 }
 else
 c = Page.FindControl(ctl);

 if (c is System.Web.UI.WebControls.Button || c is System.Web.UI.WebControls.ImageButton)
 {
 control = c;
 break;
 }
 }
 }
 return control;
 }

If you are using master pages, simply add this to the master.cs file and where you need to call the method use the following code:

MasterPage masterPage = (MasterPage)Page.Master; // where MasterPage is the class name
 Control rep = masterPage.getPostBackControlName();
 if (rep.Parent.Parent.ID == "rpRegion")// only if postback is the regions control
 GetSelectedRegion();
Speak to Simon Steed about any of the topics discussed this site.

Searching google turned up nothing on this so did some digging in MSDN and worked out a method of disabling all the style sheets, javascript etc to produce a text only page:

1/ Add a content block to your master page – i’ve called mine ‘cssContentHolder’

<asp:contentplaceholder id=”cssContentHolder” runat=”server”>
<link rel=”stylesheet” href=”css/master.css” type=”text/css” media=”all” />
<link href=”css/flyout.css” media=”screen” rel=”stylesheet” type=”text/css” />
<script src=”scripts/APIs/JQuery/JQuery-1.3.2.min.js” type=”text/javascript”></script>
<script src=”scripts/APIs/JQuery/Plugins/jquery-ui-1.7.1.custom.min.js” type=”text/javascript”></script>
</asp:contentplaceholder>

2/ In the markup, add a link button so the user can click it to remove the formatting

<asp:LinkButton  PostBackUrl=”#” ID=”textLink”  runat=”server” Text=”Text Only Version” onclick=”textLink_Click” ></asp:LinkButton>

3/ In the code behind, create an event handler for the button and add the following code

protected void textLink_Click(object sender, EventArgs e)
{
bool Hidden = Page.Master.FindControl(“cssContentHolder”).Visible ;
Page.Master.FindControl(“cssContentHolder”).Visible = !Hidden;
if (Hidden)
textLink.Text = “Switch to Graphical Version”;
else
textLink.Text = “Text Only Version”;
}

That’s it. When you click on the link, you will perform a postback to the server, get the state of the control and show/hide accordingly. It will also change the text so you can click back again.

Simple when you know how!

Using Javascript, another method to remove all the CSS but not update any link text etc is to call the following function:

function hideCSS(){
	if(document.getElementsByTagName){
		for(n=0;n<document.getElementsByTagName("link").length;n++){
			if(document.getElementsByTagName("link")[n].getAttribute){
				if(document.getElementsByTagName("link")[n].getAttribute("rel").indexOf("stylesheet")!=-1){
					document.getElementsByTagName("link")[n].disabled="disabled"
					}
				}
			}
		}
	}
Speak to Simon Steed about any of the topics discussed this site.

I recently had a problem on a job where no matter what we did, we could not control the left/right balance programmatically on two specific PC’s.

We tried using various methods:

  1. Windows Media player API
  2. DirectSound APi
  3. WinMM.dll
  4. Praying

None of them worked although you could control the balance using the Windows sound vol (sndvol.exe) program from the taskbar.

We decided to try and use the same method so out came Depends.exe and we loaded the sndvol.exe to see what libraries and methods it was loading. We discovered a likely method called mixerSetControlDetails() and promptly started to google it to discover how it worked.

The following example is the result. After a lot of searching for c# code samples, I found a chinese site that had a code listing that I could modify to possibly fix our problem.

Well to cut a long story very short (not much time today), I got it working and implemented into the project. The code is below so feel free to use as you wish.

SoundControl.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

class SoundControl
{
#region declarations

const int MAXPNAMELEN = 32;
const int MIXER_SHORT_NAME_CHARS = 16;
const int MIXER_LONG_NAME_CHARS = 64;

[Flags]
enum MIXERLINE_LINEF : uint
{
ACTIVE = 0x00000001,
DISCONNECTED = 0x00008000,
SOURCE = 0x80000000
}
[Flags]
enum MIXER : uint
{
GETLINEINFOF_DESTINATION = 0x00000000,
GETLINEINFOF_SOURCE = 0x00000001,
GETLINEINFOF_LINEID = 0x00000002,
GETLINEINFOF_COMPONENTTYPE = 0x00000003,
GETLINEINFOF_TARGETTYPE = 0x00000004,
GETLINEINFOF_QUERYMASK = 0x0000000F,

GETLINECONTROLSF_ALL = 0x00000000,
GETLINECONTROLSF_ONEBYID = 0x00000001,
GETLINECONTROLSF_ONEBYTYPE = 0x00000002,
GETLINECONTROLSF_QUERYMASK = 0x0000000F,

GETCONTROLDETAILSF_VALUE = 0x00000000,
GETCONTROLDETAILSF_LISTTEXT = 0x00000001,
GETCONTROLDETAILSF_QUERYMASK = 0x0000000F,

OBJECTF_MIXER = 0x00000000,
OBJECTF_WAVEOUT = 0x10000000,
OBJECTF_WAVEIN = 0x20000000,
OBJECTF_MIDIOUT = 0x30000000,
OBJECTF_MIDIIN = 0x40000000,
OBJECTF_AUX = 0x50000000,
OBJECTF_HANDLE = 0x80000000,
OBJECTF_HMIXER = OBJECTF_HANDLE | OBJECTF_MIXER,
OBJECTF_HWAVEOUT = OBJECTF_HANDLE | OBJECTF_WAVEOUT,
OBJECTF_HWAVEIN = OBJECTF_HANDLE | OBJECTF_WAVEIN,
OBJECTF_HMIDIOUT = OBJECTF_HANDLE | OBJECTF_MIDIOUT,
OBJECTF_HMIDIIN = OBJECTF_HANDLE | OBJECTF_MIDIIN
}
[Flags]
enum MIXERCONTROL_CT : uint
{
CLASS_MASK = 0xF0000000,
CLASS_CUSTOM = 0x00000000,
CLASS_METER = 0x10000000,
CLASS_SWITCH = 0x20000000,
CLASS_NUMBER = 0x30000000,
CLASS_SLIDER = 0x40000000,
CLASS_FADER = 0x50000000,
CLASS_TIME = 0x60000000,
CLASS_LIST = 0x70000000,

SUBCLASS_MASK = 0x0F000000,

SC_SWITCH_BOOLEAN = 0x00000000,
SC_SWITCH_BUTTON = 0x01000000,

SC_METER_POLLED = 0x00000000,

SC_TIME_MICROSECS = 0x00000000,
SC_TIME_MILLISECS = 0x01000000,

SC_LIST_SINGLE = 0x00000000,
SC_LIST_MULTIPLE = 0x01000000,

UNITS_MASK = 0x00FF0000,
UNITS_CUSTOM = 0x00000000,
UNITS_BOOLEAN = 0x00010000,
UNITS_SIGNED = 0x00020000,
UNITS_UNSIGNED = 0x00030000,
UNITS_DECIBELS = 0x00040000, /* in 10ths */
UNITS_PERCENT = 0x00050000, /* in 10ths */
}
[Flags]
enum MIXERCONTROL_CONTROLTYPE : uint
{
CUSTOM = MIXERCONTROL_CT.CLASS_CUSTOM | MIXERCONTROL_CT.UNITS_CUSTOM,
BOOLEANMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_BOOLEAN,
SIGNEDMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_SIGNED,
PEAKMETER = SIGNEDMETER + 1,
UNSIGNEDMETER = MIXERCONTROL_CT.CLASS_METER | MIXERCONTROL_CT.SC_METER_POLLED | MIXERCONTROL_CT.UNITS_UNSIGNED,
BOOLEAN = MIXERCONTROL_CT.CLASS_SWITCH | MIXERCONTROL_CT.SC_SWITCH_BOOLEAN | MIXERCONTROL_CT.UNITS_BOOLEAN,
ONOFF = BOOLEAN + 1,
MUTE = BOOLEAN + 2,
MONO = BOOLEAN + 3,
LOUDNESS = BOOLEAN + 4,
STEREOENH = BOOLEAN + 5,
BASS_BOOST = BOOLEAN + 0x00002277,
BUTTON = MIXERCONTROL_CT.CLASS_SWITCH | MIXERCONTROL_CT.SC_SWITCH_BUTTON | MIXERCONTROL_CT.UNITS_BOOLEAN,
DECIBELS = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_DECIBELS,
SIGNED = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_SIGNED,
UNSIGNED = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_UNSIGNED,
PERCENT = MIXERCONTROL_CT.CLASS_NUMBER | MIXERCONTROL_CT.UNITS_PERCENT,
SLIDER = MIXERCONTROL_CT.CLASS_SLIDER | MIXERCONTROL_CT.UNITS_SIGNED,
PAN = SLIDER + 1,
QSOUNDPAN = SLIDER + 2,
FADER = MIXERCONTROL_CT.CLASS_FADER | MIXERCONTROL_CT.UNITS_UNSIGNED,
VOLUME = FADER + 1,
BASS = FADER + 2,
TREBLE = FADER + 3,
EQUALIZER = FADER + 4,
SINGLESELECT = MIXERCONTROL_CT.CLASS_LIST | MIXERCONTROL_CT.SC_LIST_SINGLE | MIXERCONTROL_CT.UNITS_BOOLEAN,
MUX = SINGLESELECT + 1,
MULTIPLESELECT = MIXERCONTROL_CT.CLASS_LIST | MIXERCONTROL_CT.SC_LIST_MULTIPLE | MIXERCONTROL_CT.UNITS_BOOLEAN,
MIXER = MULTIPLESELECT + 1,
MICROTIME = MIXERCONTROL_CT.CLASS_TIME | MIXERCONTROL_CT.SC_TIME_MICROSECS | MIXERCONTROL_CT.UNITS_UNSIGNED,
MILLITIME = MIXERCONTROL_CT.CLASS_TIME | MIXERCONTROL_CT.SC_TIME_MILLISECS | MIXERCONTROL_CT.UNITS_UNSIGNED
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct MIXERLINE
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct TargetInfo
{
public uint dwType;
public uint dwDeviceID;
public ushort wMid;
public ushort wPid;
public uint vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXPNAMELEN)]
public string szPname;
}

public uint cbStruct;
public uint dwDestination;
public uint dwSource;
public uint dwLineID;
public MIXERLINE_LINEF fdwLine;
public uint dwUser;
public uint dwComponentType;
public uint cChannels;
public uint cConnection;
public uint cControls;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_SHORT_NAME_CHARS)]
public string szShortName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_LONG_NAME_CHARS)]
public string szName;
public TargetInfo Target;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct MIXERCONTROL
{
[StructLayout(LayoutKind.Explicit)]
public struct BoundsInfo
{
[FieldOffset(0)]
public int lMinimum;
[FieldOffset(4)]
public int lMaximum;
[FieldOffset(0)]
public uint dwMinimum;
[FieldOffset(4)]
public uint dwMaximum;
[FieldOffset(8), MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public uint[] dwReserved;
}
[StructLayout(LayoutKind.Explicit)]
public struct MetricsInfo
{
[FieldOffset(0)]
public uint cSteps;
[FieldOffset(0)]
public uint cbCustomData;
[FieldOffset(4), MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public uint[] dwReserved;
}

public uint cbStruct;
public uint dwControlID;
public MIXERCONTROL_CONTROLTYPE dwControlType;
public uint fdwControl;
public uint cMultipleItems;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_SHORT_NAME_CHARS)]
public string szShortName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MIXER_LONG_NAME_CHARS)]
public string szName;
public BoundsInfo Bounds;
public MetricsInfo Metrics;
}
[StructLayout(LayoutKind.Explicit)]
struct MIXERLINECONTROLS
{
[FieldOffset(0)]
public uint cbStruct;
[FieldOffset(4)]
public uint dwLineID;
[FieldOffset(8)]
public uint dwControlID;
[FieldOffset(8)] // not a typo! overlaps previous field
public uint dwControlType;
[FieldOffset(12)]
public uint cControls;
[FieldOffset(16)]
public uint cbmxctrl;
[FieldOffset(20)]
public IntPtr pamxctrl;
}
[StructLayout(LayoutKind.Explicit)]
struct MIXERCONTROLDETAILS
{
[FieldOffset(0)]
public uint cbStruct;
[FieldOffset(4)]
public uint dwControlID;
[FieldOffset(8)]
public uint cChannels;
[FieldOffset(12)]
public IntPtr hwndOwner;
[FieldOffset(12)] // not a typo!
public uint cMultipleItems;
[FieldOffset(16)]
public uint cbDetails;
[FieldOffset(20)]
public IntPtr paDetails;
}
[StructLayout(LayoutKind.Sequential)]
struct VOLUME
{
public int left;
public int right;
}
struct MixerInfo
{
public uint volumeCtl;
public uint muteCtl;
public int minVolume;
public int maxVolume;
}

[DllImport("WinMM.dll", CharSet = CharSet.Auto)]
static extern uint mixerGetLineInfo(IntPtr hmxobj, ref MIXERLINE pmxl, MIXER flags);

[DllImport("WinMM.dll", CharSet = CharSet.Auto)]
static extern uint mixerGetLineControls(IntPtr hmxobj, ref MIXERLINECONTROLS pmxlc, MIXER flags);

[DllImport("WinMM.dll", CharSet = CharSet.Auto)]
static extern uint mixerGetControlDetails(IntPtr hmxobj, ref MIXERCONTROLDETAILS pmxcd, MIXER flags);

[DllImport("WinMM.dll", CharSet = CharSet.Auto)]
static extern uint mixerSetControlDetails(IntPtr hmxobj, ref MIXERCONTROLDETAILS pmxcd, MIXER flags);

#endregion declarations

#region private methods

static MixerInfo GetMixerControls()
{
MIXERLINE mxl = new MIXERLINE();
MIXERLINECONTROLS mlc = new MIXERLINECONTROLS();
mxl.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERLINE));
mlc.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERLINECONTROLS));

mixerGetLineInfo(IntPtr.Zero, ref mxl, MIXER.OBJECTF_MIXER | MIXER.GETLINEINFOF_DESTINATION);

mlc.dwLineID = mxl.dwLineID;
mlc.cControls = mxl.cControls;
mlc.cbmxctrl = (uint)Marshal.SizeOf(typeof(MIXERCONTROL));
mlc.pamxctrl = Marshal.AllocHGlobal((int)(mlc.cbmxctrl * mlc.cControls));

mixerGetLineControls(IntPtr.Zero, ref mlc, MIXER.OBJECTF_MIXER | MIXER.GETLINECONTROLSF_ALL);

MixerInfo rtn = new MixerInfo();

for (int i = 0; i < mlc.cControls; i++)
{
MIXERCONTROL mxc = (MIXERCONTROL)Marshal.PtrToStructure((IntPtr)((int)mlc.pamxctrl + (int)mlc.cbmxctrl * i), typeof(MIXERCONTROL));
switch (mxc.dwControlType)
{
case MIXERCONTROL_CONTROLTYPE.VOLUME:
rtn.volumeCtl = mxc.dwControlID;
rtn.minVolume = mxc.Bounds.lMinimum;
rtn.maxVolume = mxc.Bounds.lMaximum;
break;
case MIXERCONTROL_CONTROLTYPE.MUTE:
rtn.muteCtl = mxc.dwControlID;
break;
}
}

Marshal.FreeHGlobal(mlc.pamxctrl);

return rtn;
}
static VOLUME GetVolume(MixerInfo mi)
{
MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS();
mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS));
mcd.dwControlID = mi.volumeCtl;
mcd.cMultipleItems = 0;
mcd.cChannels = 2;
mcd.cbDetails = (uint)Marshal.SizeOf(typeof(VOLUME));
mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails);

mixerGetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER);

VOLUME rtn = (VOLUME)Marshal.PtrToStructure(mcd.paDetails, typeof(VOLUME));

Marshal.FreeHGlobal(mcd.paDetails);

return rtn;
}
static bool IsMuted(MixerInfo mi)
{
MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS();
mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS));
mcd.dwControlID = mi.muteCtl;
mcd.cMultipleItems = 0;
mcd.cChannels = 1;
mcd.cbDetails = 4;
mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails);

mixerGetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER);

int rtn = Marshal.ReadInt32(mcd.paDetails);

Marshal.FreeHGlobal(mcd.paDetails);

return rtn != 0;
}

static void MuteIt(MixerInfo mi, bool left, bool right)
{
VOLUME volume = GetVolume(mi);
if (!left && !right) // mute off
{
volume.left = 65530;
volume.right = 65530;
}
else if (left) //mute left channel
{
volume.left = 0;
volume.right = 65530;
}
else if (right) // mute right channel
{
volume.left = 65530;
volume.right = 0;
}

SetVolume(mi, volume);
}

static void SetVolume(MixerInfo mi, VOLUME volume)
{
MIXERCONTROLDETAILS mcd = new MIXERCONTROLDETAILS();
mcd.cbStruct = (uint)Marshal.SizeOf(typeof(MIXERCONTROLDETAILS));
mcd.dwControlID = mi.volumeCtl;
mcd.cMultipleItems = 0;
mcd.cChannels = 2;
mcd.cbDetails = (uint)Marshal.SizeOf(typeof(VOLUME));
mcd.paDetails = Marshal.AllocHGlobal((int)mcd.cbDetails);

Marshal.StructureToPtr(volume, mcd.paDetails, false);

mixerSetControlDetails(IntPtr.Zero, ref mcd, MIXER.GETCONTROLDETAILSF_VALUE | MIXER.OBJECTF_MIXER);

Marshal.FreeHGlobal(mcd.paDetails);
}

#endregion private methods

#region public methods

/// <summary>
/// Mutes the left hand channel and transfers audio fully to the right
/// </summary>
public void MuteLeftChannel()
{
MixerInfo mi = GetMixerControls();
MuteIt(mi, false, true);
}

/// <summary>
/// Mutes the right hand channel and transfers audio fully to the left
/// </summary>
public void MuteRightChannel()
{
MixerInfo mi = GetMixerControls();
MuteIt(mi, true, false);
}

public void MuteOff()
{
MixerInfo mi = GetMixerControls();
MuteIt(mi, false, false);
}

#endregion public methods
}

You call it as follows:

private void CreateSoundControl()
{
if (sndMute != null) return;
sndMute = new SoundControl();
}

private void btnRight_Click(object sender, EventArgs e)
{
CreateSoundControl();
sndMute.MuteRightChannel();
}

private void btnLeft_Click(object sender, EventArgs e)
{
CreateSoundControl();
sndMute.MuteLeftChannel();
}

private void btnCenter_Click(object sender, EventArgs e)
{
CreateSoundControl();
sndMute.MuteOff();

}

Download the source files here

Enjoy – remember if your machine blows up or crashes, do not blame me :)

Speak to Simon Steed about any of the topics discussed this site.

URL Rewriting in asp.net (c#). (Download Example Project for URL Rewriting in asp.net at the end of this article)

One way to get yourselves rated better in the search engines is to get rid of the basic aspx page and replace it with something much more descriptive i.e.:

If I were selling Nokia phones, I may have a page called http://www.mydomain.com/nokia.aspx – not much good if I am trying to target a specific phone though is it? What about this then?

http://www.mydomain.com/Nokia-E71-Mobile-Phone-With-Email-And-Internet-Browser

Much more descriptive and much more likely to get the search engines juices flowing more and hence get you rated higher in the listings.

After searching around for a few solutions, I found this article by Scott GU (Microsoft Guru Extraordinaire) http://weblogs.asp.net/scottgu/archive/2007/02/26/tip-trick-url-rewriting-with-asp-net.aspx which got me excited.

He mentions a few methods, one of which I use on http://www.simonantony.co.uk which is running IIS7 by using the Rewrite module built into IIS – works a treat and has allowed me to convert a static html site into a more dynamic and search engine friendly version.

The other is to use a library from http://urlrewriter.net/ which is the other route I have taken. I’ve successfully implemented this on a project I am currently working upon and thought it would be nice of me to post some fully working example code that you can actually understand – the examples on the urlrewriter website/demos are very poor and not clear at all – no wonder so many people struggle to get it working.

Some blurb from the URLRewriting website will explain it more:

UrlRewriter.NET is an open-source, light-weight, highly configurable URL rewriting component for ASP.NET 1.1 and 2.0. UrlRewriter.NET provides similar IIS Rewrite capabilities that the Apache web server provides with mod_rewrite and .htaccess. You don’t need to install an ISAPI Rewrite filter to use the component. Best of all, UrlRewriter.NET is free and licensed with a very permissive MIT-style licence.

UrlRewriter.NET is a great Search Engine Optimization (SEO) tool. Using UrlRewriter.NET, you can create URL’s containing your target keywords, boosting your rankings.

With UrlRewriter.NET, you can:

* Rewrite URL’s from “user and Search Engine” friendly urls to the actual .aspx pages (also known as URL Masking, IIS Rewrite or ASP Rewrite)
* Redirect from old URL patterns to the new ones, ensuring the Search Engine spiders continue to follow your links (also known as URL Replace)
* Block certain visitors based on the User-Agent – very helpful for blocking crawlers that don’t obey the robots.txt protocol
* Ban users based on IP range (provides the capabilities of mod_rewrite on IIS)
* And much more…

UrlRewriter.NET is a pure .NET component written in C#, and does not require any ISAPI rewrite dll’s to be installed in IIS. You configure rules in a very readable XML format, either in your web.config file or an external rewriter configuration file.

UrlRewriter.NET is in use in many websites large and small such as DotNetKicks, and is embedded in several open source packages, such as the fantastic Yet Another Forum.NET.

Anyway here is how the project is constructed and how to get it working.

  1. Create a new web project – I am using C# but if you really want to you can use VB
  2. Download the urlrewriting library from the official site http://urlrewriter.net
  3. Add a reference to the UrlRewritingNet.UrlRewriter.dll to your project
  4. Open up the web.config file and replace the content with the following code:

<?xml version=”1.0″?>
<configuration>
<configSections>
<section name=”urlrewritingnet” requirePermission=”false”  type=”UrlRewritingNet.Configuration.UrlRewriteSection, UrlRewritingNet.UrlRewriter”  />
</configSections>

<urlrewritingnet
rewriteOnlyVirtualUrls=”true”
contextItemsPrefix=”QueryString”
defaultPage=”default.aspx”
defaultProvider=”RegEx”
xmlns=”http://www.urlrewriting.net/schemas/config/2006/07″ >
<rewrites>
<add name=”this-is-a-long-page-name”  virtualUrl=”^~/this-is-a-long-page-name”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”~/longpage.aspx”
ignoreCase=”true” />

<add name=”Product-Search-uk”  virtualUrl=”^~/Product-Search-uk”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”~/search.aspx”
ignoreCase=”true” />

<add name=”submit-your-company”  virtualUrl=”^~/submit-your-company”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”~/submit_company.aspx”
ignoreCase=”true” />

<add name=”this-is-my-site-blog”  virtualUrl=”^~/this-is-my-site-blog”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”~/blog.aspx”
ignoreCase=”true” />

<add name=”contact-my-company”  virtualUrl=”^~/contact-my-company”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”~/contact.aspx”
ignoreCase=”true” />

<add name=”Product-Search-uk-partnumber”  virtualUrl=”^~/product(.*).aspx”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”~/search.aspx?id=$1″
ignoreCase=”true” />

<!–<add name=”Rewrite”  virtualUrl=”^~/(.*)/Detail(.*).aspx”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”~/Default.aspx?language=$1&amp;id=$2″
ignoreCase=”true” />

<add name=”RedirectInApplication”  virtualUrl=”^~/(.*)/Default.aspx”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”~/$1/Detail_Redirected.aspx”
redirect=”Application”
redirectMode=”Permanent”
ignoreCase=”true” />

<add name=”KickBrowserToDomain”  virtualUrl=”^http\://(.*)/SampleWeb/kickto/(.*).aspx”
rewriteUrlParameter=”ExcludeFromClientQueryString”
destinationUrl=”http://$2?source=$1″
redirect=”Domain”
redirectMode=”Permanent”
ignoreCase=”true” />–>
</rewrites>
</urlrewritingnet>

<appSettings/>
<system.web>
<customErrors mode=”Off”>
</customErrors>
<httpModules>
<add name=”UrlRewriteModule” type=”UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter” />
</httpModules>
<compilation debug=”true” />
</system.web>
</configuration>

    • Create the aspx pages
      1. blog.aspx
      2. contact.aspx
      3. default.aspx (this should already exist)
      4. longpage.aspx
      5. search.aspx
      6. submit_company.aspx
        • In Default.aspx add the following code:

          <div id=”nav”>
          <div id=”navcontainer”>
          <ul id=”navlist”>
          <li><a href=”default.aspx”>Home</a></li>
          <li><a href=”this-is-a-long-page-name”>this-is-a-long-page-name</a></li>
          <li><a href=”Product-Search-uk”>Product Search</a></li>
          <li><a href=”submit-your-company”>Submit your company</a></li>
          <li><a href=”this-is-my-site-blog”>Blog</a></li>
          <li><a href=”contact-my-company”>Contact</a></li>
          <li><a href=”product123.aspx”>Note that this aspx page does not actually exist – click it and see what happens</a></li>

          </ul>
          </div>
          </div>

          You will notice that the href links are defined in the web.config file.

            • In search.aspx, add the following html code:

              <div>
              This is the region page – if you click on <a href=”product12345.aspx”>product12345.aspx</a>, you will be redirected here but the code will show the arguments of the page i.e. 12345 – confused? You will be!

              </div>

                • Now open up the code behind file for search.aspx and add in the Page_Load event:

                  if(Request.QueryString["id"] != null)
                  Response.Write(“querystring passed in: ” + Request.QueryString["id"]);
                  else
                  Response.Write(“No query string passed in”);

                    • Run the project. If you click on the search link, you will be taken to the search page but notice the URL in the browser window as it should be reading Product-Search-UK. Same for the other url’s as well except for the last one, if you click on that, a product id will be passed into the page as a querystring that you can use to display specific products on a single page – clever eh!

                      Anyway I hope this has helped you understand how to get a basic implementation of URL Rewriting in your site – i’d love to hear of any more examples you have used, if you want to post them here let me know.

                      Si

                      Download Example Project for URL Rewriting in asp.net

                      Speak to Simon Steed about any of the topics discussed this site.

                      Today the Prime Minister Gordon Brown visited Manchester based company EDM Ltd. He was shown around the factory by the staff members and had a hands on with some of the training simulators that the company produces and then went on to present an hour long seminar on business and export.

                      Mr Brown visited the site due to the strong exports that the company produces, especially in these trying times. EDM exports strongly all over the world with their trainer systems and the MD Kevin Bird has recently returned from a trip to China to secure more business in the coming weeks.

                      Mr Brown was particularly interested in the railway simulator recently purchased by Northern Ireland Railways and also the Continental Boeing 787 dreamliner door trainer systems – both of which Simon Steed (author) actually worked upon and helped design the software.

                      The railway simulator uses touch screen technology to provide a means to train signallers on railway operations. The door trainers provide means to train cabin crew in the operation of the various parts of the aircraft, primarily door operation but also cabin procedures etc.

                      All the software was written using the Microsoft Dotnet framework by EDM

                      Gordon Brown arriving at EDM with his entourageGordon Brown arrives at EDM

                      Quoted from the Number 10 website:

                      Thursday 12 March 2009

                      PM pledges support for exporters

                      Gordon Brown in Manchester - PA copyrightThe Prime Minister has pledged more support for British exporters to help expansion into new foreign markets during the downturn.

                      The Government plans to provide specialist and tailored financial and legal advice to over 1,200 businesses in the coming year.

                      The PM said that although times are tough, opportunities for new export growth still exist.

                      “There are still markets for British goods if we help businesses access them. That is why it is vital we give British businesses world class support to make the most of global opportunities and increase their activity in overseas markets.”

                      Gordon Brown and the Minister for Trade and Investment, Lord Davies, spoke to 100 of the North West’s largest business exporters this morning.

                      The PM said that a recent survey found companies that export tend to be more resilient in a downturn. He said 42% of exporters increased their turnover in the past 12 months, compared with only 23% overall.

                      But Lord Davies said small and medium businesses needed to continue to be flexible and innovative to seek out new export opportunities.

                      “Small businesses can find it hard to break into new markets on their own and UKTI is there to help. The £3.5 million programme ‘Gateway to Global Growth’ will start from April helping SMEs to access foreign markets where they see potential for their business.”

                      The Prime Minister’s visit coincided with the launch of the Real Help Now guide for the North West.

                      http://www.number10.gov.uk/Page18581

                      Speak to Simon Steed about any of the topics discussed this site.

                      Add META keywords and Description in ASP.NET

                      Here is the syntax for programmatically adding META tags to an ASP.NET 2.0 page.

                      HtmlMeta metaDesc = new HtmlMeta();

                      metaDesc.Name = “description”;

                      metaDesc.Content = “Tips on roasting coffee at home”;

                      Page.Header.Controls.Add(metaDesc);

                      HtmlMeta metaKey = new HtmlMeta();

                      metaKey.Name = “keywords”;

                      metaKey.Content = “roast, coffee, home, tips”;

                      Page.Header.Controls.Add(metaKey);

                      ASP.NET will render the above code to valid XHTML META tags.

                      via Add META keywords and Description in ASP.NET (DigitalColony.com).

                      Speak to Simon Steed about any of the topics discussed this site.

                      My previous article which you can find at http://blog.xploiter.com/index.php/2009/01/16/socket-programming-in-c-using-the-built-in-libraries-a-fully-working-production-example-part-1/ covered the creation of a solid production ready Socket Server written in C#. I promised to follow up with part 2 which would be a suitable client so without further ado, here we go:

                      App.Config

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

                      <configuration>

                      <appSettings>

                      <add key=ServerIP value=127.0.0.1 />

                      <add key=ServerPort value=10001 />

                      </appSettings>

                      </configuration>

                      This time we define the server IP Address we wish to connect to as well as the port to use.

                      ExceptionHandler.CS

                      using System;

                      using System.Collections.Generic;

                      using System.Linq;

                      using System.Text;

                      using System.Data;

                      using System.Data.SqlClient;

                      using System.Windows;

                      namespace SocketClient

                      {

                      ///

                      /// Handles displaying error messages

                      ///

                      public class ExceptionHandler

                      {

                      ///

                      /// Takes the exception message and displays a meaningful message to the user

                      ///

                      public static string DisplayMessage(Exception ex)

                      {

                      return DisplayMessage(ex, “”);

                      }

                      ///

                      /// Takes the exception message and displays a meaningful message to the user

                      ///

                      /// The exception to display.

                      /// Current User

                      //[System.Diagnostics.DebuggerStepThrough()]

                      public static string DisplayMessage(Exception ex, string userName)

                      {

                      StringBuilder sb = new StringBuilder();

                      if (ex is DBConcurrencyException)

                      sb.Append(“Concurrency Error: One or more people have updated this data since your last request.”);

                      else if (ex is SqlException)

                      {

                      sb.Append(“Database Error: “);

                      switch (((SqlException)ex).Number)

                      {

                      case 547:

                      sb.Append(“There is a constraint on the items you tried to modify. Please try again.”);

                      break;

                      case 2601:

                      // Unique Index

                      sb.Append(“Cannot insert duplicate values into the database.”);

                      break;

                      case 2627:

                      // Unique Constraint

                      sb.Append(“Cannot insert duplicate values into the database.”);

                      break;

                      default:

                      sb.Append(ex.Message);

                      break;

                      }

                      }

                      else

                      {

                      sb.Append(“Exception Handler Unexpected Error: “ + ex.Message);

                      }

                      string nl = “\n\n”;

                      sb.Append(nl + “Exception Information:” + nl);

                      sb.Append(“Message: “ + ex.Message + nl);

                      sb.Append(“Source: “ + ex.Source + nl);

                      sb.Append(“Stack Trace: “ + ex.StackTrace + nl);

                      if (ex.InnerException != null)

                      {

                      sb.Append(nl + “Inner Exception Info:” + nl);

                      sb.Append(“Message: “ + ex.InnerException.Message + nl);

                      sb.Append(“Source: “ + ex.InnerException.Source + nl);

                      sb.Append(“Stack Trace: “ + ex.InnerException.StackTrace + nl);

                      }

                      return sb.ToString();

                      }

                      }

                      }

                      Same as the SocketServer code.

                      SocketClient.cs

                      using System;

                      using System.Windows.Forms;

                      using System.Net;

                      using System.Net.Sockets;

                      using System.Diagnostics;

                      using System.Collections;

                      using System.ComponentModel;

                      using System.Collections.Generic;

                      using System.Reflection;

                      using System.Data;

                      using System.Drawing;

                      using System.Linq;

                      using System.Text;

                      using System.Threading;

                      using System.IO;

                      using Microsoft.VisualBasic;

                      using System.Configuration;

                      namespace SocketClient

                      {

                      /// <summary>

                      /// Description of SocketClient.

                      /// </summary>

                      public class Client : System.Windows.Forms.Form

                      {

                      #region private members

                      byte[] m_dataBuffer = new byte[10];

                      IAsyncResult m_result;

                      public AsyncCallback m_pfnCallBack;

                      private System.Windows.Forms.Timer timerAlive;

                      private System.ComponentModel.IContainer components;

                      private int _ServerSocketID = -1;

                      public Socket m_clientSocket;

                      bool isClosing = false;

                      Int16 _Port = 10001; // default port we listen on

                      string _ServerIP = “127.0.0.1″;

                      private GroupBox groupBox1;

                      private Button buttonConnect;

                      private Button button1;

                      private TextBox textBoxMsg;

                      private Button buttonDisconnect;

                      private Button btnSendMessage;

                      private Label label4;

                      private RichTextBox richTextRxMessage;

                      private System.Windows.Forms.Timer tmrServerCheck;

                      // This delegate enables asynchronous calls for setting

                      // the text property on a TextBox control.

                      delegate void AppendTextCallback(string text);

                      delegate void DisconnectCallback();

                      #endregion private members

                      #region constructor

                      public Client()

                      {

                      //

                      // The InitializeComponent() call is required for Windows Forms designer support.

                      //

                      InitializeComponent();

                      _ServerIP = ConfigurationManager.AppSettings[“ServerIP”];

                      _Port = Convert.ToInt16(ConfigurationManager.AppSettings[“ServerPort”]);

                      }

                      [STAThread]

                      public static void Main(string[] args)

                      {

                      Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

                      Application.Run(new Client());

                      }

                      private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)

                      {

                      WriteToLogFile(ExceptionHandler.DisplayMessage(e.Exception));

                      MessageBox.Show(ExceptionHandler.DisplayMessage(e.Exception));

                      }

                      #endregion constructor

                      #region Windows Forms Designer generated code

                      /// <summary>

                      /// This method is required for Windows Forms designer support.

                      /// Do not change the method contents inside the source code editor. The Forms designer might

                      /// not be able to load this method if it was changed manually.

                      /// </summary>

                      private void InitializeComponent()

                      {

                      this.components = new System.ComponentModel.Container();

                      this.timerAlive = new System.Windows.Forms.Timer(this.components);

                      this.groupBox1 = new System.Windows.Forms.GroupBox();

                      this.buttonConnect = new System.Windows.Forms.Button();

                      this.button1 = new System.Windows.Forms.Button();

                      this.textBoxMsg = new System.Windows.Forms.TextBox();

                      this.buttonDisconnect = new System.Windows.Forms.Button();

                      this.btnSendMessage = new System.Windows.Forms.Button();

                      this.label4 = new System.Windows.Forms.Label();

                      this.richTextRxMessage = new System.Windows.Forms.RichTextBox();

                      this.tmrServerCheck = new System.Windows.Forms.Timer(this.components);

                      this.groupBox1.SuspendLayout();

                      this.SuspendLayout();

                      //

                      // timerAlive

                      //

                      this.timerAlive.Interval = 10000;

                      this.timerAlive.Tick += new System.EventHandler(this.timerAlive_Tick);

                      //

                      // groupBox1

                      //

                      this.groupBox1.Controls.Add(this.buttonConnect);

                      this.groupBox1.Controls.Add(this.button1);

                      this.groupBox1.Controls.Add(this.textBoxMsg);

                      this.groupBox1.Controls.Add(this.buttonDisconnect);

                      this.groupBox1.Controls.Add(this.btnSendMessage);

                      this.groupBox1.Controls.Add(this.label4);

                      this.groupBox1.Controls.Add(this.richTextRxMessage);

                      this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;

                      this.groupBox1.Location = new System.Drawing.Point(0, 0);

                      this.groupBox1.Name = “groupBox1″;

                      this.groupBox1.Size = new System.Drawing.Size(446, 159);

                      this.groupBox1.TabIndex = 18;

                      this.groupBox1.TabStop = false;

                      this.groupBox1.Text = “Client Setup”;

                      //

                      // buttonConnect

                      //

                      this.buttonConnect.BackColor = System.Drawing.SystemColors.HotTrack;

                      this.buttonConnect.Font = new System.Drawing.Font(“Tahoma”, 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                      this.buttonConnect.ForeColor = System.Drawing.Color.Yellow;

                      this.buttonConnect.Location = new System.Drawing.Point(12, 19);

                      this.buttonConnect.Name = “buttonConnect”;

                      this.buttonConnect.Size = new System.Drawing.Size(85, 48);

                      this.buttonConnect.TabIndex = 38;

                      this.buttonConnect.Text = “Connect To Server”;

                      this.buttonConnect.UseVisualStyleBackColor = false;

                      this.buttonConnect.Click += new System.EventHandler(this.ButtonConnectClick);

                      //

                      // button1

                      //

                      this.button1.Location = new System.Drawing.Point(139, 124);

                      this.button1.Name = “button1″;

                      this.button1.Size = new System.Drawing.Size(49, 24);

                      this.button1.TabIndex = 35;

                      this.button1.Text = “Clear”;

                      this.button1.Click += new System.EventHandler(this.btnClear_Click);

                      //

                      // textBoxMsg

                      //

                      this.textBoxMsg.Location = new System.Drawing.Point(7, 98);

                      this.textBoxMsg.Name = “textBoxMsg”;

                      this.textBoxMsg.Size = new System.Drawing.Size(181, 20);

                      this.textBoxMsg.TabIndex = 33;

                      this.textBoxMsg.Tag = “”;

                      //

                      // buttonDisconnect

                      //

                      this.buttonDisconnect.BackColor = System.Drawing.Color.Red;

                      this.buttonDisconnect.Font = new System.Drawing.Font(“Tahoma”, 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                      this.buttonDisconnect.ForeColor = System.Drawing.Color.Yellow;

                      this.buttonDisconnect.Location = new System.Drawing.Point(12, 19);

                      this.buttonDisconnect.Name = “buttonDisconnect”;

                      this.buttonDisconnect.Size = new System.Drawing.Size(85, 48);

                      this.buttonDisconnect.TabIndex = 32;

                      this.buttonDisconnect.Text = “Disconnect From Server”;

                      this.buttonDisconnect.UseVisualStyleBackColor = false;

                      this.buttonDisconnect.Visible = false;

                      this.buttonDisconnect.Click += new System.EventHandler(this.ButtonDisconnectClick);

                      //

                      // btnSendMessage

                      //

                      this.btnSendMessage.Enabled = false;

                      this.btnSendMessage.Location = new System.Drawing.Point(80, 124);

                      this.btnSendMessage.Name = “btnSendMessage”;

                      this.btnSendMessage.Size = new System.Drawing.Size(49, 24);

                      this.btnSendMessage.TabIndex = 31;

                      this.btnSendMessage.Text = “Send”;

                      this.btnSendMessage.Click += new System.EventHandler(this.ButtonSendMessageClick);

                      //

                      // label4

                      //

                      this.label4.Location = new System.Drawing.Point(9, 79);

                      this.label4.Name = “label4″;

                      this.label4.Size = new System.Drawing.Size(120, 16);

                      this.label4.TabIndex = 30;

                      this.label4.Text = “Message To Server”;

                      //

                      // richTextRxMessage

                      //

                      this.richTextRxMessage.BackColor = System.Drawing.SystemColors.InactiveCaptionText;

                      this.richTextRxMessage.Font = new System.Drawing.Font(“Microsoft Sans Serif”, 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                      this.richTextRxMessage.Location = new System.Drawing.Point(194, 19);

                      this.richTextRxMessage.Name = “richTextRxMessage”;

                      this.richTextRxMessage.ReadOnly = true;

                      this.richTextRxMessage.Size = new System.Drawing.Size(247, 129);

                      this.richTextRxMessage.TabIndex = 27;

                      this.richTextRxMessage.Text = “”;

                      //

                      // tmrServerCheck

                      //

                      this.tmrServerCheck.Enabled = true;

                      this.tmrServerCheck.Interval = 5000;

                      this.tmrServerCheck.Tick += new System.EventHandler(this.tmrServerCheck_Tick);

                      //

                      // Client

                      //

                      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

                      this.ClientSize = new System.Drawing.Size(446, 159);

                      this.Controls.Add(this.groupBox1);

                      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;

                      this.Name = “Client”;

                      this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SocketClient_FormClosed);

                      this.groupBox1.ResumeLayout(false);

                      this.groupBox1.PerformLayout();

                      this.ResumeLayout(false);

                      }

                      #endregion

                      #region event handlers

                      private void tmrServerCheck_Tick(object sender, EventArgs e)

                      {

                      // check to see if the server is available, if so connect to it automatically

                      // See if we have text on the IP and Port text fields

                      if (_ServerIP != “”)

                      {

                      try

                      {

                      UpdateControls(false);

                      CreateSocket();

                      UpdateControls(true);

                      buttonConnect.Visible = false;

                      buttonDisconnect.Visible = true;

                      btnSendMessage.Enabled = true;

                      }

                      catch (SocketException se)

                      {

                      WriteToLogFile(“Cannot connect to server, is it available?”);

                      UpdateControls(false);

                      }

                      }

                      }

                      void ButtonDisconnectClick(object sender, System.EventArgs e)

                      {

                      timerAlive.Enabled = false;

                      SendMessageToServer(“id=client,closing,socket=” + _ServerSocketID);

                      if (m_clientSocket != null)

                      {

                      m_clientSocket.Close();

                      m_clientSocket = null;

                      UpdateControls(false);

                      buttonConnect.Visible = true;

                      buttonDisconnect.Visible = false;

                      btnSendMessage.Enabled = false;

                      }

                      }

                      private void btnClear_Click(object sender, System.EventArgs e)

                      {

                      richTextRxMessage.Clear();

                      }

                      private void timerAlive_Tick(object sender, EventArgs e)

                      {

                      SendMessageToServer(“id=client,available,socket=” + _ServerSocketID);

                      }

                      private void ExitApplication()

                      {

                      ClosingApplication();

                      Close();

                      }

                      private void ClosingApplication()

                      {

                      SendMessageToServer(“id=client,shutdown,socket=” + _ServerSocketID);

                      isClosing = true;

                      if (m_clientSocket != null)

                      {

                      m_clientSocket.Close();

                      m_clientSocket = null;

                      }

                      }

                      private void SocketClient_FormClosed(object sender, FormClosedEventArgs e)

                      {

                      if (!isClosing)

                      ClosingApplication();

                      }

                      void ButtonConnectClick(object sender, System.EventArgs e)

                      {

                      // See if we have text on the IP and Port text fields

                      if (_ServerIP == “”)

                      {

                      MessageBox.Show(“Port Number is required to connect to the Server\n”);

                      return;

                      }

                      try

                      {

                      UpdateControls(false);

                      CreateSocket();

                      UpdateControls(true);

                      buttonConnect.Visible = false;

                      buttonDisconnect.Visible = true;

                      btnSendMessage.Enabled = true;

                      }

                      catch (SocketException se)

                      {

                      string str;

                      str = “Connection failed, is the server running?\n” + se.Message;

                      WriteToLogFile(str);

                      UpdateControls(false);

                      }

                      }

                      void ButtonSendMessageClick(object sender, System.EventArgs e)

                      {

                      SendMessageToServer(textBoxMsg.Text + “,socket=” + _ServerSocketID);

                      }

                      private void button1_Click(object sender, EventArgs e)

                      {

                      richTextRxMessage.Clear();

                      }

                      #endregion event handlers

                      #region private methods

                      // If the calling thread is different from the thread that

                      // created the TextBox control, this method creates a

                      // AppendTextCallback and calls itself asynchronously using the

                      // Invoke method.

                      //

                      // If the calling thread is the same as the thread that created

                      // the TextBox control, the Text property is set directly.

                      private void AppendRxText(string text)

                      {

                      // InvokeRequired required compares the thread ID of the

                      // calling thread to the thread ID of the creating thread.

                      // If these threads are different, it returns true.

                      if (this.richTextRxMessage.InvokeRequired)

                      {

                      AppendTextCallback d = new AppendTextCallback(AppendRxText);

                      this.Invoke(d, new object[] { text });

                      WriteToLogFile(text);

                      }

                      else

                      {

                      richTextRxMessage.AppendText(text + “\r”);

                      WriteToLogFile(text);

                      }

                      }

                      private void ClosedownSocket()

                      {

                      if (this.buttonDisconnect.InvokeRequired)

                      {

                      DisconnectCallback d = new DisconnectCallback(ClosedownSocket);

                      this.Invoke(d, null);

                      }

                      else

                      this.ButtonDisconnectClick(this, null);

                      }

                      private void CreateSocket()

                      {

                      // Create the socket instance

                      m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                      // Cet the remote IP address

                      IPAddress ip = IPAddress.Parse(_ServerIP);

                      int iPortNo = System.Convert.ToInt16(_Port);

                      // Create the end point

                      IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);

                      // Connect to the remote host

                      m_clientSocket.Connect(ipEnd);

                      if (m_clientSocket.Connected)

                      {

                      //Wait for data asynchronously

                      WaitForData();

                      }

                      }

                      /// <summary>

                      /// Allows us to send a string command to our server

                      /// </summary>

                      /// <param name=”msg”>string command to send (comma delimited format)</param>

                      private void SendMessageToServer(string msg)

                      {

                      try

                      {

                      if (m_clientSocket != null)

                      {

                      if (m_clientSocket.Connected)

                      {

                      // New code to send strings

                      NetworkStream networkStream = new NetworkStream(m_clientSocket);

                      System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);

                      streamWriter.WriteLine(msg);

                      streamWriter.Flush();

                      }

                      }

                      }

                      catch (SocketException se)

                      {

                      MessageBox.Show(se.Message);

                      }

                      }

                      /// <summary>

                      /// Allows us to send a Byte Array to our server

                      /// </summary>

                      /// <param name=”objData”>Byte array to send</param>

                      private void SendMessageToServer(byte[] objData)

                      {

                      try

                      {

                      // Use the following code to send bytes

                      byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());

                      if (m_clientSocket != null)

                      {

                      m_clientSocket.Send(byData);

                      }

                      }

                      catch (SocketException se)

                      {

                      MessageBox.Show(se.Message);

                      }

                      }

                      private void UpdateControls(bool connected)

                      {

                      buttonConnect.Enabled = !connected;

                      buttonDisconnect.Enabled = connected;

                      string connectStatus = connected ? “Connected” : “Not Connected”;

                      AppendRxText(connectStatus + “\r”);

                      if (connected)

                      {

                      timerAlive.Enabled = true;

                      tmrServerCheck.Enabled = false;

                      }

                      else

                      {

                      timerAlive.Enabled = false;

                      tmrServerCheck.Enabled = true;

                      }

                      }

                      //—————————————————-

                      // This is a helper function used (for convenience) to

                      // get the IP address of the local machine

                      //—————————————————-

                      private String GetIP()

                      {

                      String strHostName = Dns.GetHostName();

                      // Find host by name

                      IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);

                      // Grab the first IP addresses

                      String IPStr = “”;

                      foreach (IPAddress ipaddress in iphostentry.AddressList)

                      {

                      IPStr = ipaddress.ToString();

                      return IPStr;

                      }

                      return IPStr;

                      }

                      private void Processcommand(string[] ClientCommand, SocketPacket socket)

                      {

                      // get our command string, parse it, pass through case statement

                      // and perform the relevant update i.e. label status

                      //int count = ClientCommand.Length; // how many elements in our array

                      if (ClientCommand[0].ToLower() != “server reply”)

                      {

                      switch (ClientCommand[0].ToLower())

                      {

                      case “shutdown”:

                      {

                      // server has closed the connection, ensure we disconnect

                      ClosedownSocket();

                      }

                      break;

                      case “servermsg:killclient”:

                      {

                      // shutdown this application

                      ClosedownSocket();

                      Close();

                      }

                      break;

                      case “hello”: // we have connected to our server, get our socketid to use in all our comms

                      // this ensures that our server knows which client has sent the command

                      {

                      string[] Args = SplitQuoted(ClientCommand[1], “\t\r\n\0″);

                      _ServerSocketID = Convert.ToInt32(Args[0]);

                      SendMessageToServer(“hello,” + _ServerSocketID + “,id=client”);

                      }

                      break;

                      default:

                      break;

                      }

                      }

                      }

                      /// <summary>

                      /// Here we decode the string sent from the client

                      /// </summary>

                      /// <param name=”szData”></param>

                      private string[] DecodeCommandString(string szData)

                      {

                      string[] command = SplitQuoted(szData, “;\r\n\0″);

                      return command;

                      }

                      private void WaitForData()

                      {

                      try

                      {

                      if (m_clientSocket != null)

                      {

                      if (m_pfnCallBack == null)

                      {

                      m_pfnCallBack = new AsyncCallback(OnDataReceived);

                      }

                      SocketPacket theSocPkt = new SocketPacket();

                      theSocPkt.thisSocket = m_clientSocket;

                      // Start listening to the data asynchronously

                      m_result = m_clientSocket.BeginReceive(theSocPkt.dataBuffer,

                      0, theSocPkt.dataBuffer.Length,

                      SocketFlags.None,

                      m_pfnCallBack,

                      theSocPkt);

                      WriteToLogFile(“Connected to “ + m_clientSocket.RemoteEndPoint.ToString());

                      }

                      }

                      catch (SocketException se)

                      {

                      MessageBox.Show(se.Message);

                      }

                      }

                      private void OnDataReceived(IAsyncResult asyn)

                      {

                      SocketPacket theSockId = (SocketPacket)asyn.AsyncState;

                      try

                      {

                      int iRx = theSockId.thisSocket.EndReceive(asyn);

                      char[] chars = new char[iRx + 1];

                      System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();

                      int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);

                      System.String szData = new System.String(chars);

                      string[] ClientCommand = SplitQuoted(szData, “,\r\n\0″);

                      Processcommand(ClientCommand, theSockId);

                      AppendRxText(szData + “\r”);

                      WaitForData();

                      }

                      catch (ObjectDisposedException)

                      {

                      WriteToLogFile(“Socket has been closed”);

                      System.Diagnostics.Debugger.Log(0, “1″, “\nOnDataReceived: Socket has been closed\n”);

                      }

                      catch (SocketException se)

                      {

                      AppendRxText(se.Message + “: “ + theSockId.thisSocket.RemoteEndPoint);

                      if (se.Message == “An existing connection was forcibly closed by the remote host”)

                      {

                      WriteToLogFile(“Connection closed by remote host”);

                      ClosedownSocket();

                      }

                      else

                      MessageBox.Show(se.Message);

                      }

                      }

                      #endregion private methods

                      #region public methods

                      /// <summary>

                      /// Action to be performed by RetryOpen

                      /// </summary>

                      /// <returns></returns>

                      public delegate T RetryOpenDelegate<T>();

                      /// <summary>

                      /// Perform an action until succeeds without throwing IOException

                      /// </summary>

                      /// <typeparam name=”T”>object returned</typeparam>

                      /// <param name=”action”>action performed</param>

                      /// <returns></returns>

                      public static T RetryOpen<T>(RetryOpenDelegate<T> action)

                      {

                      while (true)

                      {

                      try

                      {

                      return action();

                      }

                      catch (IOException)

                      {

                      System.Threading.Thread.Sleep(50);

                      }

                      }

                      }

                      public static void WriteToLogFile(string msg)

                      {

                      // create our daily directory

                      string dir = Application.StartupPath + “\\logs\\” + DateTime.Now.ToString(“ddMMyyyy”);

                      if (!Directory.Exists(dir))

                      Directory.CreateDirectory(dir);

                      string LogFile = dir + “\\” + DateTime.Now.ToString(“ddMMyyyy”) + “_Client_log.txt”;

                      TextWriter tw = null;

                      try

                      {

                      // create a writer and open the file

                      tw = RetryOpen<StreamWriter>(delegate()

                      {

                      return new StreamWriter(LogFile, true);

                      });

                      // write a line of text to the file

                      tw.WriteLine(DateTime.Now + “: ‘” + Environment.MachineName + “‘ – “ + msg);

                      }

                      catch { }

                      finally

                      {

                      // close the stream

                      if (tw != null)

                      {

                      tw.Close();

                      tw.Dispose();

                      }

                      }

                      }

                      /// <summary>

                      /// Splits any string using seperators string. This is different from the

                      /// string.Split method as we ignore delimiters inside double quotes and

                      /// will *ignore multiple delimiters in a row (i.e. “One,,,,two” will split

                      /// to two fields if comma is a delimiter).

                      /// Example:

                      /// Delims: ” \t,” (space, tab, comma)

                      /// Input: “one two” three four,five

                      /// Returns (4 strings):

                      /// one two

                      /// three

                      /// four

                      /// five

                      /// </summary>

                      /// <param name=”text”>The string to split.</param>

                      /// <param name=”delimiters”>The characters to split on.</param>

                      /// <returns></returns>

                      public static string[] SplitQuoted(string text, string delimiters)

                      {

                      // Default delimiters are a space and tab (e.g. ” \t”).

                      // All delimiters not inside quote pair are ignored.

                      // Default quotes pair is two double quotes ( e.g. ‘”"‘ ).

                      if (text == null)

                      throw new ArgumentNullException(“text”, “text is null.”);

                      if (delimiters == null || delimiters.Length < 1)

                      delimiters = ” \t”; // Default is a space and tab.

                      ArrayList res = new ArrayList();

                      // Build the pattern that searches for both quoted and unquoted elements

                      // notice that the quoted element is defined by group #2 (g1)

                      // and the unquoted element is defined by group #3 (g2).

                      string pattern =

                      @”"”([^""\\]*[\\.[^""\\]*]*)”"” +

                      “|” +

                      @”([^” + delimiters + @”]+)”;

                      // Search the string.

                      foreach (System.Text.RegularExpressions.Match m in System.Text.RegularExpressions.Regex.Matches(text, pattern))

                      {

                      //string g0 = m.Groups[0].Value;

                      string g1 = m.Groups[1].Value;

                      string g2 = m.Groups[2].Value;

                      if (g2 != null && g2.Length > 0)

                      {

                      res.Add(g2);

                      }

                      else

                      {

                      // get the quoted string, but without the quotes in g1;

                      res.Add(g1);

                      }

                      }

                      return (string[])res.ToArray(typeof(string));

                      }

                      #endregion public methods

                      }

                      #region socketpacket class

                      public class SocketPacket

                      {

                      public System.Net.Sockets.Socket thisSocket;

                      public byte[] dataBuffer = new byte[1024];

                      }

                      #endregion socketpacket class

                      }

                      This is the main body of the application. Compile and run the code and at the same time have the server running.

                      The client will automatically try to connect to the server (see the timer code to see how) and once established send keep alive messages to let the server know it’s there. These will also be returned to the client and displayed accordingly.

                      Try sending some text, you will see it appear in the server and then be returned to the client.

                      Try this, add the following line into the text box on the client and send it:

                      showmessage,Hello from client

                      You should get a message box popup with your ‘Hello from client’ text.

                      That’s all there is to it. Simple eh!

                      Have fun and let me know if you make any modifications to improve it all

                      Si

                      Speak to Simon Steed about any of the topics discussed this site.

                      One of the things i’ve noticed over the last few months in particular is the lack of decent programming examples in C# for a suitable client/server socket solution that just works! I was working on a contract that needed a robust and stable communications mechanism between multiple PC’s on a closed network for a Railway Simulator and Aircraft Simulator I was working on.

                      The following Server code is the first part of this two part article. It shows you how to code a solid and reliable server with error and message handling. Part two will explain how to code a client to go along with it.

                      Now i’m not naive enough to state there are no bugs in this code but it does work and work well. I would love to hear any comments from any developers that can help improve this code. The original code base I took from a couple of articles at the following URL’s, credit to the original authors:

                      http://www.developerfusion.co.uk/forums/p/36657/126609/#126609

                      http://www.codeguru.com/Csharp/Csharp/cs_network/sockets/article.php/c8781/

                      OK here goes, simply copy this code into the relevant files within a new solution. Bear in mind i’m using VS2008 here so you may need to modify the code accordingly for your environment. Should work fine in VS2005 with slight mods, not sure about VS2003

                      App.Config

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

                      <configuration>

                      <appSettings>

                      <add key=ServerPort value=10001 />

                      </appSettings>

                      </configuration>

                      This defines the port that server will listen on.

                      Program.cs

                      using System;

                      using System.Collections.Generic;

                      using System.Linq;

                      using System.Windows.Forms;

                      using System.Threading;

                      namespace SocketServer

                      {

                      static class Program

                      {

                      /// <summary>

                      /// The main entry point for the application.

                      /// </summary>

                      [STAThread]

                      static void Main()

                      {

                      Application.EnableVisualStyles();

                      Application.SetCompatibleTextRenderingDefault(false);

                      Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

                      Application.Run(new Server());

                      }

                      private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)

                      {

                      Server.WriteToLogFile(ExceptionHandler.DisplayMessage(e.Exception));

                      MessageBox.Show(ExceptionHandler.DisplayMessage(e.Exception));

                      }

                      }

                      }

                      This is the starting point for the application. I’m also making use of the ExceptionHandler class I recently spoke about in my blog.

                      ExceptionHandler.cs

                      using System;

                      using System.Collections.Generic;

                      using System.Linq;

                      using System.Text;

                      using System.Data;

                      using System.Data.SqlClient;

                      using System.Windows;

                      namespace SocketServer

                      {

                      ///

                      /// Handles displaying error messages

                      ///

                      public class ExceptionHandler

                      {

                      ///

                      /// Takes the exception message and displays a meaningful message to the user

                      ///

                      public static string DisplayMessage(Exception ex)

                      {

                      return DisplayMessage(ex, “”);

                      }

                      ///

                      /// Takes the exception message and displays a meaningful message to the user

                      ///

                      /// The exception to display.

                      /// Current User

                      //[System.Diagnostics.DebuggerStepThrough()]

                      public static string DisplayMessage(Exception ex, string userName)

                      {

                      StringBuilder sb = new StringBuilder();

                      if (ex is DBConcurrencyException)

                      sb.Append(“Concurrency Error: One or more people have updated this data since your last request.”);

                      else if (ex is SqlException)

                      {

                      sb.Append(“Database Error: “);

                      switch (((SqlException)ex).Number)

                      {

                      case 547:

                      sb.Append(“There is a constraint on the items you tried to modify. Please try again.”);

                      break;

                      case 2601:

                      // Unique Index

                      sb.Append(“Cannot insert duplicate values into the database.”);

                      break;

                      case 2627:

                      // Unique Constraint

                      sb.Append(“Cannot insert duplicate values into the database.”);

                      break;

                      default:

                      sb.Append(ex.Message);

                      break;

                      }

                      }

                      else

                      {

                      sb.Append(“Exception Handler Unexpected Error: “ + ex.Message);

                      }

                      string nl = “\n\n”;

                      sb.Append(nl + “Exception Information:” + nl);

                      sb.Append(“Message: “ + ex.Message + nl);

                      sb.Append(“Source: “ + ex.Source + nl);

                      sb.Append(“Stack Trace: “ + ex.StackTrace + nl);

                      if (ex.InnerException != null)

                      {

                      sb.Append(nl + “Inner Exception Info:” + nl);

                      sb.Append(“Message: “ + ex.InnerException.Message + nl);

                      sb.Append(“Source: “ + ex.InnerException.Source + nl);

                      sb.Append(“Stack Trace: “ + ex.InnerException.StackTrace + nl);

                      }

                      return sb.ToString();

                      }

                      }

                      }

                      UtilityFunctions.cs

                      using System;

                      using System.Collections.Generic;

                      using System.Linq;

                      using System.Text;

                      using System.Net;

                      using System.Net.Sockets;

                      using System.Collections;

                      namespace SocketServer

                      {

                      class UtilityFunctions

                      {

                      public static String GetIP()

                      {

                      String strHostName = Dns.GetHostName();

                      // Find host by name

                      IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);

                      // Grab the first IP addresses

                      String IPStr = “”;

                      foreach (IPAddress ipaddress in iphostentry.AddressList)

                      {

                      IPStr = ipaddress.ToString();

                      return IPStr;

                      }

                      return IPStr;

                      }

                      /// <summary>

                      /// Splits any string using seperators string. This is different from the

                      /// string.Split method as we ignore delimiters inside double quotes and

                      /// will *ignore multiple delimiters in a row (i.e. “One,,,,two” will split

                      /// to two fields if comma is a delimiter).

                      /// Example:

                      /// Delims: ” \t,” (space, tab, comma)

                      /// Input: “one two” three four,five

                      /// Returns (4 strings):

                      /// one two

                      /// three

                      /// four

                      /// five

                      /// </summary>

                      /// <param name=”text”>The string to split.</param>

                      /// <param name=”delimiters”>The characters to split on.</param>

                      /// <returns></returns>

                      public static string[] SplitQuoted(string text, string delimiters)

                      {

                      // Default delimiters are a space and tab (e.g. ” \t”).

                      // All delimiters not inside quote pair are ignored.

                      // Default quotes pair is two double quotes ( e.g. ‘”"‘ ).

                      if (text == null)

                      throw new ArgumentNullException(“text”, “text is null.”);

                      if (delimiters == null || delimiters.Length < 1)

                      delimiters = ” \t”; // Default is a space and tab.

                      ArrayList res = new ArrayList();

                      // Build the pattern that searches for both quoted and unquoted elements

                      // notice that the quoted element is defined by group #2 (g1)

                      // and the unquoted element is defined by group #3 (g2).

                      string pattern =

                      @”"”([^""\\]*[\\.[^""\\]*]*)”"” +

                      “|” +

                      @”([^” + delimiters + @”]+)”;

                      // Search the string.

                      foreach (System.Text.RegularExpressions.Match m in System.Text.RegularExpressions.Regex.Matches(text, pattern))

                      {

                      //string g0 = m.Groups[0].Value;

                      string g1 = m.Groups[1].Value;

                      string g2 = m.Groups[2].Value;

                      if (g2 != null && g2.Length > 0)

                      {

                      res.Add(g2);

                      }

                      else

                      {

                      // get the quoted string, but without the quotes in g1;

                      res.Add(g1);

                      }

                      }

                      return (string[])res.ToArray(typeof(string));

                      }

                      }

                      }

                      Just a couple of general routines we can call upon. I tend to add things like this to a separate class as it makes things nice and tidy.

                      SocketServer.Designer.cs

                      namespace SocketServer

                      {

                      partial class Server

                      {

                      /// <summary>

                      /// Required designer variable.

                      /// </summary>

                      private System.ComponentModel.IContainer components = null;

                      /// <summary>

                      /// Clean up any resources being used.

                      /// </summary>

                      /// <param name=”disposing”>true if managed resources should be disposed; otherwise, false.</param>

                      protected override void Dispose(bool disposing)

                      {

                      if (disposing && (components != null))

                      {

                      components.Dispose();

                      }

                      base.Dispose(disposing);

                      }

                      #region Windows Form Designer generated code

                      /// <summary>

                      /// Required method for Designer support – do not modify

                      /// the contents of this method with the code editor.

                      /// </summary>

                      private void InitializeComponent()

                      {

                      this.label1 = new System.Windows.Forms.Label();

                      this.groupBox1 = new System.Windows.Forms.GroupBox();

                      this.richTextBoxSendMsg = new System.Windows.Forms.RichTextBox();

                      this.btnClear = new System.Windows.Forms.Button();

                      this.richTextBoxReceivedMsg = new System.Windows.Forms.RichTextBox();

                      this.label8 = new System.Windows.Forms.Label();

                      this.buttonSendMsg = new System.Windows.Forms.Button();

                      this.groupBox1.SuspendLayout();

                      this.SuspendLayout();

                      //

                      // label1

                      //

                      this.label1.AutoSize = true;

                      this.label1.Font = new System.Drawing.Font(“Microsoft Sans Serif”, 11F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                      this.label1.Location = new System.Drawing.Point(360, 9);

                      this.label1.Name = “label1″;

                      this.label1.Size = new System.Drawing.Size(115, 18);

                      this.label1.TabIndex = 7;

                      this.label1.Text = “Socket Server”;

                      //

                      // groupBox1

                      //

                      this.groupBox1.Controls.Add(this.richTextBoxSendMsg);

                      this.groupBox1.Controls.Add(this.label1);

                      this.groupBox1.Controls.Add(this.btnClear);

                      this.groupBox1.Controls.Add(this.richTextBoxReceivedMsg);

                      this.groupBox1.Controls.Add(this.label8);

                      this.groupBox1.Controls.Add(this.buttonSendMsg);

                      this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;

                      this.groupBox1.Location = new System.Drawing.Point(0, 0);

                      this.groupBox1.Name = “groupBox1″;

                      this.groupBox1.Size = new System.Drawing.Size(477, 298);

                      this.groupBox1.TabIndex = 22;

                      this.groupBox1.TabStop = false;

                      //

                      // richTextBoxSendMsg

                      //

                      this.richTextBoxSendMsg.Location = new System.Drawing.Point(6, 27);

                      this.richTextBoxSendMsg.Name = “richTextBoxSendMsg”;

                      this.richTextBoxSendMsg.Size = new System.Drawing.Size(183, 21);

                      this.richTextBoxSendMsg.TabIndex = 45;

                      this.richTextBoxSendMsg.Text = “”;

                      //

                      // btnClear

                      //

                      this.btnClear.Location = new System.Drawing.Point(287, 27);

                      this.btnClear.Name = “btnClear”;

                      this.btnClear.Size = new System.Drawing.Size(88, 24);

                      this.btnClear.TabIndex = 43;

                      this.btnClear.Text = “Clear”;

                      this.btnClear.Click += new System.EventHandler(this.btnClear_Click);

                      //

                      // richTextBoxReceivedMsg

                      //

                      this.richTextBoxReceivedMsg.BackColor = System.Drawing.SystemColors.InactiveCaptionText;

                      this.richTextBoxReceivedMsg.Dock = System.Windows.Forms.DockStyle.Bottom;

                      this.richTextBoxReceivedMsg.Font = new System.Drawing.Font(“Microsoft Sans Serif”, 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                      this.richTextBoxReceivedMsg.Location = new System.Drawing.Point(3, 57);

                      this.richTextBoxReceivedMsg.Name = “richTextBoxReceivedMsg”;

                      this.richTextBoxReceivedMsg.ReadOnly = true;

                      this.richTextBoxReceivedMsg.Size = new System.Drawing.Size(471, 238);

                      this.richTextBoxReceivedMsg.TabIndex = 35;

                      this.richTextBoxReceivedMsg.Text = “”;

                      //

                      // label8

                      //

                      this.label8.Location = new System.Drawing.Point(3, 15);

                      this.label8.Name = “label8″;

                      this.label8.Size = new System.Drawing.Size(158, 20);

                      this.label8.TabIndex = 34;

                      this.label8.Text = “Broadcast Message To Clients”;

                      //

                      // buttonSendMsg

                      //

                      this.buttonSendMsg.Location = new System.Drawing.Point(192, 27);

                      this.buttonSendMsg.Name = “buttonSendMsg”;

                      this.buttonSendMsg.Size = new System.Drawing.Size(89, 24);

                      this.buttonSendMsg.TabIndex = 33;

                      this.buttonSendMsg.Text = “Send Message”;

                      this.buttonSendMsg.Click += new System.EventHandler(this.buttonSendMsg_Click);

                      //

                      // Server

                      //

                      this.AcceptButton = this.btnClear;

                      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

                      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

                      this.ClientSize = new System.Drawing.Size(477, 298);

                      this.Controls.Add(this.groupBox1);

                      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;

                      this.Name = “Server”;

                      this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;

                      this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;

                      this.Load += new System.EventHandler(this.LaunchForm_Load);

                      this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Server_FormClosed);

                      this.groupBox1.ResumeLayout(false);

                      this.groupBox1.PerformLayout();

                      this.ResumeLayout(false);

                      }

                      #endregion

                      private System.Windows.Forms.Label label1;

                      private System.Windows.Forms.GroupBox groupBox1;

                      private System.Windows.Forms.Button btnClear;

                      private System.Windows.Forms.RichTextBox richTextBoxReceivedMsg;

                      private System.Windows.Forms.Label label8;

                      private System.Windows.Forms.Button buttonSendMsg;

                      private System.Windows.Forms.RichTextBox richTextBoxSendMsg;

                      }

                      }

                      SocketServer.cs

                      using System;

                      using System.Collections.Generic;

                      using System.ComponentModel;

                      using System.Data;

                      using System.Drawing;

                      using System.Linq;

                      using System.Text;

                      using System.Windows.Forms;

                      using System.Diagnostics;

                      using System.Threading;

                      using System.IO;

                      using System.Net;

                      using System.Net.Sockets;

                      using System.Collections;

                      using System.Reflection;

                      using System.Configuration;

                      namespace SocketServer

                      {

                      public partial class Server : Form

                      {

                      #region socket stuff

                      // sample code and basis of client/server app taken from the following url’s

                      // http://www.developerfusion.co.uk/forums/p/36657/126609/#126609

                      // http://www.codeguru.com/Csharp/Csharp/cs_network/sockets/article.php/c8781/

                      public delegate void UpdateRichEditCallback(string text);

                      public delegate void UpdateClientListCallback();

                      public AsyncCallback pfnWorkerCallBack;

                      private Socket m_mainSocket;

                      // An ArrayList is used to keep track of worker sockets that are designed

                      // to communicate with each connected client. Make it a synchronized ArrayList

                      // For thread safety

                      private System.Collections.ArrayList m_workerSocketList = ArrayList.Synchronized(new System.Collections.ArrayList());

                      // This delegate enables asynchronous calls for setting

                      // the text property on a TextBox control.

                      delegate void AppendTextCallback(string text);

                      // The following variable will keep track of the cumulative

                      // total number of clients connected at any time. Since multiple threads

                      // can access this variable, modifying this variable should be done

                      // in a thread safe manner

                      private int m_clientCount = 0;

                      Dictionary<string, int> SocketMachineID = new Dictionary<string, int>(); // int = socketid, string = machineid

                      #endregion socket stuff

                      #region private members

                      Int16 _Port = 10001; // default port we listen on

                      bool isClosing = false;

                      byte[] m_dataBuffer = new byte[10];

                      public AsyncCallback m_pfnCallBack;

                      public Socket m_clientSocket;

                      #endregion

                      #region constructor

                      public Server()

                      {

                      InitializeComponent();

                      _Port = Convert.ToInt16(ConfigurationManager.AppSettings[“ServerPort”]);

                      }

                      #endregion constructor

                      #region private methods

                      /// <summary>

                      /// Search our dictionary to get the index of our socket to send the correct data down

                      /// </summary>

                      /// <param name=”Mode”>Client mode, we can identify our individual clients here, I will use Client for this example</param>

                      /// <returns>Integer contaning the socket id to pass into SendMsgToClient method</returns>

                      private int GetModeFromDictionary(string Mode)

                      {

                      int value = -1;

                      SocketMachineID.TryGetValue(Mode, out value);

                      return value;

                      }

                      #endregion private methods

                      #region event handlers

                      /// <summary>

                      /// Action to be performed by RetryOpen

                      /// </summary>

                      /// <returns></returns>

                      public delegate T RetryOpenDelegate<T>();

                      /// <summary>

                      /// Perform an action until succeeds without throwing IOException

                      /// </summary>

                      /// <typeparam name=”T”>object returned</typeparam>

                      /// <param name=”action”>action performed</param>

                      /// <returns></returns>

                      public static T RetryOpen<T>(RetryOpenDelegate<T> action)

                      {

                      while (true)

                      {

                      try

                      {

                      return action();

                      }

                      catch (IOException)

                      {

                      System.Threading.Thread.Sleep(50);

                      }

                      }

                      }

                      public static void WriteToLogFile(string msg)

                      {

                      // create our daily directory

                      string dir = Application.StartupPath + “\\logs\\” + DateTime.Now.ToString(“ddMMyyyy”);

                      if (!Directory.Exists(dir))

                      Directory.CreateDirectory(dir);

                      string LogFile = dir + “\\” + DateTime.Now.ToString(“ddMMyyyy”) + “_Server_log.txt”;

                      TextWriter tw = null;

                      try

                      {

                      // create a writer and open the file

                      tw = RetryOpen<StreamWriter>(delegate()

                      {

                      return new StreamWriter(LogFile, true);

                      });

                      // write a line of text to the file

                      tw.WriteLine(DateTime.Now + “: ‘” + Environment.MachineName + “‘ – “ + msg);

                      }

                      catch { }

                      finally

                      {

                      // close the stream

                      if (tw != null)

                      {

                      tw.Close();

                      tw.Dispose();

                      }

                      }

                      }

                      private void buttonSendMsg_Click(object sender, EventArgs e)

                      {

                      AppendToRichEditControl(“User Sending Message :” + richTextBoxSendMsg.Text);

                      SendMsgToAllClients(richTextBoxSendMsg.Text);

                      }

                      private void btnClear_Click(object sender, EventArgs e)

                      {

                      richTextBoxReceivedMsg.Clear();

                      }

                      void ExitApplication()

                      {

                      isClosing = true;

                      SendMsgToClient(“Shutdown”, -1); // broadcast message to all clients

                      Close();

                      }

                      private void Server_FormClosed(object sender, FormClosedEventArgs e)

                      {

                      if (!isClosing)

                      CloseSockets();

                      }

                      private void LaunchForm_Load(object sender, EventArgs e)

                      {

                      StartServerListening(); //Ensure our clients can find us by starting the server running

                      }

                      #endregion event handlers

                      #region Socket Methods

                      private void StartServerListening()

                      {

                      try

                      {

                      // Create the listening socket…

                      m_mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                      IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, _Port);

                      // Bind to local IP Address…

                      m_mainSocket.Bind(ipLocal);

                      // Start listening – allow 5 simultaneous connections…

                      m_mainSocket.Listen(5);

                      // Create the call back for any client connections…

                      m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);

                      }

                      catch (SocketException se)

                      {

                      AppendToRichEditControl(se.Message);

                      }

                      }

                      /// <summary>

                      /// This is the call back function, which will be invoked when a client is connected

                      /// </summary>

                      /// <param name=”asyn”></param>

                      public void OnClientConnect(IAsyncResult asyn)

                      {

                      try

                      {

                      if (m_mainSocket != null)

                      {

                      // Here we complete/end the BeginAccept() asynchronous call

                      // by calling EndAccept() – which returns the reference to a new Socket object

                      Socket workerSocket = m_mainSocket.EndAccept(asyn);

                      // Now increment the client count for this client in a thread safe manner

                      Interlocked.Increment(ref m_clientCount);

                      // Add the workerSocket reference to our ArrayList

                      m_workerSocketList.Add(workerSocket);

                      // Send a welcome message to client with their socket id so they can communicate properly with us

                      string msg = “hello,” + m_clientCount;

                      SendMsgToClient(msg, m_clientCount);

                      // Let the worker Socket do the further processing for the just connected client

                      WaitForData(workerSocket, m_clientCount);

                      // Since the main Socket is now free, it can go back and wait for

                      // other clients who are attempting to connect

                      m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);

                      }

                      }

                      catch (ObjectDisposedException)

                      {

                      System.Diagnostics.Debugger.Log(0, “1″, “\n OnClientConnection: Socket has been closed\n”);

                      }

                      catch (SocketException se)

                      {

                      AppendToRichEditControl(se.Message);

                      }

                      }

                      /// <summary>

                      /// Start waiting for data from the client

                      /// </summary>

                      /// <param name=”soc”></param>

                      /// <param name=”clientNumber”></param>

                      public void WaitForData(System.Net.Sockets.Socket soc, int clientNumber)

                      {

                      try

                      {

                      if (pfnWorkerCallBack == null)

                      {

                      // Specify the call back function which is to be

                      // invoked when there is any write activity by the connected client

                      pfnWorkerCallBack = new AsyncCallback(OnDataReceived);

                      }

                      SocketPacket theSocPkt = new SocketPacket(soc, clientNumber);

                      soc.BeginReceive(theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, pfnWorkerCallBack, theSocPkt);

                      AppendToRichEditControl(“Connected to Client “ + soc.RemoteEndPoint);

                      }

                      catch (SocketException se)

                      {

                      AppendToRichEditControl(se.Message);

                      }

                      }

                      /// <summary>

                      /// This the call back function which will be invoked when the socket

                      /// detects any client writing of data on the stream

                      /// </summary>

                      /// <param name=”asyn”></param>

                      public void OnDataReceived(IAsyncResult asyn)

                      {

                      SocketPacket socketData = (SocketPacket)asyn.AsyncState;

                      try

                      {

                      // Complete the BeginReceive() asynchronous call by EndReceive() method

                      // which will return the number of characters written to the stream by the client

                      int iRx = socketData.m_currentSocket.EndReceive(asyn);

                      char[] chars = new char[iRx + 1];

                      // Extract the characters as a buffer

                      System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();

                      int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);

                      System.String szData = new System.String(chars);

                      string msg = “” + socketData.m_clientNumber + “:”;

                      Processcommand(DecodeCommandString(szData), socketData);

                      AppendToRichEditControl(msg + szData);

                      msg = “command=” + Dns.GetHostName() + “,ok,” + szData;

                      SendMsgToClient(msg, socketData); // send our response back to the calling client

                      // Continue the waiting for data on the Socket

                      WaitForData(socketData.m_currentSocket, socketData.m_clientNumber);

                      }

                      catch (ObjectDisposedException)

                      {

                      System.Diagnostics.Debugger.Log(0, “1″, “\nOnDataReceived: Socket has been closed\n”);

                      }

                      catch (SocketException se)

                      {

                      if (se.ErrorCode == 10054) // Error code for Connection reset by peer

                      {

                      string msg = “Client “ + socketData.m_clientNumber + ” Disconnected” + “\n”;

                      AppendToRichEditControl(msg);

                      // Remove the reference to the worker socket of the closed client

                      // so that this object will get garbage collected

                      m_workerSocketList[socketData.m_clientNumber - 1] = null;

                      }

                      else

                      {

                      MessageBox.Show(“SocketException Error in OnDataReceived: “ + se.Message + “\r” + se.StackTrace);

                      }

                      }

                      catch (Exception ex)

                      {

                      MessageBox.Show(“General Error in OnDataReceived: “ + ex.Message + “\r” + ex.StackTrace);

                      }

                      }

                      private void Processcommand(string[] ClientCommand, SocketPacket socket)

                      {

                      // get our command string, parse it, pass through case statement

                      // and perform the relevant update i.e. label status

                      int count = ClientCommand.Length; // how many elements in our array

                      for (int i = 0; i < count; i++)

                      {

                      switch (ClientCommand[0].ToLower())

                      {

                      case “hello”: // hello from client

                      {

                      int SocketID = Convert.ToInt16(ClientCommand[1]); // get our socket

                      string Ident = “”;

                      if (ClientCommand[2].ToLower() == “id”)

                      Ident = ClientCommand[3];

                      // check if key already exists

                      if (!SocketMachineID.ContainsKey(Ident))

                      {

                      try

                      {

                      // Now add to dictionary

                      SocketMachineID.Add(Ident, SocketID);

                      }

                      catch (ArgumentException)

                      {

                      SocketMachineID.Remove(Ident); // remove the invalid entry

                      SocketMachineID.Add(Ident, SocketID); // re-add it

                      AppendToRichEditControl(“Updated key in dictionary”);

                      }

                      }

                      }

                      break;

                      case “id”: // machine identifier

                      {

                      if (ClientCommand[1].ToLower() == “client”)

                      {

                      bool avail = ClientCommand[2].ToLower() == “available”;

                      }

                      }

                      break;

                      case “showmessage”:

                      {

                      MessageBox.Show(ClientCommand[1]);

                      }

                      break;

                      default:

                      break;

                      }

                      }

                      }

                      /// <summary>

                      /// Here we decode the string sent from the client

                      /// </summary>

                      /// <param name=”szData”></param>

                      private string[] DecodeCommandString(string szData)

                      {

                      string[] command = UtilityFunctions.SplitQuoted(szData, “=,\r\n\0″);

                      return command;

                      }

                      /// <summary>

                      /// This method could be called by either the main thread or any of the worker threads

                      /// </summary>

                      /// <param name=”msg”>String to append</param>

                      private void AppendToRichEditControl(string msg)

                      {

                      // Check to see if this method is called from a thread other than the one created the control

                      if (InvokeRequired)

                      {

                      // We cannot update the GUI on this thread.

                      // All GUI controls are to be updated by the main (GUI) thread.

                      // Hence we will use the invoke method on the control which will

                      // be called when the Main thread is free

                      // Do UI update on UI thread

                      object[] pList = { msg };

                      richTextBoxReceivedMsg.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit), pList);

                      WriteToLogFile(msg);

                      }

                      else

                      {

                      // This is the main thread which created this control, hence update it directly

                      OnUpdateRichEdit(msg);

                      WriteToLogFile(msg);

                      }

                      }

                      /// <summary>

                      /// This UpdateRichEdit will be run back on the UI thread

                      /// (using System.EventHandler signature so we don’t need to define a new delegate type here)

                      /// </summary>

                      /// <param name=”msg”></param>

                      private void OnUpdateRichEdit(string msg)

                      {

                      richTextBoxReceivedMsg.AppendText(msg + “\r”);

                      }

                      void CloseSockets()

                      {

                      if (m_mainSocket != null)

                      {

                      m_mainSocket.Close();

                      m_mainSocket = null;

                      }

                      try

                      {

                      Socket workerSocket = null;

                      for (int i = 0; i < m_workerSocketList.Count; i++)

                      {

                      workerSocket = (Socket)m_workerSocketList[i];

                      if (workerSocket != null)

                      {

                      m_workerSocketList.Remove(workerSocket);

                      workerSocket.Close();

                      workerSocket = null;

                      }

                      }

                      }

                      catch

                      { }

                      }

                      /// <summary>

                      /// Allows us to send a specific message to a specific client

                      /// </summary>

                      /// <param name=”msg”></param>

                      /// <param name=”clientNumber”></param>

                      void SendMsgToClient(string msg, int clientNumber)

                      {

                      // Convert the reply to byte array

                      byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg);

                      if (clientNumber == -1) // send to all available servers

                      {

                      for (int i = 0; i < m_workerSocketList.Count; i++)

                      {

                      Socket workerSocket = (Socket)m_workerSocketList[i];

                      if (workerSocket != null)

                      workerSocket.Send(byData);

                      }

                      }

                      else

                      {

                      if (clientNumber != 0)

                      {

                      Socket workerSocket = (Socket)m_workerSocketList[clientNumber - 1];

                      if (workerSocket != null)

                      workerSocket.Send(byData);

                      }

                      }

                      }

                      /// <summary>

                      /// Send back a reply to the client using a socket descriptor

                      /// </summary>

                      /// <param name=”socketData”>Socket to send the data down</param>

                      /// <param name=”szData”>Data to send</param>

                      private static void SendMsgToClient(string szData, SocketPacket socketData)

                      {

                      try

                      {

                      string replyMsg = “Server Reply,” + szData.ToUpper();

                      // Convert the reply to byte array

                      byte[] byData = System.Text.Encoding.ASCII.GetBytes(replyMsg);

                      Socket workerSocket = (Socket)socketData.m_currentSocket;

                      workerSocket.Send(byData);

                      }

                      catch //(Exception ex)

                      {

                      // MessageBox.Show(“Error in SendMsgToClient method: ” + ex.Message + “\r” + ex.StackTrace);

                      }

                      }

                      /// <summary>

                      /// Allows us to send a broadcast message to all our clients

                      /// </summary>

                      /// <param name=”msg”>Message to send</param>

                      private void SendMsgToAllClients(string msg)

                      {

                      try

                      {

                      msg = “servermsg:” + msg + “\n”;

                      byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg);

                      Socket workerSocket = null;

                      for (int i = 0; i < m_workerSocketList.Count; i++)

                      {

                      workerSocket = (Socket)m_workerSocketList[i];

                      if (workerSocket != null)

                      {

                      if (workerSocket.Connected)

                      {

                      workerSocket.Send(byData);

                      }

                      }

                      }

                      }

                      catch //(SocketException se)

                      {

                      //MessageBox.Show(se.Message);

                      }

                      }

                      #endregion Socket Methods

                      }

                      #region SocketPacket Class

                      public class SocketPacket

                      {

                      // Constructor which takes a Socket and a client number

                      public SocketPacket(System.Net.Sockets.Socket socket, int clientNumber)

                      {

                      m_currentSocket = socket;

                      m_clientNumber = clientNumber;

                      }

                      public System.Net.Sockets.Socket m_currentSocket;

                      public int m_clientNumber;

                      // Buffer to store the data sent by the client

                      public byte[] dataBuffer = new byte[1024];

                      }

                      #endregion SocketPacket Class

                      }

                      Now simply compile and run. You will now have a server application which is capable of receiving any clients that connect to it on port 10001. Try it with a telnet client i.e. telnet 127.0.0.1 10001

                      You should see the client connect in the server window and the telnet client should get a response back saying hello with the socket number it’s connected on. Whilst this session is open, try another telnet session and you should see the socket number increase.

                      In the server app, add some text to the text box and click Send Message. The telnet clients will display the server sent message

                      That’s all there is to it. In the next part I will knock up a client application that you can use to talk more effectively to the server and have it send commands that it acts upon. For a hint, check out the ProcessCommand method in the server

                      Good luck!

                      Si

                      Speak to Simon Steed about any of the topics discussed this site.

                      Next Page »