NullifyNetwork

The blog and home page of Simon Soanes
Skip to content
[ Log On ]

CodeBlog Articles - Main Index

Over the years I have written a number of coding related articles, links to them are listed below.

This has been delaying my release of an upgraded version of this blog for months now, and has also meant that I have chosen to use Linq To SQL on several large projects when working (Linq To SQL fully supports this scenario despite being the 2nd class citizen in entity mapping at Microsoft), Paul Patterson explains it quite well here so I can be lazy and just link to his article:-

http://www.paulspatterson.com/technology/dot-net-development/entity-framework-4-and-sql-uniqueidentifier-bug/

I wasn't willing to employ his fix though, it was frustrating and would get overwritten whenever the schema was updated however I have just found that there is a hotfix for this now available from Microsoft so that you can correctly configure the EDMX in entity framework to support the rowguid correctly:-

http://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=37957

This isn't perfect as you still need to manually set the StoreGeneratedPattern option on the rowguid columns to Identity, but it is certainly better than the total failure that was the case before!  Hopefully they will consider better support for replication, guid's and server-generated values in future versions.

I guess this means I can finally switch to Entity Framework and get my new site version released... :)

Permalink 

So I have encountered a situation where I need to use two factor authentication and recently bought a couple of Yubico YubiKey's to investigate them as a potential solution where I can't use smart cards (mostly with other users who can't install the appropriate drivers or on locked down systems/internet cafe's).

