Archive for the ‘Uncategorized’ Category

Transformers!

September 18, 2009

Last week, I spent an evening helping my girlfriends son with his new Optimus Prime transformer, from the ROFT (Revenge Of The Fallen) movie.  We had a great time trying to figure out how to get past the chest plate step, which was poorly documented in the instruction manual.  He found an article on Google which finally showed us how.  Below are some pictures of the before and after, along with a couple of shots of the original Optimus Prime!  The toys have really made a huge leap in complexity.  I was very surprised at the amount of detail in the new OP model, and how well he turns into truck form.  Very clean lines with lots of options for play value added in, such as the ability to make wings.

OptPrime-1

OptPrime-4

I’ll have to upload more pictures of OP when he’s in robot form.  I thought I had a few ready to go!

Synchronized Dictionary

August 31, 2007

This is just a simple dictionary object, which derives from System.Collections.Generic.Dictionary<TKey, TValue>.  The idea is to simply provide an efficient and thread-safe dictionary, where 99% of the access methods are reads.  The real-world application of this object is in a web-app: The application maintains a collection of all the valid user objects, for all users that are logged in.

   1: using System;
   2: using System.Collections;
   3: using System.Collections.Generic;
   4: using System.Threading;
   5:  
   6: namespace Utilities
   7: {
   8:     /// <summary>
   9:     /// Provides a thread-safe and lock-efficient dictionary.  Key must
  10:     /// implement the generic IComparable interface, and the value must
  11:     /// be a reference type.
  12:     /// Enumerations are thread-safe, but will block changes to the
  13:     /// dictionary.
  14:     /// The Keys and Values properties are NOT thread-safe and will throw
  15:     /// exceptions if the dictionary is modified while enumerating those
  16:     /// objects.
  17:     /// 
  18:     /// Matthew Potter
  19:     /// 2007-08-31
  20:     /// matthew@synapseware.com
  21:     /// 
  22:     /// You are free to use this code, as long as you leave my author
  23:     /// information intact.
  24:     /// </summary>
  25:     public class SyncLockDictionary<TKey, UValue> : Dictionary<TKey, UValue>
  26:         where TKey: IComparable<TKey>
  27:         where UValue: class
  28:     {
  29:         /// <summary>
  30:         /// Defines the read-lock timeout, in milliseconds.
  31:         /// </summary>
  32:         protected const int READLOCK_TIMEOUT = 100;
  33:  
  34:         /// <summary>
  35:         /// Defines the write-lock timeout, in milliseconds.
  36:         /// </summary>
  37:         protected const int WRITELOCK_TIMEOUT = 250;
  38:  
  39:         /// <summary>
  40:         /// The locking mechanism that provides the thread-safety
  41:         /// </summary>
  42:         private ReaderWriterLock _lock = new ReaderWriterLock ();
  43:  
  44:         /// <summary>
  45:         /// Default Constructor
  46:         /// </summary>
  47:         public SyncLockDictionary ()
  48:             : base ()
  49:         {}
  50:  
  51:         /// <summary>
  52:         /// Copy Constructor
  53:         /// </summary>
  54:         /// <param name="copy"></param>
  55:         public SyncLockDictionary (Dictionary<TKey, UValue> copy)
  56:             : base (copy)
  57:         {}
  58:  
  59:         /// <summary>
  60:         /// Constructor
  61:         /// </summary>
  62:         /// <param name="comparer"></param>
  63:         public SyncLockDictionary (IEqualityComparer<TKey> comparer)
  64:             : base (comparer)
  65:         {}
  66:  
  67:         /// <summary>
  68:         /// Constructor
  69:         /// </summary>
  70:         /// <param name="capacity"></param>
  71:         public SyncLockDictionary (int capacity)
  72:             : base (capacity)
  73:         {}
  74:  
  75:         /// <summary>
  76:         /// Constructor
  77:         /// </summary>
  78:         /// <param name="capacity"></param>
  79:         /// <param name="comparer"></param>
  80:         public SyncLockDictionary (int capacity, IEqualityComparer<TKey> comparer)
  81:             : base (capacity, comparer)
  82:         {
  83:         }
  84:  
  85:         /// <summary>
  86:         /// Add a new value to the dictionary.
  87:         /// </summary>
  88:         /// <param name="key"></param>
  89:         /// <param name="value"></param>
  90:         public new void Add (TKey key, UValue value)
  91:         {
  92:             try
  93:             {
  94:                 _lock.AcquireWriterLock (READLOCK_TIMEOUT);
  95:                 if (base.ContainsKey (key))
  96:                     base [key] = value;
  97:                 else
  98:                     base.Add (key, value);
  99:             }
 100:             finally
 101:             {
 102:                 // release reader lock
 103:                 _lock.ReleaseWriterLock ();
 104:             }
 105:         }
 106:  
 107:         /// <summary>
 108:         /// Remove a value from the dictionary.
 109:         /// </summary>
 110:         /// <param name="key"></param>
 111:         public new void Remove (TKey key)
 112:         {
 113:             try
 114:             {
 115:                 // get read lock and return if nothing to remove
 116:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 117:                 if (!base.ContainsKey (key))
 118:                     return;
 119:  
 120:                 // upgrade to writer lock so we can safely remove the item
 121:                 LockCookie lc = _lock.UpgradeToWriterLock (WRITELOCK_TIMEOUT);
 122:  
 123:                 // remove the item
 124:                 base.Remove (key);
 125:  
 126:                 // downgrade writer lock
 127:                 _lock.DowngradeFromWriterLock (ref lc);
 128:             }
 129:             finally
 130:             {
 131:                 // release reader lock
 132:                 _lock.ReleaseReaderLock ();
 133:             }
 134:         }
 135:  
 136:         /// <summary>
 137:         /// Returns true if the specified key exists in the collection.
 138:         /// </summary>
 139:         /// <param name="key"></param>
 140:         /// <returns></returns>
 141:         public new bool ContainsKey (TKey key)
 142:         {
 143:             try
 144:             {
 145:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 146:  
 147:                 return base.ContainsKey (key);
 148:             }
 149:             finally
 150:             { _lock.ReleaseReaderLock (); }
 151:         }
 152:  
 153:         /// <summary>
 154:         /// Returns true if the specified value exists in the collection.
 155:         /// </summary>
 156:         /// <param name="value"></param>
 157:         /// <returns></returns>
 158:         public new bool ContainsValue (UValue value)
 159:         {
 160:             try
 161:             {
 162:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 163:  
 164:                 return base.ContainsValue (value);
 165:             }
 166:             finally
 167:             { _lock.ReleaseReaderLock (); }
 168:         }
 169:  
 170:         /// <summary>
 171:         /// Gets the value associated with the specified key.  Returns
 172:         /// false if the specified key does not exist in the dictionary.
 173:         /// </summary>
 174:         /// <param name="key"></param>
 175:         /// <param name="value"></param>
 176:         /// <returns></returns>
 177:         public new bool TryGetValue (TKey key, out UValue value)
 178:         {
 179:             try
 180:             {
 181:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 182:  
 183:                 return base.TryGetValue (key, out value);
 184:             }
 185:             finally
 186:             { _lock.ReleaseReaderLock (); }
 187:         }
 188:  
 189:         /// <summary>
 190:         /// Returns the number of items currently in the dictionary.
 191:         /// </summary>
 192:         public new int Count
 193:         {
 194:             get
 195:             {
 196:                 try
 197:                 {
 198:                     _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 199:  
 200:                     return base.Count;
 201:                 }
 202:                 finally
 203:                 { _lock.ReleaseReaderLock (); }
 204:             }
 205:         }
 206:  
 207:         /// <summary>
 208:         /// Returns a thread-safe enumerator for this dictionary (changes
 209:         /// to the dictionary will not be reflected during an enumeration).
 210:         /// </summary>
 211:         /// <returns></returns>
 212:         public new SafeEnumerator GetEnumerator ()
 213:         {
 214:             try
 215:             {
 216:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 217:  
 218:                 ArrayList items = new ArrayList ();
 219:                 Enumerator en = base.GetEnumerator ();
 220:                 while (en.MoveNext ())
 221:                     items.Add (en.Current);
 222:  
 223:                 return new SafeEnumerator (items);
 224:             }
 225:             finally
 226:             { _lock.ReleaseReaderLock (); }
 227:         }
 228:  
 229:         /// <summary>
 230:         /// Returns a reference to the Keys collection.
 231:         /// </summary>
 232:         public new SafeEnumerator Keys
 233:         {
 234:             get
 235:             {
 236:                 try
 237:                 {
 238:                     _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 239:  
 240:                     ArrayList items = new ArrayList ();
 241:                     foreach (object key in base.Keys)
 242:                         items.Add (key.ToString ());
 243:  
 244:                     return new SafeEnumerator (items);
 245:                 }
 246:                 finally
 247:                 { _lock.ReleaseReaderLock (); }
 248:             }
 249:         }
 250:  
 251:         /// <summary>
 252:         /// Returns a reference to the Values collection.
 253:         /// </summary>
 254:         public new SafeEnumerator Values
 255:         {
 256:             get
 257:             {
 258:                 try
 259:                 {
 260:                     _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 261:  
 262:                     ArrayList items = new ArrayList ();
 263:                     foreach (object key in base.Values)
 264:                         items.Add (key);
 265:  
 266:                     return new SafeEnumerator (items);
 267:                 }
 268:                 finally
 269:                 { _lock.ReleaseReaderLock (); }
 270:             }
 271:         }
 272:  
 273:         /// <summary>
 274:         /// Thread-safe accessor property.
 275:         /// </summary>
 276:         /// <param name="key"></param>
 277:         /// <returns></returns>
 278:         public new UValue this [TKey key]
 279:         {
 280:             get
 281:             {
 282:                 try
 283:                 {
 284:                     _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 285:  
 286:                     UValue value = null;
 287:                     if (base.TryGetValue (key, out value))
 288:                         return value;
 289:  
 290:                     return null;
 291:                 }
 292:                 finally
 293:                 { _lock.ReleaseReaderLock (); }
 294:             }
 295:             set
 296:             {
 297:                 try
 298:                 {
 299:                     _lock.AcquireWriterLock (WRITELOCK_TIMEOUT);
 300:                     try
 301:                     {
 302:                         if (base.ContainsKey (key))
 303:                             base [key] = value;
 304:                         else
 305:                             base.Add (key, value);
 306:                     }
 307:                     finally
 308:                     { _lock.ReleaseWriterLock (); }
 309:                 }
 310:                 finally
 311:                 {}
 312:             }
 313:         }
 314:  
 315:         /// <summary>
 316:         /// Gets an object that can be used to synchronize
 317:         /// access to the dictionary.
 318:         /// </summary>
 319:         public object SyncRoot
 320:         {
 321:             get
 322:             { return this; }
 323:         }
 324:     }
 325:  
 326:     /// <summary>
 327:     /// Provides a thread-safe enumerator for a SyncLockDictionary object.
 328:     /// </summary>
 329:     public class SafeEnumerator : System.Collections.IEnumerator, IEnumerable
 330:     {
 331:         private IList    _items;
 332:         private int        _current;
 333:  
 334:  
 335:         /// <summary>
 336:         /// 
 337:         /// </summary>
 338:         /// <param name="synclock"></param>
 339:         public SafeEnumerator (IList items)
 340:         {
 341:             _items        = items;
 342:             _current    = -1;
 343:         }
 344:  
 345:         /// <summary>
 346:         /// 
 347:         /// </summary>
 348:         public object Current
 349:         {
 350:             get
 351:             {
 352:                 if (_current < 0 || 0 == _items.Count)
 353:                     return null;
 354:  
 355:                 return _items [_current];
 356:             }
 357:         }
 358:  
 359:         /// <summary>
 360:         /// 
 361:         /// </summary>
 362:         public void Dispose ()
 363:         {}
 364:  
 365:         /// <summary>
 366:         /// 
 367:         /// </summary>
 368:         object IEnumerator.Current
 369:         {
 370:             get
 371:             {
 372:                 return this.Current;
 373:             }
 374:         }
 375:  
 376:         /// <summary>
 377:         /// 
 378:         /// </summary>
 379:         /// <returns></returns>
 380:         public bool MoveNext ()
 381:         {
 382:             if (_current >= _items.Count)
 383:                 return false;
 384:  
 385:             _current++;
 386:             if (_current < _items.Count)
 387:                 return true;
 388:  
 389:             return false;
 390:         }
 391:  
 392:         /// <summary>
 393:         /// 
 394:         /// </summary>
 395:         public void Reset ()
 396:         {
 397:             _current = -1;
 398:         }
 399:  
 400:         /// <summary>
 401:         /// 
 402:         /// </summary>
 403:         /// <returns></returns>
 404:         IEnumerator IEnumerable.GetEnumerator ()
 405:         {
 406:             return _items.GetEnumerator ();
 407:         }
 408:     }
 409: }

