Archive for April, 2009

C#: Detect If You’re Running on the Server

April 27th, 2009

If you ever need to detect whether your code is running on the machine that you’re talking to through IP (a server application for example), and you know the IP address for the remote machine, then this code may come in handy. It was originally written by my buddy Erin for a project we both worked on.

using System.Net;
 
private bool CheckIfServer(IPAddress serverIP)
{
    // Get all addresses assigned to this machine
    List<IPAddress> ipAddresses = new List<IPAddress>();
    ipAddresses.AddRange(Dns.GetHostAddresses(Dns.GetHostName()));
 
    // If desirable, also include the loopback adapter
    ipAddresses.Add(IPAddress.Loopback);
 
    // Detect if this machine contains the IP for the remote server
    // Note: This uses a Lambda Expression, which is only available .Net 3.x
    return ipAddresses.Exists(i => i.ToString() == serverIP.ToString());
}

If you don’t know the IP Address for your remote server you can easily get it using the server’s host name like this:

IPAddress[] addresses = Dns.GetHostAddresses("remote_host_address");

This returns an IPAddress[] which includes all the resolved addresses for that host.

C#: Lower Case All XML Tags with Regex

April 24th, 2009

Sometimes when accepting an XML document from an uncontrolled source using Linq to XML, it’s useful to convert all tags and attributes to lower case before processing the XML. This is because Linq to XML is case-sensitive and you can’t always rely on the program producing the XML to follow your casing standard for elements and attributes.

So here’s a quick and dirty single line of code that will accomplish just this in C# using a regular expression:

Regex.Replace(
    xml, 
    @"<[^<>]+>",
    m => { return m.Value.ToLower(); }, 
    RegexOptions.Multiline | RegexOptions.Singleline);

And here’s that functionality all nice and wrapped up inside of an extension for XElement:

public static class XElementExt
{
    public static string LowerCaseTags(string xml)
    {
        return Regex.Replace(
            xml,
            @"<[^<>]+>",
            m => { return m.Value.ToLower(); },
            RegexOptions.Multiline | RegexOptions.Singleline);
    }
}

Note: The Regex class is defined in System.Text.RegularExpressions

Here’s an example of the resulting affect.

Before:

<ParentNode>
   <ChildItem TestAttribute="ValueCasing" >
	This text Will not Be Harmed!
   </ChildItem>
</ParentNode>

After:

<parentnode>
   <childitem testattribute="valuecasing" >
	This text Will not Be Harmed!
   </childitem>
</parentnode>

You’ll notice that with this method all text within element tags is converted to lower case. This means that attribute values will lose any special casing they may have had, which may or may not be a problem for what you’re doing.

WPF: Vista Blue Highlight Brush

April 17th, 2009

For the WPF application I’m currently working on for work I decided that I wanted to change the style for all ListBoxItems so that they looked a little more like list items in Vista when highlighted, instead of the boring white text on a black background.

So I found this wonderful guide to setting the style for IsSelected ListBoxItems across the application. You can find it here: http://www.uxpassion.com/2008/09/styling-wpf-listbox-highlight-color/

Then, for a nice light-blue, glossy vista look I used this gradient:

<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
    <LinearGradientBrush.GradientStops>
        <GradientStop Offset="0" Color="#FFE3F4FC"/>
        <GradientStop Offset="0.38" Color="#FFD8EFFC"/>
        <GradientStop Offset="0.38" Color="#FFBEE6FD"/>
        <GradientStop Offset="1" Color="#FFA6D9F4"/>
    </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

It’s not perfect, but it looks pretty good. I also gave it a solid LightBlue border with a corner radius of 5. Here’s what the results looked like:
Vista Blue Highlight

C#: Set File Type Association

April 14th, 2009

While searching for some simple C# code to set the program and icon associated with a file type in Windows I ran across these beautiful functions that illustrate how to accomplish this by using the registry.

All credit goes to cristiscu (source).

Here’s the code:

using Microsoft.Win32;
using System.Runtime.InteropServices;
 
public class FileAssociation
{
    // Associate file extension with progID, description, icon and application
    public static void Associate(string extension, 
           string progID, string description, string icon, string application)
    {
        Registry.ClassesRoot.CreateSubKey(extension).SetValue("", progID);
        if (progID != null && progID.Length > 0)
            using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(progID))
            {
                if (description != null)
                    key.SetValue("", description);
                if (icon != null)
                    key.CreateSubKey("DefaultIcon").SetValue("", ToShortPathName(icon));
                if (application != null)
                    key.CreateSubKey(@"Shell\Open\Command").SetValue("", 
                                ToShortPathName(application) + " \"%1\"");
            }
    }
 
    // Return true if extension already associated in registry
    public static bool IsAssociated(string extension)
    {
        return (Registry.ClassesRoot.OpenSubKey(extension, false) != null);
    }
 
    [DllImport("Kernel32.dll")]
    private static extern uint GetShortPathName(string lpszLongPath, 
        [Out] StringBuilder lpszShortPath, uint cchBuffer);
 
    // Return short path format of a file name
    private static string ToShortPathName(string longName)
    {
        StringBuilder s = new StringBuilder(1000);
        uint iSize = (uint)s.Capacity;
        uint iRet = GetShortPathName(longName, s, iSize);
        return s.ToString();
    }
}