They are fairly cheap (particularly in bulk) and provide similar functionality to an RSA Securid but without the need to type the password (they act as a keyboard and type onto the computer, but can't be modified by the computer in question).  They also have two 'slots' for different tokens, you can touch the button once for one and touch and hold for a second one time key.

Whilst there's plenty of code examples around for them (the company are extremely open), I haven't found a simple, logical C# library/class I could use to do authentication locally (they supply ones for remote auth on their servers) - there were always multiple files and loads of code in peoples projects.

My intention is to write a Windows SubAuthentication DLL (in C++ but I learn in C#) to use with these keys which also still checks your normal password - so when remote desktop'ing, using something that authenticates to Windows or using the Windows Radius server (NPS) to authenticate VPN's you can choose to either supply your normal password, or if you're on a system you don't trust you can use your username/low security pin code and Yubikey.

So here's my take on the decoding of a Yubikey's input - note that I'm not interested in making a software token though so the class doesn't generate values for the random value (if you wanted to do this you just need to ask RNGCryptoProvider for a few bytes of random though) and there's also no incrementing of the sessions, in-session use counters or timestamps included - however I did include the code to encrypt it appropriately if you do supply all the values.

To use this class you just need to call it like so - where privateKey is a byte[] array with the private key in and otpCode is a string like "fkfthfffktbnreffrghcldrffeclcgkt" output from a touch of the Yubikey:-

YubiKey otp = YubiKey.FromModHex(privateKey, otpCode);
if (otp.UidMatch(checkIdentity))
{
Console.WriteLine("Decoded the YubiKey's OTP code:-");
Console.WriteLine("\tSession:\t" + otp.SessionCounter.ToString());
Console.WriteLine("\tCount in session:\t" + otp.SessionUseCount.ToString());
Console.WriteLine("\tTime (high):\t" + otp.TimestampHighPart.ToString());
Console.WriteLine("\tTime (low):\t" + otp.TimestampLowPart.ToString());
Console.WriteLine("\tTime (low):\t" + otp.Uid.ToString());
}
else
{
Console.WriteLine("Failed to identify the keys correct OTP");
}

 

And you can decode the private key/identity as they're displayed in the YubiKey personalisation tool with the following handy (but not super efficient) hex to byte algorithms:-

 

public static byte[] StringHexDecode(string hexData)
{
List<byte> data = new List<byte>();
foreach (string b in hexData.Split(' '))
{
data.Add(Convert.ToByte(b, 16));
}
return data.ToArray();
}

public static string StringHexEncode(byte[] hexData)
{
return BitConverter.ToString(hexData).Replace('-'' ');
}

And finally here's the actual Yubikey class including the algorithm to decrypt the data that the USB dongles actually output in 'ModHex' which is an odd keyboard language independent format but seems to work quite well:-

/// <summary>
/// A YubiKey OTP is symmetric two-factor auth key, this class allows decoding and validating them
/// </summary> public class YubiKey {
public YubiKey()
{
}

private const int CRC_OK_RESIDUE = 0xf0b8; /// <summary>
/// Unique (secret) ID.
/// </summary> public byte[] Uid = new byte[6]; /// <summary>
/// Session counter (incremented by 1 at each startup).  High bit
/// indicates whether caps-lock triggered the token.
/// </summary>
public UInt16 SessionCounter; /// <summary>
/// Timestamp incremented by approx 8Hz (low part).
/// </summary>
public UInt16 TimestampLowPart; /// <summary>
/// Timestamp (high part).
/// </summary>
public byte TimestampHighPart;
/// <summary>
/// Number of times used within session + activation flags.
/// </summary> public byte SessionUseCount; /// <summary>
/// Pseudo-random value.
/// </summary>
public UInt16 RandomValue; /// <summary>
/// CRC16 value of all fields.
/// </summary>
public UInt16 CRC;

/// <summary>
/// Does the included UID match the one we expected?
/// </summary>
/// <param name="uid"></param>
/// <returns></returns>
public bool UidMatch(byte[] uid)
{
for (int i = 0; i < uid.Length; i++)
{
if (Uid[i] != uid[i])
{
return false;
}
}
return true;
}

#region Post Decryption Conversion

private static int calculateCrc(byte[] b)
{
int crc = 0xffff;

for (int i = 0; i < b.Length; i += 1)
{
crc ^= b[i] & 0xFF;
for (int j = 0; j < 8; j++)
{
int n = crc & 1;
crc >>= 1;
if (n != 0)
{
crc ^= 0x8408;
}
}
}
return crc;
}

internal static YubiKey OtpFromRawByteArray(byte[] input)
{
if (input.Length < 16)
{
throw new YubiKeyException("Invalid OTP data - the amount supplied was
insufficient for a six byte identity."
);
}

if (calculateCrc(input) != CRC_OK_RESIDUE)
{
throw new YubiKeyException("CRC was invalid on that OTP");
}

YubiKey u = new YubiKey();
u.Uid = input.Take(6).ToArray();
u.SessionCounter = BitConverter.ToUInt16(input, 6);
u.TimestampLowPart = BitConverter.ToUInt16(input, 8);
u.TimestampHighPart = input[10];
u.SessionUseCount = input[11];
u.RandomValue = BitConverter.ToUInt16(input, 12);
u.CRC = BitConverter.ToUInt16(input, 14);
return u;
}

internal static byte[] RawByteArrayFromOtp(YubiKey input)
{
List<byte> data = new List<byte>();
data.AddRange(input.Uid);
data.AddRange(BitConverter.GetBytes(input.SessionCounter));
data.AddRange(BitConverter.GetBytes(input.TimestampLowPart));
data.Add(input.TimestampHighPart);
data.Add(input.SessionUseCount);
data.AddRange(BitConverter.GetBytes(input.RandomValue));
data.AddRange(BitConverter.GetBytes(input.CRC));
return data.ToArray();
}
#endregion

#region Cryptographic wrapper
internal byte[] AESEncrypt(byte[] data, byte[] key, byte[] iv)
{
Aes enc = Aes.Create();
enc.Key = key;
enc.IV = iv;
enc.Padding = PaddingMode.None;
using (ICryptoTransform transform = enc.CreateEncryptor())
{
byte[] output = transform.TransformFinalBlock(data, 0, data.Length);
return output;
}
}

internal static byte[] AESDecrypt(byte[] data, byte[] key, byte[] iv)
{
Aes aesImplementation = Aes.Create();
aesImplementation.Key = key;
aesImplementation.IV = iv;
aesImplementation.Padding = PaddingMode.None;

using (ICryptoTransform transform = aesImplementation.CreateDecryptor())
{
byte[] output = transform.TransformFinalBlock(data, 0, data.Length);

return output;
}
}
#endregion

#region ModHex Support

private const string alphabet = "cbdefghijklnrtuv";

internal static string ModHexEncode(byte[] data)
{
StringBuilder result = new StringBuilder();

for (int i = 0; i < data.Length; i++)
{
result.Append(alphabet[(data[i] >> 4) & 0xf]);
result.Append(alphabet[data[i] & 0xf]);
}

return result.ToString();
}

internal static byte[] ModHexDecode(String s)
{
List<byte> baos = new List<byte>();
int len = s.Length;

bool toggle = false;
int keep = 0;

for (int i = 0; i < len; i++)
{
char ch = s[i];
int n = alphabet.IndexOf(ch.ToString().ToLower());
if (n == -1)
{
throw new YubiKeyException(s + " is not properly encoded");
}

toggle = !toggle;

if (toggle)
{
keep = n;
}
else
{
baos.Add((byte)((keep << 4) | n));
}
}
return baos.ToArray();
}

#endregion

#region Factory helpers
/// <summary>
/// Create a Yubikey object from the mod hex and the private key
/// </summary>
/// <param name="privateKey">The private key to decrypt with</param>
/// <param name="modHex">The modhex content</param>
/// <returns>A yubikey object</returns>
public static YubiKey FromModHex(byte[] privateKey, string modHex)
{
//no IV in use
byte[] inputOTP = ModHexDecode(modHex);
byte[] decrypted = AESDecrypt(inputOTP, privateKey, new byte[16]);
return OtpFromRawByteArray(decrypted);
}

/// <summary>
/// Convert this yubikey instance into a mod-hex OTP string
/// </summary>
/// <param name="privateKey">The private key to encrypt with</param>
/// <returns>The modhext content</returns>
public string ToModHex(byte[] privateKey)
{
byte[] clearotp = RawByteArrayFromOtp(this);
byte[] encrypted = AESEncrypt(clearotp, privateKey, new byte[16]);
return ModHexEncode(encrypted);
}
#endregion

public class YubiKeyException : Exception
{
public YubiKeyException(string message) : base(message)
{

}
} }

Once decrypted it is a simple matter to verify it is a key with a particular code (the simple act of decryption should do that but there's a UID included inside too) and that the Session counter and SessionUseCount have been incremented appropriately to prevent re-use of existing keys.

Note that if you are trying to decode a key which has a prefix added you are interested in the last 32 characters of the output - the first few characters by default on a key are a static identifier so that it's possible to identify which encryption key to use to decrypt the token; I've turned this off and favour the user having to enter their own username/password prior to using the key.

Permalink 

Here's one from my distant past but which may be useful to me at some point today. I can actually see plenty of quicker ways to achieve this but it's also well tested for generating/checking credit card check digits:-

/// <summary>
    /// Creates/appends Luhn/Mod10 check digits to a specified numeric string
    /// Goes belly up with a text string.
    /// </summary>
    public class LuhnCheck
    {
        /// <summary>
        /// Initialise the LuhnCheck class with a number
        /// </summary>
        /// <param name="numberToAddDigitTo">The number to do work on</param>
        public LuhnCheck(string numberToAddDigitTo)
        {
            _numberToAddDigitTo = numberToAddDigitTo;
            setupok = true;
        }
        /// <summary>
        /// Initialise the LuhnCheck class without a number to start with
        /// </summary>
        public LuhnCheck()
        {
            _numberToAddDigitTo = "";
        }

        private string _numberToAddDigitTo;
        /// <summary>
        /// The number to work on
        /// </summary>
        public string NumberToAddDigitTo
        {
            get
            {
                return _numberToAddDigitTo;
            }
            set
            {
                _numberToAddDigitTo = value;
                setupok = true;
            }
        }
        private bool setupok = false;

        /// <summary>
        /// Add the check digit to the string and return the whole string
        /// </summary>
        /// <returns>The whole string with added check digit</returns>
        public string AddCheckDigit()
        {
            if (setupok)
            {
                NumberToAddDigitTo += Convert.ToString(CreateCheckDigit());
                return NumberToAddDigitTo;
            }
            else
            {
                throw new ArgumentException("Please specify the number to add the digit to.");
            }
        }
        /// <summary>
        /// Creates a check digit without using it
        /// </summary>
        /// <returns>The check digit</returns>
        public int CreateCheckDigit()
        {
            if (setupok)
            {
                return CreateCheckDigit(NumberToAddDigitTo);
            }
            else
            {
                throw new ArgumentException("Please specify the number to calculate the digit for.");
            }
        }
        /// <summary>
        /// Creates the check digit for a specified numeric string - it does not add it, only calculates it
        /// </summary>
        /// <param name="numberToAddDigitTo">The number to work the check digit out for</param>
        /// <returns>The check digit</returns>
        public int CreateCheckDigit(string numberToAddDigitTo)
        {
            string validChars = "0123456789";
            foreach (char c in numberToAddDigitTo)
            {
                if (!(validChars.IndexOf(c) >= 0))
                    throw new FormatException("The value passed in was not a valid number");
            }

            string tocheckdigit = numberToAddDigitTo + "0"; //We add zero to use it to calculate
            //the number from the correct point - since we'll be alternating between multiplying it by one or two
            int strlen = tocheckdigit.Length;
            int ncheck = 0;
            int nweight = 1; //this will alternate between one and two
            int intermediary = 0;
            string tosplit = "";

            for (int i = 1; i <= strlen; i++) //loop through the card number string
            {
                intermediary = nweight * Convert.ToInt32(Convert.ToString(tocheckdigit[strlen - i])); //make intermediary
//be the multiple of the variance and the card number
                if (intermediary > 9) //if it's bigger than ten...
                {
                    tosplit = Convert.ToString(intermediary);
                    //Split the two digits
                    int firstdigit = Convert.ToInt32(Convert.ToString(tosplit[0]));
                    int seconddigit = Convert.ToInt32(Convert.ToString(tosplit[1]));
                    //Then add them together
                    intermediary = firstdigit + seconddigit;
                }
                //Add the intermediary result to the rolling total
                ncheck += intermediary;
                //Change the variance as per the Luhn formula
                if (nweight == 2)
                {
                    nweight = 1;
                }
                else
                {
                    nweight = 2;
                }
            }
            //ncheck now has the total
            int remainder = 0;
            //Work out the remainder
            Math.DivRem(ncheck, 10, out remainder);
            //return ten minus the remainder (if it's zero then it divides perfectly by ten so is valid,
            //but since we're CREATING a check digit we want to know how far off the result is and how much we
	    //need to correct it using the check digit)
            if (10 - remainder == 10)
            {
                return 0;
            }
            else
            {
                return 10 - remainder;
            }

        }
        /// <summary>
        /// Whether the number stored in the object is a valid MOD 10/Luhn check digited number
        /// </summary>
        public bool IsValid
        {
            get
            {
                if (CreateCheckDigit() == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    }
Permalink 

Attempting to pass paths with a space or any other command line argument that requires being enclosed in quotes was causing me some mild frustration, it looks like the .NET implementation that fills args is incorrectly mangling the data that is passed into it.  A major bug that shouldn't have gotten through QA exists somewhere...

If you pass a path into a program that is foreach-ing over the args collection through the debug properties in visual studio (and presumably through anywhere else!) you go from:-

program.exe /path "c:\my documents\" /dostuff 1

Turn into two rather than four arguments:-

args[0] is /path
args[1] is c:\my documents" /dostuff 1

Which is downright strange, as you'd expect to get:-

args[0] is /path
args[1] is c:\my documents\
args[2] is /dostuff
args[3] is 1

What on earth are they doing to cause such a mess to command line arguments... Anyway, whilst I'm not sure when this started but thankfully the Environment.CommandLine is left intact and undamaged, so you can do something like this to fix the problem:-

private static string[] FixedExtractCmdLineElements()
        {
            List<string> elements = new List<string>();

            string[] firstParts = Environment.CommandLine.Split(' ');

            //reparse it
            StringBuilder temporaryPart = new StringBuilder("");
            bool inside = false;
            foreach (string part in firstParts)
            {
                //are we inside a quoted part, or did we just find a quote?
                if (!inside && !part.Contains("\""))
                {
                    elements.Add(part);
                }
                else
                {
                    if (inside)
                    {
                        //we are still inside a quote...
                        temporaryPart.Append(" " + part);

                        if (part.Contains("\""))
                        {
                            //then we are also at the end!
                            elements.Add(temporaryPart.Replace("\"", "").ToString()); //add the part minus its quotes to the array
                            //all done!
                            inside = false;
                        }
                    }
                    else
                    {
                        //else we just found a quote!
                        inside = true;
                        temporaryPart = new StringBuilder(part);
                    }
                }
            }

            return elements.ToArray();
        }
Permalink  2 Comments 

This is mostly so I don't have to ever type this in again, but it's most useful when you're also using an RSACryptoProvider to encrypt and send the key to the other end where you're decrypting whatever you are sending, but I thought these might be of use to someone...  There's really nothing complicated to these at all.

Note that the iv (initialisation vector) should be some random data that you pass with the encrypted data, but it does not need to be protected.  It's used to prevent two duplicate bits of input data outputting the exact same (and therefore being obvious), and to prevent someone making you encrypt something special in a way that you can have your private key exposed.

public static string AESEncrypt(string input, byte[] key, byte[] iv)
{
    Aes enc = Aes.Create();
    enc.Key = key;
    enc.IV = iv;
    using (ICryptoTransform transform = enc.CreateEncryptor())
    {
        byte[] data = Encoding.Unicode.GetBytes(input);
        byte[] output = transform.TransformFinalBlock(data, 0, data.Length);

        return Convert.ToBase64String(output);
    }
}

private static string AESDecrypt(string input, byte[] key, byte[] iv)
{
    Aes aesImplementation = Aes.Create();
    aesImplementation.Key = key;
    aesImplementation.IV = iv;

    using (ICryptoTransform transform = aesImplementation.CreateDecryptor())
    {
        byte[] data = Convert.FromBase64String(input);
        byte[] output = transform.TransformFinalBlock(data, 0, data.Length);

        return Encoding.Unicode.GetString(output);
    }
}
Permalink 

I needed to send some data over another medium to WCF and wanted to retain my current objects and classes, but also to retain the serialisation format for ease of direct input at the other end of this communications 'tube'.  I was actually sending these messages over XMPP after encrypting them, which is what the next post will be about...  It's worth noting that serialization using WCF is marginally faster than the more capable XmlSerializer but at the same time this has its own quirks and tends to produce more verbose XML.

So here's methods to serialise and deserialise DataContract marked up objects to XML strings:-

        public static string ContractObjectToXml<T>(T obj)
        {
            DataContractSerializer dataContractSerializer = new DataContractSerializer(obj.GetType());

            String text;
            using (MemoryStream memoryStream = new MemoryStream())
            {
                dataContractSerializer.WriteObject(memoryStream, obj);
                text = Encoding.UTF8.GetString(memoryStream.ToArray());
            }
            return text;
        }

        public static T XmlToContractObject<T>(string data)
        {
            DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(T));

            byte[] binary = Encoding.UTF8.GetBytes(data);
            using (MemoryStream memoryStream = new MemoryStream(binary))
            {
                object o = dataContractSerializer.ReadObject(memoryStream);
                return (T)o;
            }
        }
 
(Google thinks I should spell Serialise incorrectly as Serialize so I'm very conflicted about which I should use in this article as anyone searching would probably look for the American spelling...!)
Permalink 

I was experiencing problems with SQL compact edition (complete .NET framework freezes) and found that not only is it not thread safe (fairly obvious) but it's doesn't like to even have multiple instances of itself on the same thread - it deadlocks a lot if it does.  I also found that if it runs out of instances then it unloads from memory and has to be reloaded again afterwards, so avoiding that can result in a many tens of thousands of percent performance improvement.

So here's a small class I wrote to track the connection per thread based on someone elses on the Internet (they were just creating one per thread, in this one it is creating one per thread and maintaining the lifespan of that connection to close it when the thread it was for has been closed).  I'll probably add per-connection-string pooling but figured that the important thing is the concept of the solution to the COM deadlocks and total freezing of the framework in this.

/// <summary>
/// Manages open connections on a per-thread basis
/// </summary>
public abstract class SqlCeConnectionPool
{
    private static Dictionary<int, IDbConnection> threadConnectionMap = new Dictionary<int, IDbConnection>();

    private static Dictionary<int, Thread> threadMap = new Dictionary<int, Thread>();

    /// <summary>
    /// The connection map
    /// </summary>
    public static Dictionary<int, IDbConnection> ThreadConnectionMap
    {
        get { return SqlCeConnectionPool.threadConnectionMap; }
    }

    /// <summary>
    /// Gets the connection string.
    /// </summary>
    /// <value>The connection string.</value>
    public static string ConnectionString
    {
        get;
        set;
    }

    /// <summary>
    /// Gets a connection for this thread, maintains one open one of each.
    /// </summary>
    /// <remarks>Don't do this with anything but SQL compact edition or you'll run out of connections - compact edition is not
    /// connection pooling friendly and unloads itself too often otherwise so that is why this class exists</remarks> 
        /// <returns>An open connection</returns>
    public static IDbConnection Connection
    {
        get
        {
            lock (threadConnectionMap)
            {
                //do some quick maintenance on existing connections (closing those that have no thread)
                List<int> removeItems = new List<int>();
                foreach (var kvp in threadConnectionMap)
                {
                    if (threadMap.ContainsKey(kvp.Key))
                    {
                        if (!threadMap[kvp.Key].IsAlive)
                        {
                            //close the connection
                            kvp.Value.Close();
                            removeItems.Add(kvp.Key);
                        }
                    }
                    else
                    {
                        kvp.Value.Close();
                        removeItems.Add(kvp.Key);
                    }
                }
                foreach (int i in removeItems)
                {
                    threadMap.Remove(i);
                    threadConnectionMap.Remove(i);
                }

                //now issue the appropriate connection for our current thread
                int threadId = Thread.CurrentThread.ManagedThreadId;

                IDbConnection connection = null;
                if (threadConnectionMap.ContainsKey(threadId))
                {
                    connection = threadConnectionMap[threadId];
                }
                else
                {
                    connection = new SqlCeConnection(ConnectionString);
                    connection.Open();
                    threadConnectionMap.Add(threadId, connection);
                    threadMap.Add(threadId, Thread.CurrentThread);
                }

                return connection;
            }
        }
    }
}
Permalink 

I'm sure there's an easier way to do this, but I've been maintaining my own class to do the job for a while now and keep needing to find it in my code library every time I use it - I figure it might be useful to others:- 

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace CSVParser
{
    /// <summary>
    /// Simon's stock CSV parser class
    /// </summary>
    public class CSVParser
    {
        /// <summary>
        /// Takes the CSV files contents and creates a data table from it
        /// </summary>
        /// <param name="csvFileContents">The entire contents of a CSV file split by line (rather than the filename)</param>
        /// <param name="validateLayout">Validate the file to check conformance of the layout with expected standards</param>
        /// <param name="topRowIsHeader">The top row is the header row, take it as the column names rather than data</param>
        /// <returns>A datatable</returns>
        public static DataTable DataTableFromCSV(string[] csvFileContents, bool validateLayout, bool topRowIsHeader)
        {
            DataTable outputDataTable = new DataTable();
            List<string[]> csvFileRows = new List<string[]>();
            List<string> columns = new List<string>();

            #region Pre-parse the file
            int columnCount = 0;

            bool gotHeaders = false;
            int rowNumber = 0;

            foreach (string line in csvFileContents)
            {
                string[] parts = ExtractCSVElements(line);

                //initial set of header names but only if the top row is header option is set
                if (!gotHeaders && topRowIsHeader)
                {
                    columns.AddRange(parts);
                    columnCount = parts.Length;
                    gotHeaders = true;
                }
                else
                {
                    if (parts.Length > 0)
                    {
                        csvFileRows.Add(parts);
                    }
                }

                if (parts.Length > columnCount)
                {
                    //if set to validate the layout and that the first row contains the headers then we know any extra columns are wrong
                    if (validateLayout && gotHeaders)
                    {
                        throw new Exception("Row has extra data columns: " + rowNumber.ToString());
                    }

                    //new column detected mid-data-set!
                    for (int i = columnCount; i < parts.Length; i++)
                    {
                        columns.Add("Column " + i.ToString());
                    }

                    columnCount = parts.Length;
                }

                //we always ignore zero length rows as the last line can be empty
                if (parts.Length < columnCount && parts.Length != 0)
                {
                    if (validateLayout)
                    {
                        throw new Exception("Row has missing data columns: " + rowNumber.ToString());
                    }
                }


                rowNumber++;
            }

            #endregion

            #region Build the data tables layout and data

            //columns
            foreach (string column in columns)
            {
                outputDataTable.Columns.Add(column);
            }

            //rows
            foreach (string[] row in csvFileRows)
            {
                outputDataTable.Rows.Add(row);
            }
            #endregion

            return outputDataTable;
        }

        /// <summary>
        /// Extract the elements of a line from a CSV file with support for quotes
        /// </summary>
        /// <param name="line">The data to parse</param>
        private static string[] ExtractCSVElements(string line)
        {
            List<string> elements = new List<string>();

            //do the initial split, based on commas
            string[] firstParts = line.Split(',');

            //reparse it
            StringBuilder temporaryPart = new StringBuilder("");
            bool inside = false;
            foreach (string part in firstParts)
            {
                //are we inside a quoted part, or did we just find a quote?
                if (!inside //we're not inside
                && (!part.Contains("\"") //and we don't contain a quote
                 || ( //or we're handling a single quote enclosed element
                        part.StartsWith("\"") //we start with a quote
                        && part.EndsWith("\"") //and we end with a quote)
                    )
                )
                {
                    elements.Add(part);
                }
                else
                {
                    if (inside)
                    {
                        //we are still inside a quote...
                        temporaryPart.Append("," + part);

                        if (part.Contains("\""))
                        {
                            //then we are also at the end!
                            elements.Add(temporaryPart.Replace("\"", "").ToString()); //add the part minus its quotes to the array
                            //all done!
                            inside = false;
                        }
                    }
                    else
                    {
                        //else we just found a quote!
                        inside = true;
                        temporaryPart = new StringBuilder(part);
                    }
                }
            }

            return elements.ToArray();
        }
    }
}

 

Permalink 

My ASP.NET server/composite controls were not getting events from child controls, but only on the real pages, they worked fine on test ones.  It turned out that I had a master page enabled but didn't have an ID set for it, so it was auto generating it.

Just add this to your master pages code file:-

protected override void OnInit(EventArgs e) 
{ 
	base.OnInit(e); 
	this.ID = "SomeName"; 
}

And child controls will start working as expected.  I don't often do web development so this stumped me for quite a while...

Permalink 

Very quick snippet that I just made use of to allow users to remotely change passwords over the web.  Just leave the domainname and username black to change the current users password.  This works great from ASP.NET and requires no special permissions, unlike some solutions that use LDAP or impersonation.

[DllImport("netapi32.dll", CharSet = CharSet.Unicode, 
   CallingConvention = CallingConvention.StdCall, SetLastError = true)]

static extern uint NetUserChangePassword(string domainname, string username, string oldpassword, string newpassword);
Permalink 

Just a quick example:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Policy;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Reflection;
using System.IO;

namespace RestrictedAppDomainTest
{
    class Program
    {
        /// <summary>
        /// Example program demonstrating AppDomains with restrictive security
        /// Note that it requires the existance of C:\windows\win.ini to actually demonstrate it, but you 
        /// can modify this to any other file.
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //we want to define a level of access for this appdomain to have
            PolicyLevel levelOfAccess = PolicyLevel.CreateAppDomainLevel();

            //now we grant the permissions to do something specific:-
            PermissionSet executeOnly = new PermissionSet(PermissionState.None);

            //bare minimum to run at all
            executeOnly.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

            //if you wanted to grant the rights to read files then you need to grant FileIO:-
            //uncommenting this means that the appdomain created can complete its task rather than erroring 
            //as intended:-
            //  executeOnly.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, "C:\\Windows\\"));

            PolicyStatement executeOnlyStatement = new PolicyStatement(executeOnly);
            UnionCodeGroup applicablePolicy = new UnionCodeGroup(new AllMembershipCondition(), 
		executeOnlyStatement);
            //and tie the code group we defined to the level of access
            levelOfAccess.RootCodeGroup = applicablePolicy;
            
            //now we could add rights for things we trust, so they can assert that they
	     //want to perform operations that the appdomain normally can't:-
            /*
             * This is commented out because it grants the running assembly those rights, but this is an 
             * example of how to do it:-
             * 
             * After using this, you can use a MessageBox or form from inside the plugin.
             * 
             * (Change to a using multiple assemblies to restrict each one seperately)
             *
            
            //this example results in the UI being available
            PermissionSet displayUI = new PermissionSet(PermissionState.None);
            displayUI.AddPermission(new UIPermission(PermissionState.Unrestricted));
            //wrap the permission set in a statement
            PolicyStatement displayUIPolicyStatement = new PolicyStatement(displayUI);
            //And only grant this permission when the assembly has been strong named
            AssemblyName exampleAssembly = Assembly.GetExecutingAssembly().GetName();
            UnionCodeGroup selectPolicy = new UnionCodeGroup(new StrongNameMembershipCondition(
                        new StrongNamePublicKeyBlob(exampleAssembly.GetPublicKey()
                    ), exampleAssembly.Name, exampleAssembly.Version
                ), displayUIPolicyStatement);
            
            //and finally we add this new policy to the previous one so there's a chain
            applicablePolicy.AddChild(selectPolicy);
            
             */

            //create the appdomain with our basic permission set!
            AppDomain domain = AppDomain.CreateDomain("RestrictedDomain", null, 
		  AppDomain.CurrentDomain.SetupInformation); //do not supply the level permission using this
// constructor, you can't change it later using//SetAppDomainPolicy
            
            //define the total security policy here
            domain.SetAppDomainPolicy(levelOfAccess);

            //now we load our example class from below, for this example we are using the currently executing 
            //assemblies name this can be replaced with another filename, or full assembly name to load a 
            //particular one from the GAC for example
            string thisAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
            IPlugin examplePlugin = (IPlugin)domain.CreateInstanceAndUnwrap(thisAssemblyName, 
		"RestrictedAppDomainTest.ExampleClass");

            //this starts running a thread and doing other things that are potentially dodgy.
            examplePlugin.DoSomething();
            //(note that if this didn't choose to start a thread it would still run in a seperate thread anyway)

            //no (security) exception here, just to show we are unaffected by the appdomain's restrictions!
            string dummyData = File.ReadAllText("C:\\windows\\win.ini");

            Console.WriteLine("An app domain is now started and running in the background.");
            Console.WriteLine();
            Console.WriteLine("Press any key to terminate and unload the restricted appdomain!");                    
            Console.ReadKey();

            //This results in the termination of the thread the AppDomain//started, and unloading of
            //any resources (including locked files or assemblies).
            AppDomain.Unload(domain);
            
            Console.WriteLine("Domain has been unloaded.  Press any key to end.");
            Console.ReadKey();
        }
    }

    /// <summary>
    /// Defines an example plugin
    /// </summary>
    public interface IPlugin
    {
        void DoSomething();
    }

    /// <summary>
    /// An example (malicious) plugin
    /// </summary>
    public class ExampleClass : MarshalByRefObject, IPlugin
    {
        /// <summary>
        /// This is called from the unrestricted AppDomain
        /// </summary>
        public void DoSomething()
        {
            voidDelegate startDoingThings = new voidDelegate(longNaughtyOperation);
            //run the method on a different thread to demonstrate we can  	     //even start threads here
            startDoingThings.BeginInvoke(null, null);
        }

        private delegate void voidDelegate();

        private void longNaughtyOperation()
        {
            while (true)
            {
                try
                {
                    //this is denied so will fail
                    string dummyData = File.ReadAllText("C:\\windows\\win.ini");
                    //this won't ever happen hopefully :)
                    Console.WriteLine("Restricted AppDomain completed its work!!!");
                    //stop looping if the above works!
                    break;
                }
                catch (SecurityException)
                {
                    Console.WriteLine("Security exception as expected, trying  again so you can terminate this thread... :)");
                }
                Thread.Sleep(1000);
            }
        }
    }
}
Permalink 

I needed to get the unmanaged container name of an X509Certificate2 in order to be able to get access to the equivalent private key for it on Windows Mobile (I also wanted to be able to use the same routine on Windows CE and Win32 so this works as-is on all platforms).

No decent commentary but hopefully it will help someone else who is stuck without the container name or something.


#region Structures
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPT_KEY_PROV_INFO
{
      [MarshalAs(UnmanagedType.LPWStr)]
      public string pwszContainerName;
      [MarshalAs(UnmanagedType.LPWStr)]
      public string pwszProvName;
      public uint dwProvType;
      public uint dwFlags;
      public uint cProvParam;
      public IntPtr rgProvParam;
      public uint dwKeySpec;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPTOAPI_BLOB
{
    public uint cbData;
    public IntPtr pbData;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CERT_DSS_PARAMETERS
{
    public CRYPTOAPI_BLOB p;
    public CRYPTOAPI_BLOB q;
    public CRYPTOAPI_BLOB g;
}
#endregion

[DllImport("crypt32.dll")]
public static extern bool CertGetCertificateContextProperty(IntPtr pCertContext, 
	uint dwPropId, IntPtr pvData, ref uint pcbData);

public CRYPT_KEY_PROV_INFO GetCertificateContextProperty(X509Certificate2 certificate)
{
     //call once to get the size, call again to get the data
     try
     {
         IntPtr certhandle = certificate.Handle;
         uint pcbData = 0;
         if (CertGetCertificateContextProperty(certhandle, 2, IntPtr.Zero, ref pcbData))
         {
             IntPtr memoryChunk = Marshal.AllocHGlobal((int)pcbData);
             try
             {
       		    if (CertGetCertificateContextProperty(certhandle, 2, memoryChunk, 
			ref pcbData))
                  {
                    CRYPT_KEY_PROV_INFO context = 
				(CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(memoryChunk, 
				typeof(CRYPT_KEY_PROV_INFO));
                     return context;
                  }
                  else
                  {
                      throw new Exception("Failed to fetch the Certificate Context 
Property, possibly due to the certificate being modified during the call.  Please try again!");
                  }
              }
              finally
              {
                  Marshal.FreeHGlobal(memoryChunk);
              }
          }
      }
      finally
      {
          //dispose of certhandle or not??
      }
      throw new Exception("Failed to fetch the Certificate Context Property");
}

(Incidentally the extra structures are handy for doing other operations with the certificate so I left them there - the blob particularly is used in a lot of places in the CryptoAPI)

Permalink 

Okay so to make up for not having posted a single codeblog entry in several months I have a mammoth one here that has taken over 6 hours to figure out and write.

The following is a class that implements near-full support for the WMI interface to the MS DNS Server on Windows Server 2003 (also should work on Windows Server 2008 and if you install an add-on you can probably use it under Server 2000 but I have only briefly tried server 2008).  I wrote this out of frustration when I googled for an easy way to create a DNS record programmatically in Microsoft DNS Server and there was a distinct absence of actually useful information (there were just a couple of poor examples and no really complete solutions).  You can use this to allow you to modify a DNS zone in C# (dynamic DNS hosting under Windows anyone?) or for running your webhosting businesses automation from ASP.NET.  Note that I haven't tested deleting!

This class requires both a reference to and a using statement for System.Management from .NET 2.0.  I included the entire thing as if it were a single file for the ease of demonstration - you probably want to remove the DNSServer class and its helper classes (which are included within it) and put them into a seperate file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;

namespace DNSManager
{
    #region Example usage code
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Connecting to the DNS Server...");
            DNSServer d = new DNSServer("vex.nullify.net"); //my internal DNS Server, change to yours.
                                                            //You will need to be able to get to it using WMI.
            Console.WriteLine("Connected to the DNS Server");

            Console.Write("Creating a new zone as a test...");
            try
            {
                d.CreateNewZone("testzone.uk.nullify.net.", DNSServer.NewZoneType.Primary);
                Console.WriteLine("OK");
            }
            catch (Exception)
            {
                Console.WriteLine("Failed to create a new zone, it probably exists.");
            }

            Console.Write("Creating a DNS record as a test...");
            try
            {
                d.CreateDNSRecord("testzone.uk.nullify.net.", "test1.testzone.uk.nullify.net. IN CNAME xerxes.nullify.net.");
                Console.WriteLine("OK");
            }
            catch (Exception)
            {
                Console.WriteLine("Failed to create a new resource record, it probably exists");
            }

            Console.WriteLine("Getting a list of domains:");
            foreach (DNSServer.DNSDomain domain in d.GetListOfDomains())
            {
                Console.WriteLine("\t"+domain.Name+" ("+domain.ZoneType+")");
                //and a list of all the records in the domain:-
                foreach (DNSServer.DNSRecord record in d.GetRecordsForDomain(domain.Name))
                {
                    Console.WriteLine("\t\t"+record);
                    //any domains we are primary for we could go and edit the record now!
                }
            }

            Console.WriteLine("Fetching existing named entry (can be really slow, read the warning):-");
            DNSServer.DNSRecord[] records = d.GetExistingDNSRecords("test1.testzone.uk.nullify.net.");
            foreach (DNSServer.DNSRecord record in records)
            {
                Console.WriteLine("\t\t" + record);
                record.Target = "shodan.nullify.net.";
                record.SaveChanges();
            }
        }
    }
    #endregion

    #region Real code

    /// <summary>
    /// A Microsoft DNS Server class that abstracts out calls to WMI for MS DNS Server
    /// </summary>
    /// <remarks>
    /// WMI Documentation: 
    /// http://msdn.microsoft.com/en-us/library/ms682123(VS.85).aspx
    /// System.Management Documentation: 
    /// http://msdn.microsoft.com/en-us/library/system.management.managementobjectcollection%28VS.71%29.aspx
    /// </remarks>
    /// <c>(c) 2008 Simon Soanes, All Rights Reserved.  No warranties express or implied.
    /// DO NOT redistribute this source code publically without a link to the origin and this copyright
    /// notice fully intact, also please send any modifications back to me at simon@nullifynetwork.com
    /// Including in your software is fine although attribution would be nice.</c>
    public class DNSServer
    {

        #region Supporting classes
        /// <summary>
        /// Different types of DNS zone in MS DNS Server
        /// </summary>
        public enum ZoneType
        {
            DSIntegrated,
            Primary,
            Secondary
        }

        /// <summary>
        /// Different types of DNS zone in MS DNS Server
        /// </summary>
        /// <remarks>For creation of new zones the list is different</remarks>
        public enum NewZoneType
        {
            Primary,
            Secondary,
            /// <remarks>Server 2003+ only</remarks>
            Stub,
            /// <remarks>Server 2003+ only</remarks>
            Forwarder
        }

        /// <summary>
        /// A zone in MS DNS Server
        /// </summary>
        public class DNSDomain
        {        
            /// <summary>
            /// Create a DNS zone
            /// </summary>
            /// <param name="name">The name of the DNS zone</param>
            /// <param name="wmiObject">The object that represents it in MS DNS server</param>
            /// <param name="server">The DNS Server it is to be managed by</param>
            public DNSDomain(string name, ManagementBaseObject wmiObject, DNSServer server)
            {
                _name = name;
                _wmiObject = wmiObject;
                _server = server;
            }

            private DNSServer _server = null;

            private string _name = "";

            /// <summary>
            /// The name of the DNS zone
            /// </summary>
            public string Name
            {
                get { return _name; }
                set { _name = value; }
            }

            /// <summary>
            /// The zone type
            /// </summary>
            public ZoneType ZoneType
            {
                get
                {
                    //_wmiObject["ZoneType"].ToString()
                    return (ZoneType)Convert.ToInt32(_wmiObject["ZoneType"]);
                }
            }

            /// <summary>
            /// Is this a reverse DNS zone?
            /// </summary>
            public bool ReverseZone
            {
                get
                {
                    if (_wmiObject["Reverse"].ToString() == "1")
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }

            private ManagementBaseObject _wmiObject = null;

            /// <summary>
            /// Get a list of all objects at the base of this zone
            /// </summary>
            /// <returns>A list of <see cref="DNSRecord"/></returns>
            public DNSRecord[] GetAllRecords()
            {
                return _server.GetRecordsForDomain(_name);
            }

            /// <summary>
            /// Create a new DNS host record
            /// </summary>
            /// <param name="record">The record to create</param>
            public void CreateDNSRecord(DNSRecord record)
            {
                _server.CreateDNSRecord(_name, record.ToString());
            }

            public override string ToString()
            {
                return _name;
            }
        }

        /// <summary>
        /// An entry in a zone
        /// </summary>
        public class DNSRecord
        {
            /// <summary>
            /// Create an class wrapping a DNS record
            /// Defaults to 1 hour TTL
            /// </summary>
            /// <param name="domain"></param>
            /// <param name="recordType"></param>
            /// <param name="target"></param>
            public DNSRecord(string domain, DNSRecordType recordType, string target) : 
                this(domain, recordType, target, new TimeSpan(1, 0, 0))
            {
            }

            /// <summary>
            /// Create an class wrapping a DNS record
            /// </summary>
            /// <param name="domain"></param>
            /// <param name="recordType"></param>
            /// <param name="target"></param>
            /// <param name="ttl"></param>
            public DNSRecord(string domain, DNSRecordType recordType, string target, TimeSpan ttl)
            {
                _host = domain;
                _ttl = ttl;
                _target = target;
                _recordType = recordType;
            }

            /// <summary>
            /// Create an class wrapping a DNS record
            /// </summary>
            /// <param name="wmiObject"></param>
            public DNSRecord(ManagementObject wmiObject)
            {
                _wmiObject = wmiObject;
                _host = wmiObject["OwnerName"].ToString();
                _target = wmiObject["RecordData"].ToString();
                string[] recordParts = wmiObject["TextRepresentation"].ToString().Split(' ', '\t');
                if (recordParts.Length > 2)
                {
                    //the third offset is the location in the textual version of the data where the record type is.
                    //counting from zero that is location 2 in the array.
                    _recordType = new DNSRecordType(recordParts[2]); 
                }
                _ttl = new TimeSpan(0, 0, Convert.ToInt32(wmiObject["TTL"]));
            }

            private ManagementObject _wmiObject = null;

            private string _target = "";

            /// <summary>
            /// The value of the target is what is written to DNS as the value of a record
            /// </summary>
            /// <remarks>For MX records include the priority as a number with a space or tab between it and the actual target</remarks>
            public string Target
            {
                get { return _target; }
                set { _target = value; }
            }

            /// <summary>
            /// Save the changes to the resource record
            /// </summary>
            public void SaveChanges()
            {
                //We can call modify and if we have the method available it will work as the sub-class may have it!!
                //Some types DO NOT implement it or implement it differently

                ManagementBaseObject parameters = _wmiObject.GetMethodParameters("Modify");
                bool supported = false;

                //This is a cludge based on the various types that are implemented by MS as they didn't stick to a simple value

                //To add more, please refer to 
                if (RecordType.TextRepresentation == "A")
                {
                    parameters["IPAddress"] = _target;
                    parameters["TTL"] = _ttl.TotalSeconds;
                    supported = true;
                }

                if (RecordType.TextRepresentation == "AAAA")
                {
                    parameters["IPv6Address"] = _target;
                    parameters["TTL"] = _ttl.TotalSeconds;
                    supported = true;
                }

                if (RecordType.TextRepresentation == "CNAME")
                {
                    parameters["PrimaryName"] = _target;
                    parameters["TTL"] = _ttl.TotalSeconds;
                    supported = true;
                }

                if (RecordType.TextRepresentation == "TXT")
                {
                    parameters["DescriptiveText"] = _target;
                    parameters["TTL"] = _ttl.TotalSeconds;
                    supported = true;
                }

                if (RecordType.TextRepresentation == "MX")
                {
                    string[] components = _target.Trim().Split(' ', '\t');
                    if (components.Length > 1)
                    {
                        parameters["Preference"] = Convert.ToUInt16(components[0]); //the preference is a UINT16 in MS DNS Server
                        parameters["MailExchange"] = components[1]; //the actual host name
                        //NOT SUPPORTED BY MX ACCORDING TO THE DOCUMENTATION!? parameters["TTL"] = _ttl;
                        supported = true;
                    }
                }

                Exception temporaryException = null;
                try
                {
                    //This supports improving this classes implementation of this method and adding 
                    ManagementBaseObject lastDitchParameters = OnSaveChanges(parameters);
                    if (lastDitchParameters != null)
                    {
                        parameters = lastDitchParameters;
                        supported = true;
                    }
                }
                catch (Exception ex) //catch all as we do not know what someone will modify OnSaveChanges() to throw or cause
                {
                    if (!supported) //if we support the data type already then we don't care about exceptions as at worst case
                        throw;
                    else
                        temporaryException = ex;
                }

                if (supported)
                {
                    try
                    {
                        _wmiObject = (ManagementObject)_wmiObject.InvokeMethod("Modify", parameters, null);
                    }
                    catch (Exception ex)
                    {
                        if (temporaryException != null)
                        {
                            throw new ApplicationException("There were two exceptions, the primary failure"+
                                " was an exception that is encapsulated in this message however additionaly "+
                                "a virtual method that was optional to functionality also threw an exception "+
                                "but this was withheld till after the operation failed. Please examine the"+
                                " InnerException property for copy of the virtual methods exception.  The "+
                                "virtual methods exception message was: " + temporaryException.Message+".  "+
                                "The primary exceptions message (a "+ex.GetType().FullName.ToString()+") "+
                                "was: "+ex.Message, temporaryException);
                        }
                        else
                        {
                            throw;
                        }
                    }
                    
                    if (temporaryException != null)
                    {
                        throw new ApplicationException("A virtual method that was optional to functionality "+
                            "threw an exception but this was withheld till after the operation completed "+
                            "successfully, please examine the InnerException property for a full copy of this "+
                            "exception.  The message was: " + temporaryException.Message, temporaryException);
                    }
                }
                else
                {
                    throw new NotSupportedException("The data type you attmpted to use ("+
                        RecordType.TextRepresentation+") was not supported, please implement support for"+
                    "it by overriding the method OnSaveChanges() and returning an array of filled WMI parameters "+
                    "or by updating this implementation.");
                }
            }

            /// <summary>
            /// Method to override to add additional methods to the DNS save changes support
            /// </summary>
            /// <param name="parametersIn">An array of parameters (not yet filled in if it's an 
            /// unknown type, potentially partially filled for known types)</param>
            /// <returns>An array of filled in parameters, or null if the parameters are unknown</returns>
            public virtual ManagementBaseObject OnSaveChanges(ManagementBaseObject parametersIn)
            {
                return null;
            }

            /// <summary>
            /// Delete a record from DNS
            /// </summary>
            public void Delete()
            {
                _wmiObject.Delete();
                //well that was easy...
            }

            private TimeSpan _ttl = new TimeSpan(0, 1, 0);

            /// <summary>
            /// The time that the resolvers should cache this record for
            /// </summary>
            public TimeSpan Ttl
            {
                get { return _ttl; }
                set { _ttl = value; }
            }

            private DNSRecordType _recordType = null;

            /// <summary>
            /// The record type
            /// </summary>
            public DNSRecordType RecordType
            {
                get { return _recordType; }
            }
            private string _host = "";

            /// <summary>
            /// The location in the DNS system for this record
            /// </summary>
            public string DomainHost
            {
                get { return _host; }
                set { _host = value; }
            }

            public override string ToString()
            {
                return _host + " " + _recordType.ToString() + " " + _target;
            }
        }

        /// <summary>
        /// The type of record in MS DNS Server
        /// </summary>
        public class DNSRecordType
        {
            /// <summary>
            /// Create a new DNS record type
            /// </summary>
            /// <param name="textRepresentation">The type to create</param>
            public DNSRecordType(string textRepresentation)
            {
                _textRepresentation = textRepresentation;
            }
            private string _textRepresentation = "";

            /// <summary>
            /// The text representation of the record type
            /// </summary>
            public string TextRepresentation
            {
                get
                {
                    return _textRepresentation.ToUpper();
                }
            }

            private string _recordMode = "IN";

            /// <summary>
            /// The mode of the record, usually IN but could oneday be something else like OUT
            /// </summary>
            public string RecordMode
            {
                get
                {
                    return _recordMode;
                }
                set
                {
                    _recordMode = value;
                }
            }

            public override string ToString()
            {
                return _recordMode+" "+_textRepresentation;
            }

            #region Some Defaults!
            /// <summary>
            /// An alias
            /// </summary>
            public static DNSRecordType CNAME 
            {
                get    { return new DNSRecordType("CNAME"); }
            }

            /// <summary>
            /// An IPv4 address
            /// </summary>
            public static DNSRecordType A
            {
                get { return new DNSRecordType("A"); }
            }
            
            /// <summary>
            /// A reverse host address inside yoursubnet.in-addr.arpa
            /// </summary>
            public static DNSRecordType PTR
            {
                get { return new DNSRecordType("PTR"); }
            }
    
            /// <summary>
            /// An MX record (mail exchange)
            /// </summary>
            public static DNSRecordType MX
            {
                get { return new DNSRecordType("MX"); }
            }

            /// <summary>
            /// An IPv6 host address
            /// </summary>
            public static DNSRecordType AAAA
            {
                get { return new DNSRecordType("AAAA"); }
            }

            /// <summary>
            /// A text record
            /// </summary>
            public static DNSRecordType TXT
            {
                get { return new DNSRecordType("TXT"); }
            }

            /// <summary>
            /// A nameserver record (domain delegation)
            /// </summary>
            public static DNSRecordType NS
            {
                get { return new DNSRecordType("NS"); }
            }

            /// <summary>
            /// An SOA record (start of authority)
            /// </summary>
            public static DNSRecordType SOA
            {
                get { return new DNSRecordType("SOA"); }
            }

            #endregion
        }
        
#endregion

        /// <summary>
        /// Create a new DNS Server connection
        /// </summary>
        /// <param name="server">The hostname, IP or FQDN of a DNS server you have access to with the current credentials</param>
        public DNSServer(string server)
        {
            ConnectionOptions co = new ConnectionOptions();
            _scope = new ManagementScope(String.Format(@"\\{0}\Root\MicrosoftDNS", server), co);
            _scope.Connect();  //no disconnect method appears to exist so we do not need to manage the 
                               //persistence of this connection and tidy up
        }

        /// <summary>
        /// Create a new DNS Server connection
        /// </summary>
        /// <param name="server">The hostname, IP or FQDN of a DNS server you have access to with the current credentials</param>
        /// <param name="username">The username to connect with</param>
        /// <param name="password">The users password</param>
        public DNSServer(string server, string username, string password)
        {
            ConnectionOptions co = new ConnectionOptions();
            co.Username = username;
            co.Password = password;
            co.Impersonation = ImpersonationLevel.Impersonate;
            _scope = new ManagementScope(String.Format(@"\\{0}\Root\MicrosoftDNS", server), co);
            _scope.Connect();
        }

        private string _server = "";

        /// <summary>
        /// The server this connection applies to
        /// </summary>
        public string Server
        {
            get { return _server; }
        }

        private ManagementScope _scope = null;

        /// <summary>
        /// Return a list of domains managed by this instance of MS DNS Server
        /// </summary>
        /// <returns></returns>
        public DNSDomain[] GetListOfDomains()
        {
            ManagementClass mc = new ManagementClass(_scope, new ManagementPath("MicrosoftDNS_Zone"), null);
            mc.Get();
            ManagementObjectCollection collection =  mc.GetInstances();

            List<DNSDomain> domains = new List<DNSDomain>();
            foreach (ManagementObject p in collection)
            {
                domains.Add(new DNSDomain(p["ContainerName"].ToString(), p, this));
            }

            return domains.ToArray();
        }

        /// <summary>
        /// Return a list of records for a domain, note that it may include records
        /// that are stubs to other domains inside the zone and does not automatically
        /// recurse.
        /// </summary>
        /// <param name="domain">The domain to connect to</param>
        /// <returns></returns>
        public DNSRecord[] GetRecordsForDomain(string domain)
        {
            string query = String.Format("SELECT * FROM MicrosoftDNS_ResourceRecord WHERE DomainName='{0}'", domain);
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(_scope, new ObjectQuery(query));
            
            ManagementObjectCollection collection = searcher.Get();

            List<DNSRecord> records = new List<DNSRecord>();
            foreach (ManagementObject p in collection)
            {
                records.Add(new DNSRecord(p));
            }

            return records.ToArray();
        }

        /// <summary>
        /// Create a new DNS host record
        /// </summary>
        /// <param name="zone"></param>
        /// <param name="bindStyleHostEntry"></param>
        /// <returns></returns>
        public void CreateDNSRecord(string zone, string bindStyleHostEntry)
        {
            try
            {
                ManagementObject mc = new ManagementClass(_scope, new ManagementPath("MicrosoftDNS_ResourceRecord"), null);
                mc.Get();
                ManagementBaseObject parameters = mc.GetMethodParameters("CreateInstanceFromTextRepresentation");
                parameters["ContainerName"] = zone;
                parameters["DnsServerName"] = _server;
                parameters["TextRepresentation"] = bindStyleHostEntry;
                ManagementBaseObject createdEntry = mc.InvokeMethod("CreateInstanceFromTextRepresentation", parameters, null);
                //return createdEntry; (no reason unless you changed your mind and wanted to delete it?!)
            }
            catch (ManagementException) //the details on this exception appear useless.
            {
                throw new ApplicationException("Unable to create the record " + bindStyleHostEntry + ", please check"+
                    " the format and that it does not already exist.");
            }
        }

        /// <summary>
        /// Create a new DNS host record
        /// </summary>
        /// <param name="zone"></param>
        /// <param name="record"></param>
        public void CreateDNSRecord(string zone, DNSRecord record)
        {
            CreateDNSRecord(zone, record.ToString());
        }

        /// <summary>
        /// Fetch DNS records for a particular name
        /// WARNING: This method has performance issues, iterate over the results of getting all the records for a domain instead.
        /// </summary>
        /// <remarks>Returns a collection as one hostname/entry can have multiple records but it can take longer
        /// than getting all the records and scanning them!</remarks>
        /// <param name="hostName">The name to look up</param>
        /// <returns></returns>
        public DNSRecord[] GetExistingDNSRecords(string hostName)
        {
            string query = String.Format("SELECT * FROM MicrosoftDNS_ResourceRecord WHERE OwnerName='{0}'", hostName);
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(_scope, new ObjectQuery(query));

            ManagementObjectCollection collection = searcher.Get();
            List<DNSRecord> records = new List<DNSRecord>();
            foreach (ManagementObject p in collection)
            {
                records.Add(new DNSRecord(p));
            }

            return records.ToArray();
        }

        /// <summary>
        /// Create a new zone in MS DNS Server
        /// </summary>
        /// <param name="zoneName">The zone to create</param>
        /// <param name="zoneType">The type of zone to create</param>
        /// <returns>The domain</returns>
        public DNSDomain CreateNewZone(string zoneName, NewZoneType zoneType)
        {
            try
            {
                ManagementObject mc = new ManagementClass(_scope, new ManagementPath("MicrosoftDNS_Zone"), null);
                mc.Get();
                ManagementBaseObject parameters = mc.GetMethodParameters("CreateZone");

                /*
                [in]            string ZoneName,
                [in]            uint32 ZoneType,
                [in]            boolean DsIntegrated,   (will always be false for us, if you need AD integration you will need to change this.
                [in, optional]  string DataFileName,
                [in, optional]  string IpAddr[],
                [in, optional]  string AdminEmailName,
                */

                parameters["ZoneName"] = zoneName;
                parameters["ZoneType"] = (UInt32)zoneType;
                parameters["DsIntegrated"] = 0; //false
                ManagementBaseObject createdEntry = mc.InvokeMethod("CreateZone", parameters, null);
                DNSDomain d = new DNSDomain(zoneName, createdEntry, this);
                return d;
            }
            catch (ManagementException) //returns generic error when it already exists, I'm guessing this is a generic answer!
            {
                throw new ApplicationException("Unable to create the zone "+zoneName+", please check "+
                    "the format of the name and that it does not already exist.");
            }
        }

        public override string ToString()
        {
            return _server;
        }
    }
    #endregion
}
Permalink  8 Comments 

I was trying to get speech recognition to work as easily as text-to-speech synthesis and noticed that there's a gotcha in that you can't use it from an MTA STA thread, so you need to invoke it on another thread.  Calling BeginInvoke on an anonymous delegate instance of voidDelegate sorts this pretty easily and is a nice and brief method of avoiding the problem.

Here's the necessary code to make a blank form with two text boxes (called TextBox1 and TextBox2) do speech recognition continually.  To use this code you need a reference to System.Speech.DLL and a using clause pointing to System.Speech.Recognition.

Note that hypothesized text is also displayed, so you can see the speech recognition engine 'thinking' which is handy as it lets you tell if you need to do more training with the engine.

private void Form1_Load(object sender, EventArgs e)

{

       InitSpeechRecognition();

}

 

SpeechRecognitionEngine _recognitionEngine;

 

public void InitSpeechRecognition()

{

       voidDelegate d = new voidDelegate(initSpeechRecognition);

       d.BeginInvoke(null, null);

}

 

private delegate void voidDelegate();

 

private void initSpeechRecognition()

{

       _recognitionEngine = new System.Speech.Recognition.SpeechRecognitionEngine();

       _recognitionEngine.SetInputToDefaultAudioDevice();

       DictationGrammar d = new DictationGrammar();

       d.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(d_SpeechRecognized);

       _recognitionEngine.UnloadAllGrammars();

       _recognitionEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(r_SpeechHypothesized);

       _recognitionEngine.RecognizeCompleted += new EventHandler<RecognizeCompletedEventArgs>(r_RecognizeCompleted);

       _recognitionEngine.LoadGrammar(d);

       _recognitionEngine.RecognizeAsync();

}

 

void r_RecognizeCompleted(object sender, RecognizeCompletedEventArgs e)

{

       BeginRecognition();

}

 

delegate void SpeechHypothesizedPassThroughDelegate(object sender, SpeechHypothesizedEventArgs e);

 

void r_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)

{

       if (this.InvokeRequired)

       {

              this.Invoke(new SpeechHypothesizedPassThroughDelegate(r_SpeechHypothesized), sender, e);

       }

       else

       {

              textBox2.Text = e.Result.Text;

       }

}

 

delegate void SpeechPassThroughDelegate(object sender, SpeechRecognizedEventArgs e);

 

void d_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)

{

       if (this.InvokeRequired)

       {

              this.Invoke(new SpeechPassThroughDelegate(d_SpeechRecognized), sender, e);

       }

       else

       {

              //display the recognised text, or process it here

              textBox1.Text += e.Result.Text + " ";

       }

}

 

private void BeginRecognition()

{

       new voidDelegate(delegate()

       {

              _recognitionEngine.RecognizeAsync();

       }).BeginInvoke(null, null);

}

 

private void StopRecognition()

{

       new voidDelegate(delegate()

       {

              _recognitionEngine.RecognizeAsyncStop();

       }).BeginInvoke(null, null);

}

Permalink 

I wanted to run a bunch of methods simultaneously on as many threads as possible to get the job done, but still wait at the end.  I know MS have something coming to solve this, but wanted a lightweight solution, so here it is:

public class Parallel
{
       public static T[] ExecuteWaitAll<T>(Func<T>[] functions)
       {
              List<T> resultSet = new List<T>();
              int i = 0;
              object lockObject = new object();
              foreach (Func<T> function in functions)
              {
                     lock (lockObject)
                     {
                           i++;
                           function.BeginInvoke(delegate(IAsyncResult result)
                           {
                                  lock (lockObject)
                                  {
                                         resultSet.Add(function.EndInvoke(result));
                                         i--;
                                  }
                           }, null);
                     }
              }
 
              while (i > 0)
              {
                     Thread.Sleep(1);
              }
              return resultSet.ToArray();
       }
}

To use this, you simply call it with a list of delegates you want to execute, and define the return type:

public void ExecuteWait()
{
       List<Func<int>> list = new List<Func<int>>();
       for (int i=0; i<100; i++)
       {
              list.Add(new Func<int>(delegate()
                     {
                           Thread.Sleep(1000);
                           return 1;
                     }));
       }
      
       int[] quantity = Parallel.ExecuteWaitAll<int>(list.ToArray());
       int count = 0;
       foreach (int result in quantity)
       {
              count += result;
       }
}

The result is now valid for 100 executions but took a lot less time than 100 seconds to calculate.  You could of course just be running four things at the same time, all different using this.

Permalink 

This is really simple but annoyed me for a few minutes until I got .NET Reflector up, so hopefully this will help someone else.

The render method on ASP.NET WebControl based server controls seems to be adding a span tag around the HTML output for some reason, to fix this simply override the Render method:

protected override void Render(HtmlTextWriter writer)
{
    RenderContents(writer);
}

Permalink 

There's an article on MSDN about how to host the Windows Workflow Foundation design surface (which is a redistributable).

The example code is really complete and worth a look at, it's almost an out-of-the-box copy of just the workflow designer from Visual Studio.

If your end user requires more flexibility than most you can offer them drag-and-drop customisation of particular processes in your system (like creating a new customer could be made to go off and send details to a webservice without you, the developer; needing to get involved).

Permalink 

Just a single snippet of code to work from, I included explanations in the comments. This is really a very easy to use feature in C# 3. Unfortunately you can’t create extension properties yet, but that will likely be coming soon.

namespace ExtensionMethods
{
       //Note that this class is static, it must be to contain extension methods and
       //it also can't reside inside another class.
       public static class ExampleExtensionMethod
       { 
              //This is the extension method
              public static bool HasLetterAInIt(this string s)
              {
                     //Just return if it contains the capital letter A as this is just an
                     //example
                     return s.Contains("A");
              }
       }
      
       class Program
       {
              static void Main(string[] args)
              {
                     //This will print false
                     Console.WriteLine("TEST".HasLetterAInIt().ToString());
                     //whilst this will print true
                     Console.WriteLine("AAHH!!".HasLetterAInIt().ToString());
              }
       }
}

Permalink 

Create a .NET 3.5 Console, Windows Forms or WPF project, add an SQL Compact Edition local database, I left the default name of Database1.sdf for the example. Just right click and open it from solution explorer and add some tables. I added two tables:  Person and Pet, with a relationship between the two (right click the child table, choose properties to get the add relationship option).

Next you want to add a command to visual studios tools menu, using Tools, External Tools… This command will allow you to generate a Linq To SQL DBML file which describes the contents of the database. Once we have that Linq is perfectly compatible with SQL Compact Edition – but the Visual Studio design tools aren’t so we need to do this manually.
Title:  Make &Linq classes for Database
Command:  C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SqlMetal.exe
Arguments: $(ItemPath) /dbml:$(ItemFileName).dbml
Initial Directory: $(ItemDir)
Now this tool will let you generate your DBML, select your Database1.sdf file then choose Tools, “Make Linq classes for Database”. It should pop up and seemingly do something in a command prompt.
Now right click your project, choose Add existing item and then change the filetype to either Data Files or All files. You should see there’s a new file called Database1.dbml – select this file and add it to your solution.
Bingo! It is now available to be edited in Linq – you can double click this dbml file and you’ll get the designer up – it should show your classes (NOTE: At this point I should add that relationships weren’t automatically generated for compact edition).
Now it’s time to use Linq to actually connect and query/save some data. This is where Linq takes a lot of the hassle out of building software that talks to databases, it simply works.
static void Main(string[] args)
{
       //Connect to the database itself.
       using (Database1 db = new Database1("Database1.sdf"))
       {
              //This is easy because we used SqlMetal to generate
              //the dbml targetting an SQL Compact edition database.
              //Normally you'd have to specify a full connection string.
 
              //obviously remove these two lines if you don't want to start with an empty database each time.
              db.Person.DeleteAllOnSubmit(db.Person);
              db.SubmitChanges();
 
              //Create a couple of Person entities
              Person simon = new Person();
              simon.Name = "Simon";
              simon.EMail = "me@myhost";
 
              //and a cat for me
              Pet cat = new Pet();
              cat.Name = "Fluffy";
              simon.Pets.Add(cat);
 
              db.Person.InsertOnSubmit(simon);
 
              Person fred = new Person();
              fred.Name = "Fred";
              fred.EMail = "them@myhost";
              db.Person.InsertOnSubmit(fred);
 
              //now actually add them to the database
              db.SubmitChanges();
 
              //Select the names of some people                                   
              var names = from Person p in db.Person
                                  select p.Name;
 
              //Print those names
              foreach (string name in names)
              {
                     Console.WriteLine(name);
              }
 
              //but you can also get back the entities instead of just names
              //this is handy if you require more than just one item for a particular person
              var people = from Person p in db.Person
                                   select p;
 
              foreach (Person person in people)
              {
                     Console.WriteLine(String.Format("{0} has an e-mail adddress of {1}", person.Name, person.EMail));
              }
 
              //but what if you want multiple items not all in one person?
              //well you can use anonymous classes
              var peopleAndPets = from Person p in db.Person
                                                orderby p.Pets.Count descending
                                                select new { p.Name, p.Pets.Count };
 
              //this is where the var keyword becomes essential. peopleAndPets
              //is not of a type that can be described before compilation.
              foreach (var quantity in peopleAndPets)
              {
                     Console.WriteLine(String.Format("{0} has {1} pets", quantity.Name, quantity.Count.ToString()));
              }
       }
 
       Console.WriteLine("The example is over!");
       Console.ReadKey();
}
Permalink  1 Comments 

This is really easy and quick, but something that is handy. Getting speech synthesis to work under .NET 3.0 is really a breeze.

First, add a reference to System.Speech – this contains the managed speech API, it allows you to do recognition and synthesis extremely easily.
Next, add the following to an empty console application/button click event:
using (System.Speech.Synthesis.SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
     synth.SelectVoiceByHints(System.Speech.Synthesis.VoiceGender.Female, System.Speech.Synthesis.VoiceAge.Teen, 0);
     synth.Speak("Hello world!");
}
And you’re done! That should have taken less than a minute if your references dialog didn’t take ages to load.
If you have Microsoft Anna (you have Windows Vista, Autoroute or Streets and Trips installed) then this will use that preferentially (that’s the SelectVoiceByHints line), otherwise it may use Microsoft Sam which sounds pretty bad but works well.
Permalink  3 Comments 

There's a limit on the data sent and recieved in WCF, resulting in errors like this when the webservice sends back larger messages:

"The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element."

The fix for this is to create a new binding with much larger limits:

System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding();
binding.MaxBufferSize = 1024 * 1024 * 2; //bit bigger than default
binding.MaxReceivedMessageSize = 1024 * 1024 * 2;
binding.ReaderQuotas.MaxStringContentLength = 1024 * 1024 * 2;
ServiceReference1.MyServicesSoapClient client = new ServiceReference1.MyServicesSoapClient(binding, new System.ServiceModel.EndpointAddress("http://myservice/service.asmx"));

Permalink 

Just a reminder to myself, to let a user run an application pool without granting silly rights, you just need to run:

aspnet_regiis -ga <machine>\<user>

Which grants rights to the metabase and the temporary files folder.

Permalink 

Just a quick note so I can look it up easier later :)  - Simply call EnableGlass(); in the Form load event and it'll change the form to support glass.

You also need to implement support for changing the colour scheme of Vista and it needs to invalidate the form after running EnableGlass - a call to this.Invalidate();

private void EnableGlass()

{

       if (Environment.OSVersion.Version.Major >= 6) //check for vista

       {

              DwmEnableComposition(true);

              DWM_BLURBEHIND d = new DWM_BLURBEHIND();

              d.dwFlags = DWM_BLURBEHIND.DWM_BB_BLURREGION | DWM_BLURBEHIND.DWM_BB_ENABLE;

              d.fEnable = true;

              d.hRegionBlur = IntPtr.Zero;

              DwmEnableBlurBehindWindow(this.Handle, d);

              Paint += new PaintEventHandler(Glass_Paint);

       }

}

 

[StructLayout(LayoutKind.Sequential)]

public class DWM_BLURBEHIND

{

       public uint dwFlags;

       [MarshalAs(UnmanagedType.Bool)]

       public bool fEnable;

       public IntPtr hRegionBlur;

       [MarshalAs(UnmanagedType.Bool)]

       public bool fTransitionOnMaximized;

 

       public const uint DWM_BB_ENABLE = 0x00000001;

       public const uint DWM_BB_BLURREGION = 0x00000002;

       public const uint DWM_BB_TRANSITIONONMAXIMIZED = 0x00000004;

}

 

[DllImport("dwmapi.dll", PreserveSig = false)]

public static extern void DwmEnableComposition(bool bEnable);

 

[DllImport("dwmapi.dll", PreserveSig = false)]

public static extern bool DwmIsCompositionEnabled();

 

[DllImport("dwmapi.dll", PreserveSig = false)]

public static extern void DwmEnableBlurBehindWindow(IntPtr hWnd, DWM_BLURBEHIND pBlurBehind);

 

private void Glass_Paint(object sender, PaintEventArgs e)

{

       if (Environment.OSVersion.Version.Major >= 6)

       {

              if (DwmIsCompositionEnabled())  //check Aero is enabled

              {

                     e.Graphics.FillRectangle(Brushes.Black, this.ClientRectangle);

              }

       }

}

Permalink 

using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;

 
namespace WCFTest
{
       ///<summary>
       /// A data contract stores some data and allows it to be serialised for passing to OperationContract's
       ///</summary>
       [DataContract]
       class Thing
       {
              ///<summary>
              /// Some data that will be filled.
              /// This can be a property and the getter and setter will be called on it when it is filled with data.
              ///</summary>
              [DataMember]
              public string SomeData = "";
       }
 
       [ServiceContract]
       interface IDoStuff
       {
              ///<summary>
              /// Jump method
              ///</summary>
              [OperationContract]
              void Jump();
              ///<summary>
              /// Duck method
              ///</summary>
              [OperationContract]
              void Duck();
              ///<summary>
              /// Hide method
              ///</summary>
              ///<param name="thingy">A parameter DataContract to be passed</param>
              [OperationContract]
              void Hide(Thing thingy);
       }
 
       ///<summary>
       /// This is the class that provides the actual code to do the work, it conforms to the contract defined earlier.
       ///</summary>
       class StuffWorker : IDoStuff
       {
              #region IDoStuff Members
              ///<summary>
              /// The jump method, with code
              ///</summary>
              public void Jump()
              {
                     Console.WriteLine("Jump: Remote method executing here.");
              }
              ///<summary>
              /// The duck method with code
              ///</summary>
              public void Duck()
              {
                     Console.WriteLine("Duck: Another remote method executing here.");
              }
              ///<summary>
              /// Hide something method
              ///</summary>
              ///<param name="thingy">The item to hide</param>
              public void Hide(Thing thingy)
              {
                     Console.WriteLine("Hiding: Remote method is hiding " + thingy.SomeData);
              }
              #endregion
       }
       ///<summary>
       /// A self hosting WCF service that does not use the configuration file
       ///</summary>
       class Program
       {
              ///<summary>
              /// Program start
              ///</summary>
              ///<param name="args"></param>
              static void Main(string[] args)
              {
                     Console.Write("Starting the service...");
                     ServiceHost host = start();
                     Console.WriteLine("Ok");
                     Console.ReadKey();
              }
 
              static ServiceHost start()
              {
                     //this does the hosting
                     ServiceHost host = new ServiceHost(typeof(StuffWorker), new Uri("http://localhost:7000/WCF/"));
                     //this lets you browse to the WSDL:
                     ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                     smb.HttpGetEnabled = true;
                     smb.HttpGetUrl = new Uri("http://localhost:7000/WCF/Meta");
                     host.Description.Behaviors.Add(smb);
                     //This is the bit that handles HTTP
                     WSHttpBinding ws = new WSHttpBinding(SecurityMode.None);
                     Binding mex = MetadataExchangeBindings.CreateMexHttpBinding();
                     //These are the endpoints on that HTTP server
                     host.AddServiceEndpoint("WCFTest.IDoStuff", ws, "http://localhost:7000/WCF/DoStuff"); //one to actually do things
                     host.AddServiceEndpoint(typeof(IMetadataExchange), mex, "http://localhost:7000/WCF/Meta"); //and one to provide metadata
 
                     // start listening
                     host.Open();
                     return host;
              }
       }
}

A self hosting service example mostly so I don't forget how.  Remember to add references to System.ServiceModel and System.Runtime.Serialisation!

Permalink  3 Comments 

Getting a long PageRequestManagerParserErrorException error with some HTML in it when using ASP.NET Ajax with something like a Gridview?  Does the error only happen once in a while, usually the first time you do something specific after a long delay?

Know you're not actually using Response.Write and only using MS controls?

Well, maybe asp.net is trying to do a postback for you to create a cookie when you are using the session variable.

Solution: A dirty solution was calling Session["IWantASessionCookie"] = true; on a page load, after this the problem went away as ASP.NET didn't need to create the local cookie when doing things in the UpdatePanel as it had already done it.

Anybody have a neater solution to extend ASP.NET Ajax to create the cookie automatically using client side Javascript instead of ASP.NET trying to do it normally?

Permalink 

Just a handy little method I chucked together that might be useful when prototyping stuff in command line applications:

/// <summary>
/// Draw a progress bar at the current cursor position.
/// Be careful not to Console.WriteLine or anything whilst using this to show progress!
/// </summary>
/// <param name="progress">The position of the bar</param>
/// <param name="total">The amount it counts</param>

private static void drawTextProgressBar(int progress, int total)
{
 //draw empty progress bar
 Console.CursorLeft = 0;
 Console.Write("["); //start
 Console.CursorLeft = 32;
 Console.Write("]"); //end
 Console.CursorLeft = 1;
 float onechunk = 30.0f / total;
 
 //draw filled part
 int position = 1;
 for (int i = 0; i < onechunk * progress; i++)
 {
  Console.BackgroundColor = ConsoleColor.Gray;
  Console.CursorLeft = position++;
  Console.Write(" ");
 }

 //draw unfilled part
 for (int i = position; i <= 31; i++)
 {
  Console.BackgroundColor = ConsoleColor.Black;
  Console.CursorLeft = position++;
  Console.Write(" ");
 }

 //draw totals
 Console.CursorLeft = 35;
 Console.BackgroundColor = ConsoleColor.Black;
 Console.Write(progress.ToString() + " of " + total.ToString()+"    "); //blanks at the end remove any excess
}

Permalink  2 Comments 

This is just a quick example so I don't forget how to search generic lists easily and have to hunt for it again, but I've fleshed it out so it will hopefully be of help to someone else!

//Set up our example generic List
List<string> myItems = new List<string>();
myItems.Add("This isn't going to be found");
myItems.Add("Nor this");
myItems.Add("But it will find this example for nullify!");
myItems.Add("And it will find this nullify example too!");
//This is our search term, it is a local variable
string localVariable = "nullify";

//Do the search using a Predicate<> delegate here.
//
//This can point to a method that takes a parameter of the type, but
//doing that will result in not being able to pass parameters to the
//method (its parameters are predefined as the type, with a boolean
//return as far as I can see). We get around this by using an
//anonymous delegate, so it is inline and can access local variables

string[] matches = myItems.FindAll(delegate(string searchItem) {
    //this is an anonymous delegate, that
    return searchItem.IndexOf(localVariable)>-1;
}).ToArray();

 

Updated 7/2/2010: You could also use a Lambda expression to do this with a few less characters:-

string[] matches = myItems.FindAll(searchItem => {
    //this is an anonymous delegate, that 
    return searchItem.IndexOf(localVariable)>-1; 
}).ToArray();

Permalink 

Here's a static method that sets a printer as the default on a system, using the windows scripting host network stuff from C#.  It's here so I can look it up if anyone else asks in future since I couldn't easily find how to do this in C#...  (I know the exception handling is poor)

/// <summary>
/// Sets a default printer
/// </summary>
/// <param name="name"></param>
public static void SetDefaultPrinter(string name)
{
   try
   {
      //late bind to the wsh network com object
      //create an instance of a reflection type
      Type t = Type.GetTypeFromProgID("WScript.Network");
      //create an instance using the system activator, consuming the type
      Object o = Activator.CreateInstance(t);
      //invoke the method using the object we created
      t.InvokeMember("SetDefaultPrinter", System.Reflection.BindingFlags.InvokeMethod, null, o, new object[] {name});
   } 
   catch (Exception)
   {
      throw new Exception("Unable to set a default printer. The printer may not exist or the WScript.Network com object may have a problem.");
   }
}

Permalink 

[ Taken from my post at the ms forums here: http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=1014 ]

This is a bit bodged but I just hashed it together to see how easy it would be.  I thought back and could have just iterated over chararray, but it works which is what counts :D

/// <summary>
///
Represents a paragraph in English
///
</summary>
public
abstract class Paragraph
{
///
<summary>
///
Convert a string in arbitrary case to English sentence capitalisation.
///
</summary>
/// <param name="text">The text to convert
</param>
/// <returns>The paragraph of text
</returns>
public
static string ToSentenceCase(string text)
{
string
temporary = text.ToLower();
string
result = "";
while
(temporary.Length>0)
{
string
[] splitTemporary = splitAtFirstSentence(temporary);
temporary = splitTemporary[1];
if
(splitTemporary[0].Length>0)
{
result += capitaliseSentence(splitTemporary[0]);
}
else
{
result += capitaliseSentence(splitTemporary[1]);
temporary =
""
;
}
}
return
result;
}

private static string capitaliseSentence(string sentence)
{
string
result = "";
while
(sentence[0]==' ')
{
sentence = sentence.Remove(0,1);
result+=
" "
;
}
if
(sentence.Length>0)
{
result += sentence.TrimStart().Substring(0, 1).ToUpper();
result += sentence.TrimStart().Substring(1, sentence.TrimStart().Length-1);
}
return
result;
}

private static string[] splitAtFirstSentence(string text)
{
//these are the characters to start a new sentence after
int
lastChar = text.IndexOfAny(new
char[] {'.', ':', '\n', '\r', '!', '?'})+1;
if
(lastChar==1)
{
lastChar = 0;
}
return
new string[] { text.Substring(0, lastChar), text.Substring(lastChar, text.Length-lastChar) };
}
}

Permalink 

[posted by me on the new Microsoft Forums at http://forums.microsoft.com/msdn/ShowPost.aspx?PostID=1266 ]

ProcessStartInfo pi = new ProcessStartInfo("cmd.exe", "/c dir");
pi.WindowStyle = ProcessWindowStyle.Hidden;
pi.RedirectStandardOutput =
true
;
pi.UseShellExecute =
false
;
Process p = Process.Start(pi);
p.WaitForExit();
p.Start();
TextReader t = p.StandardOutput;
MessageBox.Show(t.ReadToEnd());

Permalink 

A colleague of mine at work was having some trouble with multithreading this morning and I suggested using asynchronous delegates (a delegate - something you can make do something else, in .NET this can be used as a form of trigger for starting any number of other methods that take and return the same parameters as it uses - that runs its methods in another thread).  This got me thinking so I decided to do a quick tutorial for anyone else who hasn't yet encountered this way of doing multithreading!

This is a short sharp example, and can be created in a simple form.  Remember not to try to update the form from the method being run by the delegate - if you want to do this you need to run a method that checks if InvokeRequired is true, then runs Invoke(myMethodsOwnName, new object {myFirstParameter, mySecondParameter, andSoOn}) if it is true, or does whatever UI editing is needed if false - so it is calling itself in the context of the user interface.

Anyway, on with the example!

/// <summary>
///
A button on the form
///
</summary>
private
void button1_Click(object sender, System.EventArgs e)
{
   delegateInstance = new
ExampleDelegate(beginThink);
   d.BeginInvoke(5, new
AsyncCallback(finished), null);
}

This is where the program runs, a simple button that can be pressed.  We want to do something CPU intensive and blocking in here but instead we create an instance of a delegate and use the BeginInvoke method, the methods parameters come first (in this case 5) and then the callback method to run, and null for the object state.

/// <summary>
///
An instance of the delegate used to call a method asynchronously
///
</summary>
private
ExampleDelegate delegateInstance;

/// <summary>
///
The example delegate
///
</summary>
private
delegate string ExampleDelegate(int param);

/// <summary>
///
The example method that would block the user interface
///
</summary>
/// <param name="workOn">Number of seconds to block for
</param>
/// <returns>Some string
</returns>
private
string beginThink(int workOn)
{
   Thread.Sleep(workOn*1000);
   return
"Done";
}

This is our ficticious CPU intensive action, in this case we'll just block the thread by seeping for workOn seconds.

/// <summary>
///
The method that is called when work is done
///
</summary>
/// <param name="results">The results of the work
</param>
private
void finished(IAsyncResult results)
{
   MessageBox.Show(delegateInstance.EndInvoke(results));
}

And this is run when the asynchronous delegate is completed.  EndInvoke automatically return the same type as the delegate, (a string) which makes this nice and easy.

Permalink 

Have you ever wanted to be able to add scripting to your application?  So your users can write a script and you can have it run inside it, adding menus, etc. - like Microsoft Visual Basic for Applications allows in Office.

This is a preliminary article, I'll try to rewrite this but I just took a 20 minute break from work (need to have something done for tomorrow - so yes, still working at 10PM!  GRR) and finally managed to get scripting using Microsoft.VSA working from a C# application.  Apologies for the lack of tabs in the formatting and lack of explanation.

This is missing the ability to access anything in the running application - you need to register a global item (in the same way as code items and references are added) to do that - then it is exposed as an object inside the environment running the script.

Add references to Microsoft.VisualBasic.Vsa and Microsoft.Vsa (when I repost I'll be using JScript.NET - never fear!) and add the following using clauses:

using System.Reflection;

using Microsoft.Vsa;

using Microsoft.Win32;

And then add the following code to a button or similar (with a textbox to enter your script in) - this will create a scripting engine object, then run your script inside it.  The best test is to show a message using MessageBox.Show(""); (remember though, it's VB!)

ScriptEngine eng = new ScriptEngine();
eng.Start();
IVsaCodeItem c = eng.CreateCodeItem(
"ScriptItem");
c.SourceText = textBox1.Text; //Where this is a simple vb.net script with a class called Script and a Sub called Main
eng.Run();

And now, the main code chunk snippet that is the scripting engine:

public class ScriptEngine : IVsaSite
{
private IVsaEngine Engine;
public ScriptEngine()
{
Start();
}

public void Start()
{
try
{
Engine =
new Microsoft.VisualBasic.Vsa.VsaEngine();
Engine.RootMoniker =
"myapp://net.nullify.www/ScriptEngine";
Engine.Name =
"vsaEngine";
Engine.RootNamespace =
"VsaEngine";
Engine.Site =
this;
Engine.InitNew();
CreateReference(
"Mscorlib.dll");
CreateReference(
"System.dll");
CreateReference(
"System.Windows.Forms.dll");
CreateReference(
"System.Data.dll");
CreateReference(
"System.Drawing.dll");
CreateReference(
"System.XML.dll");
}
catch (VsaException ex)
{
MessageBox.Show(
"Scripting engine error: "+ex.Message);
}
}

public IVsaReferenceItem CreateReference(string assemblyName)
{
IVsaReferenceItem item = (IVsaReferenceItem)Engine.Items.CreateItem(assemblyName, VsaItemType.Reference, VsaItemFlag.None);
item.AssemblyName = assemblyName;
return item;
}

public IVsaCodeItem CreateCodeItem(string itemName)
{
try
{
IVsaCodeItem item = (IVsaCodeItem)Engine.Items.CreateItem(itemName, VsaItemType.Code, VsaItemFlag.Class);
return item;
}
catch (VsaException ex)
{
MessageBox.Show(
"Problem creating the code item: "+ex.Message);
}
return null;
}

public void Run()
{
if (Engine.Compile())
{
Engine.Run();
Type type = Engine.Assembly.GetType(
"VsaEngine.Script");
MethodInfo method = type.GetMethod(
"Main");
method.Invoke(
null, null);
}
}

#region IVsaSite Members

public object GetEventSourceInstance(string itemName, string eventSourceName)
{
// TODO: Add ScriptEngine.GetEventSourceInstance implementation
return this;
}

public object GetGlobalInstance(string name)
{
// TODO: Add ScriptEngine.GetGlobalInstance implementation
return null;
}

public void Notify(string notify, object info)
{
// TODO: Add ScriptEngine.Notify implementation
}

public bool OnCompilerError(IVsaError error)
{
MessageBox.Show(
"["+error.Line+"] Compiler error: "+error.Description);
return true;
}

public void GetCompiledState(out byte[] pe, out byte[] debugInfo)
{
// TODO: Add ScriptEngine.GetCompiledState implementation
pe = null;
debugInfo =
null;
}

#endregion

}

And finally to test this you can use the following code:

imports System
imports System.Diagnostics

module Script
sub Main()
MessageBox.Show("Boo")
end sub
end module

Permalink  2 Comments 

This is some code I wrote a little while back as an example OR mapper.  When inheriting from BaseDataDynamicEntity you can use the attribute [DataDynamic(“Name”)] to indicate the field name in the database and then use the class below to fetch data from the database or update it with any changes.

 

This is just an example though and doesn’t do the updating – but instead returns an array of string that can be used to look at what’s in the object now.  Return a set of SqlParameter’s and plug it into a stored procedure for a working example.

 

      public abstract class BaseDataDynamicEntity

      {

            /// <summary>

            /// An attribute to use to work out which properties have names that are in the database

            /// </summary>

            public class DataDynamic : Attribute

            {

                  public DataDynamic(string fieldName)

                  {

                        _fieldName = fieldName;

                  }

                  /// <summary>

                  /// The name of the field in the database

                  /// </summary>

                  public string FieldName

                  {

                        get

                        {

                              return _fieldName;

                        }

                  }

                  private string _fieldName = "";

            }

 

            /// <summary>

            /// Return a set of properties on this class as a demonstration of what is possible

            /// </summary>

            /// <returns></returns>

            public string[] ListDataProperties()

            {

                  Type t = this.GetType();

                  PropertyInfo[] p = t.GetProperties();

                  ArrayList properties = new ArrayList();

                  foreach (PropertyInfo pi in p)

                  {

                        if (pi.IsDefined(typeof(DataDynamic), true))

                        {

                              properties.Add(pi.Name+": "+pi.GetValue(this, null).ToString()); //could instead write these out to some parameters.

                        }

                  }

                  string[] values = new string[properties.Count];

                  properties.CopyTo(values);

                  return values;

            }

 

            /// <summary>

            /// Given an SqlDataReader from ExecuteReader, fetch a set of data and use it to fill the child objects properties

            /// </summary>

            /// <param name="dr"></param>

            public void SetDataProperties(SqlDataReader dr)

            {

                  while (dr.Read())

                  {

                        for (int i = 0; i<dr.FieldCount; i++)

                        {

                              setProperty(dr.GetName(i), dr.GetValue(i));

                        }

                  }

                  dr.Close();

            }

 

            private void setProperty(string name, object data)

            {

                  Type t = this.GetType();

                  PropertyInfo[] p = t.GetProperties();

                  foreach (PropertyInfo pi in p)

                  {

                        if (pi.IsDefined(typeof(DataDynamic), true)&&pi.CanWrite)

                        {

                              object[] fields = pi.GetCustomAttributes(typeof(DataDynamic), true);

                              foreach (DataDynamic d in fields)

                              {

                                    if (d.FieldName == name)

                                    {

                                          pi.SetValue(this, data, null);

                                    }

                              }

                             

                        }

                  }

            }

      }

 

And to use this, you do something like:

 

      public class NewsArticle: BaseDataDynamicEntity

      {

            private int _id = 5;

            /// <summary>

            /// The Id in the database

            /// </summary>

            [DataDynamic("id")]

            public int Id

            {

                  get

                  {

                        return _id;

                  }

                  set

                  {

                        _id = value;

                  }

            }

 

            private string _name = "Demo object";

            /// <summary>

            /// The name in the database

            /// </summary>

            [DataDynamic("subject")]

            public string Name

            {

                  get

                  {

                        return _name;

                  }

                  set

                  {

                        _name = value;

                  }

            }

      }

 

Which makes populating it as easy as:

 

SqlConnection sq = new SqlConnection("Data Source=(local);InitialCatalog=nullifydb;Integrated Security=SSPI;");

      sq.Open();

      SqlCommand sc = sq.CreateCommand();

      sc.CommandText = "SELECT TOP 1 * FROM newsarticle";

NewsArticle n = new NewsArticle();

      n.SetDataProperties(sc.ExecuteReader());

      sq.Close();

 

Obviously this is just an example, and you would want to use a DAL of some sort to do the data extraction, but integrating the DAL with the above technique should be fairly easy.

Permalink 

This is something I posted to a mailing list in response to a question, but since posting it I've also been asked some questions which it answers - so, here is a VERY quick rundown of DNS:

> I basically need:

>

> (a) An overview of all the bits in the process – so I know I haven’t

> missed something obvious!

DNS is a tiered, cached method of querying some form of data, not necessarily a name, not necessarily an IP, not necessarily a text record, location, what the router for a network is, what the Kerberos/LDAP servers for a domain are, etc.

It uses the format:

Name dot

To distinguish a part, therefore (taking my own domain as an example) it is not really:

Nullify.net

But instead:

Nullify.net.

However the last dot is commonly left off for convenience incorrectly.  One or more domains controlled as a single entity on a server is called a 'zone'.

The bits that make up DNS from a practical standpoint consist of:

- A resolver

- A cache

- An authoritative server

The resolver is what exists on every persons computer, and on the ISP's nameservers along with a cache.  The resolver requests from the default DNS servers for the current dns 'zone' any desired records - in the case of a site that is in the root zone, or wants to query the root set of DNS servers there are a set of root servers, located at root-servers.net.  These can be extracted using dig, and have always stayed at the same IP - although one of these servers got a new multicast IP a short while ago.  Once a result (or NXDOMAIN, indicating there isn't a result) is retrieved - it is stored in the cache along with it's time to live (ttl).

The cache is the reason a small number of servers can support the whole Internet (obviously there's a lot behind the scenes, but the point still holds).  The vast majority of traffic is handled by the caches at every stage.  There will commonly be as many as four caches between an authoritative nameserver and a client.  The TTL maintains how long these hold a record of those results, and this is why DNS changes take so long.  The exact same cache is also used on a secondary nameserver, but rather than the TTL for records, the TTL for the zone itself is used.

An authoritative nameserver is a server that knows something itself.  It responds with a particular record for a particular domain - assuming anyone asks it.  There are both master and slave servers - a master holds the file that actually stores the data, the slave stores it in memory and relies on the TTL for the zone itself to decide how long it is authoritative.  The slave uses the zones serial number to decide whether a change has been made, and refreshes every time the refresh property of the SOA record for a zone has been expired.

>

> (b) An idea of how to set up the Windows Server as the primary nameserver

> (not sure if this is a good idea)

For windows you just create a zone and create the desired records.  From then on it will answer as a nameserver and can be queried by a machine looking at it as the default nameserver, or using nslookup/dig with it set as the default.

You then need to point a server on the internet for the domain you are adding a record to (say, net. Or com.!) to think it is the nameserver for a domain, and you require either an out of zone A record for it, or a glue record for it so that the IP of your own server can be resolved in order to go query it for the details of your domain!

To simplify this, for my domain I have a primary nameserver xerxes.nullify.net. at 2002:4262:b24a::4262:b24a and 66.98.178.74

This means that in order for xerxes to host nullify.net, the nameservers for net. Need to also contain both AAAA and A records for it.  A records resolve to a host.  (AAAA is ipv6, which you don't need to worry about yet).  You should request these records are created in advance for ALL nameservers that do not already have glue records.  The contact for the netblock the servers are hosted in may be contacted by some TLD providers, but net. And com. Don't do this.

Once you have glue records that have propagated to all the servers for the zone they are in, you need to ask them to delegate a hostname for you - this is your domain and results in your domain being set to use your nameservers - this is an NS record, and there will be one for each nameserver that knows that domain.

>

> (c) An idea of how to configure secondary nameservers

Create a secondary zone, pointed to yourdomain.tld. - note the last dot.  Then you need to make sure you secondary server has a glue record in your TLD and an A record in your domain, add an NS record to YOUR copy of the domain pointing to the nameserver, and finally have it added as an additional NS record to the TLD's servers.

>

> (d) An overview of how MX records work

An MX record is a mail exchanger record, when you send mail to a host the following happens:

- An attempt to resolve it as an A record occurs.

- An attempt to resolve it as an MX record occurs.

   - Each returned MX record points to an A record that is resolved.

      - Mail delivery is attempted at the A records in order of weighting.

The MX records take priority, to allow an A record to exist for a host, but that host not to receive mail.

MX records have a weighting, the lowest takes mail first, then if that is down the next highest, and so on.  MX records with the same weighting are attempted randomly.

If all MX records bounce, the message is queued but eventually bounces with a failure.  If there are no MX records, and no A record, the mail bounces instantly.  If there is an A record, delivery is attempted and on failure, it bounces instantly.

>

> (d) An overview of Reverse DNS records (and whether I need these)

>

You do need these to deliver mail, you also need these if you wish to run a netblock, since it can be revoked by the issuer if you fail to do so.

As the owner for a netblock, you also have rights to a second domain - in in-addr.arpa.

This domain follows the reverse of an IP, so it can be followed down through the ownership chain, for example if RIPE issued you the address space 192.168.0.0/24 you would have the zone:

0.168.192.in-addr.arpa.

You could set up www here, but it wouldn't be much use.  More use would be to set up a PTR record for your SMTP server, which is at 192.168.0.8:

8.0.168.192 PTR mymail.mydomain.tld.

Note that when working with DNS you really do need the final dot, otherwise it'll exist in your current domain.  This is the common cause of lots of problems like cname's not resolving correctly and instead trying to go to mymail.mydomain.tld.mydomain.tld.

A cname is an alias.

------

Records you need to know about are:

SOA - the actual domain as it is stored on your system.

A - a hostname to IP

PTR - an ip to hostname

SVR - a common service (e.g. - ldap and Kerberos to log in to active directory in a domain)

MX - mail exchanger

CNAME - an alias, or common name

TEXT - information or other details

You can explore from the client side and test everything is working by using nslookup.

To use nslookup, open a command prompt, define what record type you want, and type the name of the record.

For example:

C:\>nslookup

Default Server:  vex.nullify.net

Address:  192.168.0.5

> set type=a

> xerxes

Server:  vex.nullify.net

Address:  192.168.0.5

Name:    xerxes.nullify.net

Address:  66.98.178.74

> set type=ns

> nullify.net.

Server:  vex.nullify.net

Address:  192.168.0.5

nullify.net     nameserver = ns1.twisted4life.com

nullify.net     nameserver = queeg.nullify.net

nullify.net     nameserver = xerxes.nullify.net

queeg.nullify.net       internet address = 66.45.233.165

xerxes.nullify.net      internet address = 66.98.178.74

xerxes.nullify.net      AAAA IPv6 address = 2002:4262:b24a::4262:b24a

> set type=mx

> nullify.net

Server:  vex.nullify.net

Address:  192.168.0.5

nullify.net     MX preference = 20, mail exchanger = xerxes.nullify.net

nullify.net     MX preference = 30, mail exchanger = queeg.nullify.net

nullify.net     MX preference = 10, mail exchanger = firewall.nullify.net

nullify.net     nameserver = ns1.twisted4life.com

nullify.net     nameserver = queeg.nullify.net

nullify.net     nameserver = xerxes.nullify.net

firewall.nullify.net    internet address = 81.109.199.173

xerxes.nullify.net      internet address = 66.98.178.74

xerxes.nullify.net      AAAA IPv6 address = 2002:4262:b24a::4262:b24a

queeg.nullify.net       internet address = 66.45.233.165

Feel free to use my domain to explore it if you want, it (should be) set up correctly, and everything is public info anyway.  http://www.demon.net/toolkit/internettools/ contains some useful tools to test your domain from outside your own network if you don't have access to an external machine.

Exploring from the client side gives a good idea what the server side setup will need to be.

Permalink  2 Comments 

You can do this using the OPENROWSET function in MS SQL Server, so:

SELECT * FROM OPENROWSET('MSDASQL', 'ConnectionString', 'SELECT * FROM mytable')

Which is great in a view for data consolidation - but even better is to remove the need for a connection string by connecting just once!

You can do this using sp_addlinkedserver and sp_addlinkedsrvlogin.  Requirements will change depending on what you want to connect to - if you need help with a particular one feel free to e-mail me.

You can then simply use the new 'server' you just set up as so:

SELECT * FROM OPENQUERY(servername, 'SELECT * FROM mytable')

Permalink 

Have you ever wondered how to check if a number is an integer in C#?  Wondered why Convert.ToInt32() surrounded by a try catch is so slow?  Well, this article is for you then.

As everyone should know, catching an exception is an extremely time consuming task, but there's no obvious way to check if a string is actually an integer.  And before the visual basic people all say about Microsoft.VisualBasic.Information.IsNumeric this is actually simply a try...catch around a Convert.ToInt32 call.

Okay, so what is the performance drop incurred by using a try...catch and why should you worry?

Well, it's slow - 1000 iterations of try...catch around a Convert.ToInt32() comes to 2515.625 ms.  Programmatically that's a HORRID use of CPU time.

Some people (particularly on blogs.msdn.com's comments) have suggested that this is simply something you must incur, however due to NumberStyles (in System.Globalization) containing an entry for Integer it needn't be. We can use Double.TryParse without the risk that the double we'll be getting back will contain anything but a valid integer.

This is amazingly faster - 100,000 (100 times more than with a try...catch!) worst case scenarios come to a grand total of 46.875 ms of cpu time used up.  A much better overhead.

It returns True if the string was an integer and false if not - altering the value of the double passed into it as an out parameter to be the correct amount if it succeeds.  Note that the if statements are just there to confuse the compiler so it doesn't optimise out the whole contents of each for loop.

Here's an example application (sorry, no walkthrough as I have too little time, but this should be simple enough!):

using System;

using System.Globalization;

namespace BlogExamples.IntegerValidation

{

   class IntegerValidator

   {

      static void Main(string[] args)

      {

      Console.WriteLine("Comparison of speed of try..catch checking of integers");

      Console.WriteLine("1000 iterations of try...catch Convert.ToInt32()");

      DateTime before = DateTime.Now;

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

      {

         try

         {

            int t = Convert.ToInt32("testing");

            if (t>1000)

            {

               Console.WriteLine("Optimisation cheating");

            }

         }

         catch

         {

         }

      }

      TimeSpan duration = DateTime.Now - before;

      Console.WriteLine(duration.TotalMilliseconds+" ms total");

      CultureInfo MyCultureInfo = new CultureInfo("en-GB");

      Console.WriteLine("100000 iterations of Double.TryParse() (to be fair!)");

      DateTime before2 = DateTime.Now;

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

      {

            double d = 0;

            Double.TryParse("testing", System.Globalization.NumberStyles.Integer, MyCultureInfo, out d);

            if (d>1000)

            {

            Console.WriteLine("Optimisation cheating");

            }

         }

         TimeSpan duration2 = DateTime.Now - before2;

         Console.WriteLine(duration2.TotalMilliseconds+" ms total");

         Console.ReadLine();

      }

   }

}

 

Which when run on my machine reports the following:

Comparison of speed of try..catch checking of integers
1000 iterations of try...catch Convert.ToInt32()
2515.625 ms total
100000 iterations of Double.TryParse() (to be fair!)
46.875 ms total

Permalink  1 Comments 

Then maybe you have something in your most recently used list that's needing a network lookup.  UNC pathnames were causing the problem for me.

You can clear your MRU lists by exiting visual studio, then opening registry editor and deleting the contents of the keys FileMRUList and ProjectMRUList in HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\

Permalink 

If your web service (or one you're consuming) is playing up (405 Gateway timeouts, other odd behaviour) when being debugged, maybe it's the VsDebuggerCausalityData header - it's a huge string seemingly mostly filled with AAAA!

You can disable this from being sent by adding the following in your App.Config file:

<configuration>
  <system.diagnostics>
    <switches>
      <add name="Remote.Disable" value="1">
    </switches>
  </system.diagnostics>
</configuration>

This will disable the debugger from getting involved with the badly configured server (the VS header is within the HTTP specs upper limit on size).

This has been annoying me for at least the past day trying to talk to a partner of works web service!

Permalink 

Whilst I wait for someone to get back to me about something, I figured I'd quickly post about something that initially confused me about server controls on ASP.NET so that there's at least SOME new content!

ASP.NET server controls are simple components that run on the server and allow you to refactor a quantity of your sites code (such as a menubar) into a seperate module that is both reusable like a user control, and dynamic.  A server control can run code and also allows you to drag and drop it onto your pages.  A server control also has the ability to render itself at design time, so no more silly grey boxes - but rather a WYSIWYG situation (once it's built)!

So, once you've created a server control using VS.NET 2003 (or your choice of IDE!) you can easily add to the render override with something simple:

output.Write("<div class=\"mycssclass\">Hi there!</div>");

Any HTML will work, and all is fine if you just want to insert static HTML.

But what if you want to use the server control as if it were an ASP.NET application - or winforms control?

You know, so you can click a link or a button and it'll do 'something' and remember that state.

To do this you will need an event handler attached to a control.  So you create an instance of a control and delegate its event to the handler!  In winforms this is extremely easy, but in ASP.NET making it work right requires you set it all up early enough in your code!  This is the gotcha that had me stuck for a couple of hours when I first learnt it.  I did it in the render override.

Instead, change your render override to read as follows:

protected override void Render(HtmlTextWriter output)
{
   output.Write("<div class=\"myCSSClass\">");
   this
.RenderContents(output);
   output.Write("</div>");
}

This will allow you to render the controls at the right time and yet create them early enough - which will let ASP.NET create the eventhandler and wire it up for you.

Now, to create the controls that will be rendered you need to create a new override:

public LinkButton l;

protected override void OnInit(EventArgs e)
{
   base
.OnInit (e);
   l = new
LinkButton();
   l.Text = "Click me!  I'm a link that triggers an event on the server!";
   l.Enabled = true
;
   EventArgs args = new
EventArgs();
   l.Click += new
EventHandler(this.l_Click);
   this
.Controls.Add(l);
   Literal br = new
Literal();
   br.Text = "<br />";
   this
.Controls.Add(br);
}

This will create two controls - which will be rendered in the render method.  You can now create the event handler and any code you place in it will work!  If you had created the controls in the render method itself you would have found that although they posted back to the server, they didn't call the event handler.

(Note: += means "add one of" and "base" is the WebControl you are inheriting from when creating a server control.)

A quick example event handler for those who've never done one before:

void l_Click(object sender, EventArgs e)
{
   l.Text = "Thanks!";
}

Permalink 

This one had me and google stumped for a few minutes yesterday till I remembered that dBASE isn't actually a relational database but is a flat file one.

Each file is one table, so use the file management classes in .NET to list the tables your connection string has opened!

Unfortunately there's also no way to list tables in ODBC that I can see in .NET for the moment, so if you want to use a different database format you would be better off using OLE or ADO to connect if you can.

Update: Whoops, here's the code I forgot to put in:

private OdbcConnection connection;

private string dbpath;

public dBaseEasyDBConn(string path)

{

dbpath = path;

Console.Write("Opening dBASE Files...");

connection = new OdbcConnection("Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq="+path);

connection.Open();

Console.WriteLine("Done");

}

public string[] GetTables()

{

int position = 0;

string[] templist = Directory.GetFiles(dbpath, "*.dbf");

string[] filelist = new string[templist.GetLength(0)];

foreach (string s in templist)

{

filelist[position] = s.Replace(dbpath, "").Replace(".DBF", "").Replace("\\", "");

position++;

}

return filelist;

}

Permalink  1 Comments 

I'm currently sitting here considering what 'acceptable performance' is in a variety of situations, ranging from databases to user interfaces, or back end control systems.

The answer in most cases is:

It changes depending on your situation.

Even what is acceptable in a real-time environment varies dramatically, for example software designed to change the course of a cruise missile would need to respond quick enough to keep up with the rate of change of terrain, whereas something monitoring the change of temperature in a green house would likely not need to process the data faster than once every ten seconds.

A database must be atomic, as soon as you commit a transaction the data MUST exist in the database, but with concurrent connections and multiple physical CPU's this is clearly impossible without the database working sequentially - so acceptable performance in this case is "fast enough that nobody notices, but not fast enough to slow down total performance".

However, there is one exception to it being variable depending on the task:  When the user is involved.

What is acceptable performance for a user interface?

Back in the days pre-DOS and PC era people likely waited the same amount of time for applications as they do today only with fewer features.  (Obviously there were some exceptions, I remember waiting 5 minutes for a word processor to load, but things evened out pretty quickly since nobody WANTED to wait that long).

Firstly, there are two things to monitor to decide on performance.  How fast the application is available to be told what to do and how much you can tell it to do without actually needing to wait.  There are simple answers to both.

The second one is commonly ignored by a lot of bespoke software developers, and really big players who shall remain nameless - in the education sector the key piece of software in UK schools had serious problems with concurrency, and even after a full rewrite still has problems with concurrency of use of a single application - you tell it what to do and go have a cup of tea/coffee - it might be done when you get back.

This is obviously unacceptable, and companies like Microsoft who can afford to do user studies have clearly looked at the problem - for example, how long do you wait whilst you're saving in Word?  How about printing?

Correct - you don't, even if it takes a while a seperate thread is doing the actual work so there is zero delay in the user interface - you can even be typing away as it saves or prints.  They don't do it everywhere, but they do do it whereever the user would have to wait a varying amount depending on the data being altered.

This ensures that Word acts speedy even with a hundred megabyte document.

The question is, would anyone be willing to wait at that point to save the development work?

Whilst the answer is 'probably not' there would be a point where people wouldn't mind word freezing - would you mind a 1/2 a second on a save?  How about 2 seconds?

This brings me onto the issue of actual delay before the application is usable again.  What is acceptable here?

The first delay is loading the application.  This is dependant on what the user wants to do, since we don't know in advance what they want to do our user interface must APPEAR to load almost instantly so that we can shave an additional second or so of time off our REAL loading time whilst the user decides what to click or press.

The second delay is the activity of doing something with the application, and can consist of one of two things from a user perspective:

  • Critical continuity activities
  • Non-critical activities (note - non-critical to UI flow, not anything else)

In the case of critical activies that the UI is dependant on, obviously the user must wait - unfortunate as it is, they will appreciate that it must happen.  They might not be happy, but it IS going to take time to load the document they want to look at (even if just the first page is loaded for display purposes before the rest of the data is loaded).  In these cases you can try as hard as possible, but you will always cause the user to wait - sometimes a nasty amount of time.

The non-critical activies are ones that do not have to occur to leave the user interface operable.  Saving is a good example, so is printing and seach and replace - although this one is commonly not implemented properly.  These activities should be implemented as seperate threads, with the user able to continue with their task, or do an additional slow task at the same time to avoid any actual period where the user is twiddling their thumbs.

So, in essence the only real answer to both key areas of UI performance is THE USER WANTS IT NOW unless it HAS to take longer, and then they should be allowed to do something else at the same time!

I wish developers would take the perspective of the actual end user when writing the application.  We would see a lot more multi-threaded, multiple document interface applications I'm sure.

Congratulations to Microsoft for getting it right.

Permalink 

This is a nice neat way of resizing an image, I've simplified it and de-refactored (?) it for simplicity.

Firstly, you ask for your image from the database:

SqlCommand cmd = new SqlCommand("SELECT image FROM images WHERE id=@id", connection);
cmd.Parameters.Add("@id", Request.QueryString["id"]);
SqlDataReader dr = cmd.ExecuteReader();

Allocate an array of bytes to store it in temporarily:

byte[] image = null;
while
(dr.Read())
{
   image = (byte
[])dr.GetValue(0);
}
dr.Close();

Now you have an array of bytes that contains your image, you can freely load it into a bitmap from the array:

Bitmap b = (Bitmap)Bitmap.FromStream(new MemoryStream(image));

And you can resize that bitmap easily using the overloaded bitmap constructor:

Bitmap output = new Bitmap(b, new Size(320, 240);

One resized bitmap that you can now save or send anywhere - including Response.OutputStream!

Permalink 

I just found an article at http://blogs.msdn.com/mszCool/archive/2004/06/14/155420.aspx that goes really well with my old article about using reflection to build plugins.

Basically the article covers how to change the permissions of the appdomain to allow only permitted actions - a great thing to do if you want your users to be able to build the plugins!

(Update five years later in 2009: Also I forgot all about this article and did my own example here http://www.nullify.net/ViewArticle.aspx?article=315 )

Permalink 

Another easy question!

Firstly, what type of screen size are you looking for?

There are two types you can look at - the current working area, basically the area a maximised application will fill if it is polite, and the physical screen which expands from the top row of pixels to the bottom of the start bar on a standard setup.

Thankfully the Screen class offers up both of these as properties, so you can easily:

int height = Screen.PrimaryScreen.Bounds.Height;

int width = Screen.PrimaryScreen.Bounds.Width;

To get the exact, complete screen size (it may be better to handle this as a Drawing.Rectactle as that is how Bounds is typed, however for ease of explanation this is how I will do it here).

And, just as easily you can do:

int height = Screen.PrimaryScreen.WorkingArea.Height;

int width = Screen.PrimaryScreen.WorkingArea.Width;

To get the total usable space for a friendly application.

Please don't use this to work out how big you need to make your always on top application so you can obscure the start menu - that is extremely annoying ;)

Permalink 

This is a quick and easy one for anyone else trying to send mail using ASP.NET.

First, add the using statement for the appropriate namespace:

using System.Web.Mail;

Then, create a MailMessage object:

MailMessage m = new MailMessage();
m.From = "
simon@nullifynetwork.com";
m.Subject = "A demo message";
m.Body = "This is the body\n\n-Simon";
m.To = "
you@yourplace.com";

And then, finally - send it using the static method off SmtpMail:

SmtpMail.Send(m);

Another example of why .NET rocks, what used to be an annoyingly complex task is now suddenly relegated to being easy as anything...

(This article is to make up for this monster article which discusses opening file handles on physical devices...)

Permalink 

Want to access a physical device (COM port, tape drive, LPT port, anything...) using C# .net?

You can't.  Not natively anyway:

FileStream fs = File.Open("\\\\.\\COM1", FileMode.Open, FileAccess.ReadWrite, FileShare.None);

Happily errors out saying you can't use the \\.\ format with a FileStream (\\.\ becomes \\\\.\\ when you escape the backspaces with more backspaces).

FileStream does however allow opening a handle, so all is not lost, you can simply use the format:

FileStream fs = new FileStream(handle, FileAccess.ReadWrite);

After opening the handle using a CreateFile API call.  To use this API call you need to platform invoke it, which is easily done once you look at the docs for it:

[DllImport("Kernel32.dll")]
static
extern IntPtr CreateFile(string filename, [MarshalAs(UnmanagedType.U4)]FileAccess fileaccess, [MarshalAs(UnmanagedType.U4)]FileShare fileshare, int securityattributes, [MarshalAs(UnmanagedType.U4)]FileMode creationdisposition, int flags, IntPtr template);

(http://www.pinvoke.net/ is a great place to cheat)

You can then get handle (note that rather than defining the actual handle variable I'm going to put the CreateFile call inside the FileStream constructor - you could instead do InPtr handle = CreateFile() etc) by using CreateFile:

FileStream fs = new FileStream(CreateFile("\\\\.\\COM1", FileAccess.ReadWrite, FileShare.ReadWrite, 0, FileMode.Create, 0, IntPtr.Zero), FileAccess.ReadWrite);

First timers should remember to update their using statements, one for the FileStream, and one for the [DllImport]:

using System.IO;
using
System.Runtime.InteropServices;

Permalink  1 Comments 

So, I had come up with a way to do double buffering before using a backbuffer and flipping it to the front for a simple game I wrote as a test.

I have just noticed there's a Control.SetStyle method:

this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
this.UpdateStyles();

Executing this in the forms constructor will turn on double buffering the correct way.

Permalink 

So someone e-mailed to ask me why I used as to cast my object:

IHiThere asm = o as IHiThere;
if (asm != null)
{
   MessageBox.Show(asm.Hi());
}
else
{
   MessageBox.Show("Failed to make asm = o");
}

Rather than:

IHiThere asm = (IHiThere)o;

When it is neater.

Well, there is a simple reason: This is because the as operator doesn't throw an exception when it fails but instead fills the variable with null. The check if the value was null checked if the code worked or not.

Note that in the real world you will want exception handling around the whole block, incase the user selects the wrong type of dll, or access to it is denied, or... well, you get the picture.  This means you can freely use brackets to cast it - but this is in my opinion a more elegant method of doing something where you want to know if it succeeded or failed.

Update in 2009:

I would just like to clarify that I was trying to make the point that you should use the as keyword when it's something you expect not to work but don't want to use the is keyword!

Permalink 

So, I'm playing with reflection with the intention of making a plugin system for future use and looking at the obscenely complex articles on the net that don't cover anything even remotely like what I want to do.  Which is have an object I didn't write, and be able to .DoSomething with it rather than have four lines of garbage to just run a static method.  I wanted to be able to use classes I hadn't referenced at design time, just as if I had.  Obviously they need to follow my interface definition, but that's a small price to pay.

So I eventually give up and go back to the docs and play around for a bit, eventually getting this ludicrously simple method working:

OpenFileDialog openasm = new OpenFileDialog();
if (openasm.ShowDialog() == DialogResult.OK)
{
   Assembly testasm = Assembly.LoadFrom(openasm.FileName);
   Type[] asmtypes = testasm.GetTypes();
   foreach (Type t in asmtypes)
   {
      if (t.IsClass & t.GetInterface("IHiThere")!=null)
      {
         object o = testasm.CreateInstance(t.FullName);
         IHiThere asm = o as IHiThere;
         if (asm != null)
         {
            MessageBox.Show(asm.Hi());
         }
         else
         {
            MessageBox.Show("Failed to make asm = o");
         }
      }
   }
}

A quick rundown, that's:

Load the assembly you want to look at:
Assembly testasm = Assembly.LoadFrom("filename.dll");

Get a list of the types of objects in it:
Type[] asmtypes = testasm.GetTypes();

Loop through it, and for each class that implements your chosen shared interface* create it as an object:
object o = testasm.CreateInstance(t.FullName);

Then cast it to your interface:
IHiThere asm
= o as IHiThere;

Creating it as a local object you can use just like normal:
MessageBox.Show(asm.Hi());

* - Note that the interface in question here looked like:

public interface IHiThere
{
   string
Hi();
}

And was referenced by both the 'plugin' and the 'host' application.

The plugin side was a simple class that implemented the IHiThere interface, and returned "Hellow world from the plugin" as a string in the Hi method:

public class Class1 : IHiThere
{
   public
Class1()
   {
   }
   public
string Hi()
   {
      return
"Hello World - from the plugin";
   }
}

Permalink  1 Comments 

Here's a little something that took a couple of hours to write, feedback is as always appreciated!  As I've already been asked: this is all GDI based, no DirectX...  Graphics for it would be appreciated!

Anyway, click here to run GravCave from my server, you need the dot net framework - available from windows update, or I expect it will run okay under mono.  If you wish you can right click and save target as to your local machine - it's 40kb and will run from anywhere.

Another .NET game in the same vein is Chris Sells' Wahoo.  This came about as I was curious why dot net based games weren't slowly appearing yet, so thought I'd see how difficult it was to code a game in: turns out with C# it's much easier than many other languages.

I assume when people realise that they CAN use DirectX with an app that is loaded directly from the net, they'll start using it.

UPDATE: Source code is available on this page on my site

Permalink 

Ever wondered how to double buffer with a Graphics object so your GDI+ based game/control doesn't flicker annoyingly?

Me too.  There's probably a built in method that's easier, but this is how I managed to get it to work smoothly, it's nice and simple and allows you to draw anywhere that offers up the normal CreateGraphics method.

First, set up a bitmap to act as your backbuffer:

Bitmap BackBuffer = new Bitmap(this.ClientSize.Width,this.ClientSize.Height);

Graphics DrawingArea = Graphics.FromImage(BackBuffer);

Next, you want to draw to your graphics object as normal, so DrawingArea.Clear(Color.Black); and such.

Once you've completed drawing the object that you want to smoothly move, simply draw the pre-rendered bitmap over the top of the Graphics object you want to update:

Graphics Viewable = this.CreateGraphics();

Viewable.DrawImageUnscaled(BackBuffer, 0, 0);

You can also use other techniques to increase the performance, such as reusing the backbuffer by defining it in the class you're using it in - this means .NET won't need to recreate it repeatedly.

Permalink 

If your validation isn't working in Asp.net after deploying to a webserver with multiple virtual hosts you might find you need to copy the aspnet_client directory from the default site to the affected site to get the client-side validation working.

A good reason to always do server side validation!

Permalink 

This is my first attempt at an instructional article, so opinions on quality would be great!  Let me know if I made any mistakes too...

It's mainly for all those like Robert Scoble who would like to be able to drag and drop an item to a folder in their Outlook and post it instantly to their Blog, but it also covers web services and talking to Outlook.

Accessing Outlook

The first requirement is to be able to access Outlook.  For those with Outlook 2003 and XP this is relatively easy, thanks to .Net and Microsoft shipping an appropriate assembly with Office.  To install the Office 2003 assembly, you should run the office install and choose .NET Programmability Support.

You might need to use the command prompt to copy Microsoft.Office.Interop.Outlook.dll out of the GAC after installing it so you can add a reference to it, if you can add it as a reference otherwise do so and let me know how!  The Visual Studio add reference dialog doesn't seem to list items in the GAC...

Add an appropriate using clause:

 

Then you should be able to instantiate an Outlook object and make requests of it:

Outlook.Application app = new Outlook.ApplicationClass();

Outlook.NameSpace NS = app.GetNamespace("MAPI");

Outlook.MAPIFolder inboxFld = NS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);

This will give you access to inboxFld, which will allow you to iterate through the contents of the inbox!  You can also change this to iterate through notes, or through calendar entries, tasks, etc. as you want.

For example, to iterate through your mail you can do:

 

Console.WriteLine(t.Subject);

}

To write out all the subjects on the console.  The only annoying thing will be you need to say yes to a security dialog when you access mail items - I'm working on getting around this, it doesn't happen for tasks or notes, etc.

Once you are able to access Outlook, your next objective is to post data to your weblog.  You can avoid duplicates through one of two ways:

  • Keep track of what has been posted by maintaining an ArrayList of articles on your blog and checking before trying to post one.
  • Keep track of what has been posted by changing something in the MailItem's - e.g. - set or clear a flag.

The first method requires keeping a list synchronised with the blog, the second is quickest and easiest, but wouldn't be suited with multiple people possibly posting things.

Posting to your blog

Obviously everyone is using different software to manage their blog.  I can't give an example of every single method, however the simplest from a programmers perspective is if you can access the database of your blog via a webservice.

Building a webservice

Google can supply many examples and tutorials, however an example of doing this is fairly simple.

Choose to add a new webservice to your site, or create an entirely independant project and call it something suitable - ours will be blog because it's an example.

Firstly, you will need to add a few more items to your using list, so you can do XML serialisation of structures and objects.  I will assume your database is MS SQL Server too, so ensure the following are listed in addition to the defaults for a webservice (I forget what they are):

 

 

 

 

 

using System.Web.Services.Protocols;

 

 

You want to be as object oriented as possible when building your webservice, so you should define a NewsItem structure to pass back and forth, you can adjust this to include whatever you need to store in an article:

 

{

public int id;

public string topic;

public string subject;

public string postedby;

public DateTime postedat;

public string content;

 

}

This will allow you to reference rows in your database as objects, a simple organisational benefit that crosses over and permits easy use of methods of the webservice without passing a lot of parameters.  It also allows you to add groups of entries to an ArrayList, which is a big benefit (although there is a problem converting from an object transferred by a webservice and an ArrayList, if you ever do this you will need to iterate through the object and add the entries back to an ArrayList - .net does not support converting from an object[] to an ArrayList).

You can then build your method for adding the article to the database.  I have used the database on my blog as an example, you will obviously need to change the insert statement and connection string to fit your situation.  There is also no exception handling, ideally you should enclose the opening of the connection and the executing of the query in Try Catch blocks.

Note that the XmlInclude for the NewsItem struct is listed, this allows the webservice to accept a newsitem given as a parameter - otherwise if would not know to serialise the structure.

[WebMethod]

[XmlInclude(typeof(NewsItem))]

public void AddArticle(NewsItem newarticle)

{

SqlConnection sqlcn = new SqlConnection("Data Source=(local);" +

"Initial Catalog=NullifyDB;" +

"Integrated Security=SSPI");

sqlcn.Open();

SqlCommand sqlcmd = new SqlCommand("INSERT INTO newsarticle (subject, topic, content, uid) VALUES (@subject, @topic, @content, @postedby);", sqlcn);

sqlcmd.Parameters.Add("@subject", newarticle.subject);

sqlcmd.Parameters.Add("@topic", newarticle.topic);

sqlcmd.Parameters.Add("@content", newarticle.content);

sqlcmd.Parameters.Add("@postedby", 253);

sqlcmd.ExecuteNonQuery();

sqlcn.Close();

}

You should then provide additional methods for anything else you would want to do, such as listing articles, deleting articles, and editing.  For Outlook integration you really only need this method.

Accessing the webservice

Once the web service is up and working, you need to create a web reference to the webservice, this is done in visual studio by right clicking the references box and choosing add web reference.  Lets say there's one at http://webservices.nullify.net/blog.asmx

When you add a web reference Visual Studio will automatically produce a wrapping class that will allow you to easily instantiate the web service as a local object, without worrying about any of the underlying technology.  (I'll only cover synchronous calls here, otherwise this will turn into a full fledged book...)

To access the above web service, you would simply define it as a new object:

net.nullify.webservices.Blog blog = new net.nullify.webservices.Blog();

And you would define our NewsItem scructure that we defined in the webservice:

net.nullify.webservices.NewsItem article = new net.nullify.webservices.NewsItem();

This will allow you to now call methods of the blog object, which will execute directly on your web server, with all the rights of a normal asp.net page - including the ability to insert articles into your database!

Using our imaginary webservice, rather than writing the subject for each MailItem to the console, you can post them to your blog:

article.subject = t.Subject;

article.content = t.Body;

article.topic = "OutlookPost";

 

blog.AddArticle(article);

(Note, this is assuming your webservice has no security, or is protected by asp.net/IIS' own security!)

I hope this post helps someone!

 

public struct NewsItem

 

using System.Xml.Serialization;

 

using System.Web.Services.Description;

 

using System.Web.Services;

 

using System.Data.Common;

 

using System.Data.SqlTypes;

 

using System.Data.SqlClient;

 

foreach (Outlook.MailItem t in inboxFld.Items)
{

 

using Outlook = Microsoft.Office.Interop.Outlook;

(This article has been truncated due to migration to a new database, apologies!  I hope what is here helps and if you have questions there are copies around on the web of this article.)

Permalink