C# HTTP Client

May 14, 2007

This is just a quick class I threw together for SQL Server 2005 – we needed a way to download XML from a web site within a stored procedure. On the surface, this sounds like a gross over-use of the CLR, but it was an elegant solution to an otherwise difficult problem for the specific case we were working on. The code is linked to this post.

HTTP Client code (download ZIP)

   1: using System;
   2: using System.Collections.Generic;
   3: using System.IO;
   4: using System.Net;
   5: using System.Net.Sockets;
   6: using System.Text;
   7: using System.Threading;
   8: using System.Xml;
   9:  
  10: namespace Synapseware.Web
  11: {
  12:     /// <summary>
  13:     /// HttpClient class
  14:     /// </summary>
  15:     public static class HttpClient
  16:     {
  17:         /// <summary>
  18:         /// Calls the target site using an HTTP/1.0 GET.
  19:         /// </summary>
  20:         /// <param name="url">Request URL</param>
  21:         /// <param name="timeOut">Timeout to wait for response, in milliseconds.</param>
  22:         /// <returns></returns>
  23:         public static string GetString (string url, int timeOut)
  24:         {
  25:             Socket        sock            = null;
  26:             string        host            = null;                // host name of request
  27:             string        path            = null;                // path portion of request
  28:             string        request            = null;
  29:             string        response        = null;                // body of HTTP response
  30:             string []    data            = null;                // header block converted to string []
  31:             string []    parts            = null;
  32:             int            pos                = 0;
  33:             int            status            = 0;                // HTTP response code
  34:             int            hdrLen            = 0;                // length of header block
  35:             SocketState    state            = null;
  36:             Dictionary<string, string>
  37:                         headers            = null;                // HTTP headers
  38:  
  39:             try
  40:             {
  41:                 // we don't support SSL!
  42:                 if (url.StartsWith ("https://"))
  43:                     return null;
  44:  
  45:                 // parse up the request string
  46:                 if (url.StartsWith ("http://"))
  47:                     host = url.Substring (7);
  48:                 else
  49:                     host = url;
  50:  
  51:                 // split at the first path delimiter
  52:                 if (-1 != (pos = host.IndexOf ('/')))
  53:                 {
  54:                     path = host.Substring (pos);
  55:                     host = host.Substring (0, pos);
  56:                 }
  57:  
  58:                 // make sure path is correct
  59:                 if (String.IsNullOrEmpty (path) || !path.StartsWith ("/"))
  60:                     path = String.Concat ("/", (path ?? ""));
  61:  
  62:                 // connect to server
  63:                 sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  64:                 sock.Blocking = true;
  65:                 sock.Connect (host, 80);
  66:  
  67:                 // create state object
  68:                 state = new SocketState (sock);
  69:  
  70:                 // build request
  71:                 request = String.Format (
  72: @"GET {0} HTTP/1.0
  73: HOST: {1}
  74: Accept: text/\*
  75: Accept-Language: en-us
  76: Cache-Control: no-cache
  77: Content-Length: 0
  78:  
  79: ", path, host);
  80:  
  81:                 // send request and wait for it to complete
  82:                 Send (state, request);
  83:                 state.Done.WaitOne (5000, false);
  84:                 state.Done.Reset ();
  85:  
  86:                 // get the response
  87:                 StartReceive (state);
  88:                 state.Done.WaitOne ();
  89:  
  90:                 // convert the response bytes
  91:                 response = state.Data.ToString ();
  92:  
  93:                 // check for HTTP header end
  94:                 if (-1 == (hdrLen = response.IndexOf ("\r\n\r\n")))
  95:                     return null;
  96:  
  97:                 // parse out header data
  98:                 data = response.Substring (0, hdrLen).Replace ("\r\n", "\n").Split ('\n');
  99:                 if (null == data || 0 == data.Length)
 100:                     return null;
 101:  
 102:                 // get response status code
 103:                 parts = data [0].Split (' ');
 104:                 status = Int32.Parse (parts [1]);
 105:                 if (200 != status)
 106:                     return null;
 107:  
 108:                 // turn header array collection into a collection
 109:                 headers = new Dictionary<string, string> ();
 110:                 foreach (string hdr in data)
 111:                 {
 112:                     if (-1 == (pos = hdr.IndexOf (' ')))
 113:                         continue;
 114:                     if (hdr.StartsWith ("HTTP"))
 115:                         continue;
 116:                     headers.Add (hdr.Substring (0, pos), hdr.Substring (pos + 1));
 117:                 }
 118:  
 119:                 return response.Substring (hdrLen + 4);
 120:             }
 121:             catch
 122:             {
 123:                 return null;
 124:             }
 125:             finally
 126:             {
 127:                 // close the connection
 128:                 if (null != sock && sock.Connected)
 129:                 {
 130:                     sock.Disconnect (false);
 131:                     sock.Close ();
 132:                 }
 133:             }
 134:         }
 135:  
 136:         /// <summary>
 137:         /// Sends string data over the socket.
 138:         /// </summary>
 139:         /// <param name="client"></param>
 140:         /// <param name="data"></param>
 141:         private static void Send (SocketState state, string data)
 142:         {
 143:             // Convert the string data to byte data using ASCII encoding.
 144:             byte [] byteData = Encoding.ASCII.GetBytes (data);
 145:  
 146:             // Begin sending the data to the remote device.
 147:             state.Socket.BeginSend (byteData, 0, byteData.Length, 0,
 148:                 new AsyncCallback (SendCallback), state);
 149:         }
 150:  
 151:         /// <summary>
 152:         /// Send data callback.
 153:         /// </summary>
 154:         /// <param name="ar"></param>
 155:         private static void SendCallback (IAsyncResult ar)
 156:         {
 157:             SocketState    state        = null;
 158:             Socket        client        = null;
 159:  
 160:             try
 161:             {
 162:                 // Retrieve the socket from the state object.
 163:                 state = ar.AsyncState as SocketState;
 164:                 client = state.Socket;
 165:  
 166:                 // Complete sending the data to the remote device.
 167:                 client.EndSend (ar);
 168:  
 169:                 // Signal that all bytes have been sent.
 170:                 state.Done.Set ();
 171:             }
 172:             catch
 173:             { }
 174:         }
 175:  
 176:         /// <summary>
 177:         /// Main receive thread entry point
 178:         /// </summary>
 179:         /// <param name="stateInfo"></param>
 180:         private static void StartReceive (SocketState state)
 181:         {
 182:             if (null == state)
 183:                 return;
 184:  
 185:             state.Socket.BeginReceive (
 186:                   state.ReadBuffer,
 187:                   0,
 188:                   state.ReadBuffer.Length,
 189:                   SocketFlags.None,
 190:                   new AsyncCallback (OnReceiveData),
 191:                   state
 192:             );
 193:         }
 194:  
 195:         /// <summary>
 196:         /// Receive data callback.
 197:         /// </summary>
 198:         /// <param name="stateInfo"></param>
 199:         private static void OnReceiveData (IAsyncResult result)
 200:         {
 201:             SocketState        state        = null;
 202:             Socket            sock        = null;
 203:             int                read        = 0;
 204:  
 205:             if (null == result)
 206:                 return;
 207:  
 208:             if (null == (state = result.AsyncState as SocketState))
 209:                 return;
 210:  
 211:             // get socket
 212:             sock = state.Socket;
 213:  
 214:             // end the read
 215:             if (0 != (read = sock.EndReceive (result)))
 216:             {
 217:                 state.Data.Append (Encoding.ASCII.GetString (state.ReadBuffer, 0, read));
 218:  
 219:                 // start another read
 220:                 sock.BeginReceive (
 221:                        state.ReadBuffer,
 222:                        0,
 223:                        state.ReadBuffer.Length,
 224:                        SocketFlags.None,
 225:                        new AsyncCallback (OnReceiveData),
 226:                        state
 227:                 );
 228:             }
 229:             else
 230:             {
 231:                 if (state.Data.Length > 0)
 232:                 {
 233:                     state.Socket.Close ();
 234:                     state.Done.Set ();
 235:                 }
 236:             }
 237:         }
 238:     }
 239:  
 240:     /// <summary>
 241:     /// SocketState class
 242:     /// 
 243:     /// Used to track an async TCP/IP data, and maintain all data received over the async operation.
 244:     /// </summary>
 245:     internal class SocketState
 246:     {
 247:         /// <summary>
 248:         /// Constructor
 249:         /// </summary>
 250:         public SocketState ()
 251:         {
 252:             Socket        = null;
 253:             ReadBuffer    = new byte [BUFFER_SIZE];
 254:             Data        = new StringBuilder ();
 255:             Done        = new ManualResetEvent (false);
 256:         }
 257:  
 258:         /// <summary>
 259:         /// Constructor
 260:         /// </summary>
 261:         /// <param name="socket"></param>
 262:         public SocketState (Socket socket)
 263:             : this ()
 264:         {
 265:             Socket = socket;
 266:         }
 267:  
 268:         /// <summary>
 269:         /// TCP/IP socket.
 270:         /// </summary>
 271:         public Socket Socket = null;
 272:  
 273:         /// <summary>
 274:         /// Size of download buffer.
 275:         /// </summary>
 276:         public const int BUFFER_SIZE = 1024;
 277:  
 278:         /// <summary>
 279:         /// Download buffer.
 280:         /// </summary>
 281:         public byte [] ReadBuffer;
 282:  
 283:         /// <summary>
 284:         /// Downloaded data converted to a string builder.
 285:         /// </summary>
 286:         public StringBuilder Data;
 287:  
 288:         /// <summary>
 289:         /// Reset event for synchronization.
 290:         /// </summary>
 291:         public ManualResetEvent Done;
 292:     }
 293: }