And here’s how you’d use it:

if (!FileAssociation.IsAssociated(".ext"))
   Associate(".ext", "ClassID.ProgID", "ext File", "YourIcon.ico", "YourApplication.exe");

A couple caveats to this code that I’ve noticed:

  1. The second parameter passed to Associate() can be any string you’d like to use to represent your program in the registry, just make sure you’re consistent with it.
  2. ToShortPathName() will return an empty string if the file path you pass it doesn’t exist, i.e. if you pass it a path to an icon file that doesn’t exist it won’t work.
  3. IsAssociated() will return true if the file extension is associated with any program, not just yours. If you want to be specific about it checking whether it’s associated with your program, then just check whether it’s default key is set to your programs ProgID.

WCF: Net.Tcp Binding on all IP Addresses

April 1st, 2009

In my new adventures in WCF I’ve come across this need to have the Service Host listening on all available IP Addresses on the server. I fumbled around with this for about a day before discovering the answer, which is really quite simple.

My first attempt at doing this was to create the Service Host and add a new binding for each available address, all bindings listening on the same port. This caused an exception to be thrown whenever the Service Host attempted to bind to the second address.

 So here’s the incorrect code:

public static void StartHosts()
{
    try
    {
        // Create a new host
        ServiceHost host = new ServiceHost(typeof(ServerTasks));
 
        List<IPAddress> ips = new List<IPAddress>(
            Dns.GetHostAddresses(Dns.GetHostName()));
 
        if (IPAddress.Loopback != null)
            ips.Add(IPAddress.Loopback);
 
        ips.RemoveAll(
            i => i.AddressFamily != AddressFamily.InterNetwork
            );
 
        foreach (var ip in ips)
        {
            string uri = string.Empty;
 
            // Formulate the uri for this host
            uri = string.Format(
                "net.tcp://{0}:{1}/ServerTasks",
                ip.ToString(),
                ServerSettings.Instance.TCPListeningPort
            );
 
 
            // Add the endpoint binding
            host.AddServiceEndpoint(
                typeof(ServerTasks),
                new NetTcpBinding(SecurityMode.Transport) 
                { TransferMode = TransferMode.Streamed },
                uri
            );
 
        }
 
 
 
        // Add the meta data publishing
        var smb = 
            host.Description.Behaviors.Find<ServiceMetadataBehavior>();
        if (smb == null)
            smb = new ServiceMetadataBehavior();
 
        smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
        host.Description.Behaviors.Add(smb);
 
        host.AddServiceEndpoint(
            ServiceMetadataBehavior.MexContractName,
            MetadataExchangeBindings.CreateMexTcpBinding(),
            "net.tcp://localhost/ServerTasks/mex"
        );
 
        // Run the host
        host.Open();
    }
    catch (Exception exc)
    {
        DebugLogger.WriteException(exc);
    }
}

What I didn’t realize is that all I needed to do was tell the Service Host to bind to the IP of 0 or 0.0.0.0 (thanks to seakingii and Chris for pointing this out below) and WCF would automatically bind to all addresses on the machine (unless you tell it not to). This was such a wonderful and amazing discovery that I just had to share it online!

 Here’s the correct code:

public static void StartHosts()
{
    try
    {
        // Formulate the uri for this host
        string uri = string.Format(
            "net.tcp://0:{1}/ServerTasks",
            ServerSettings.Instance.TCPListeningPort
        );
 
        // Create a new host
        ServiceHost host = 
            new ServiceHost(typeof(ServerTasks), new Uri(uri));
 
        // Add the endpoint binding
        host.AddServiceEndpoint(
            typeof(ServerTasks),
            new NetTcpBinding(SecurityMode.Transport)
            {
                TransferMode = TransferMode.Streamed
            },
            uri
        );
 
        // Add the meta data publishing
        var smb = 
            host.Description.Behaviors.Find<ServiceMetadataBehavior>();
        if (smb == null)
            smb = new ServiceMetadataBehavior();
 
        smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
        host.Description.Behaviors.Add(smb);
 
        host.AddServiceEndpoint(
            ServiceMetadataBehavior.MexContractName,
            MetadataExchangeBindings.CreateMexTcpBinding(),
            "net.tcp://localhost/ServerTasks/mex"
        );
 
        // Run the host
        host.Open();
    }
    catch (Exception exc)
    {
        DebugLogger.WriteException(exc);
    }
}