# Monday, June 09, 2008

A Simple Sound Effects Engine for Silverlight 2

Audio support is all too often one of the last things a developer thinks of when it comes to building a user interface. Fortunately, Silverlight offers some basic building blocks that make it fairly trivial to add event-driven sounds to our applications. I have taken the built-in functionality one step further, and created a simple run-time audio engine that makes it even easier.

First, I will discuss the requirements that I had in mind when I created this engine. Second, I will discuss the ideal API for a complete solution. Third, I submit the simple effects engine that I developed in order to meet those requirements and API.

Sound Effects Engine Requirements

  • Must be able to play looping “background music” tracks.
  • Must be able to play smaller sound effects on demand.
  • Must support concurrent (and overlapping) sounds effects without interfering with already-playing audio.
  • Must adequately handle the possibility of download delays when pulling down external audio files.
  • Should cache audio files between playbacks.
  • Should allow serving of audio from high-bandwidth CDN such as Silverlight Streaming.

An Ideal Sound Effects API

  • Should be very approachable. If possible, only a single line of code to play any audio (similar to PlaySound() API).
  • Should support any formats supported by Silverlight.
  • Should be efficient.
  • Should offer download and playback completion callbacks (for chaining and synchronization).
  • Should support aggressive background pre-caching of audio files.

The SilverlightToolbox Solution

To address the simplicity requirements, this sound effects engine is implemented as a single static C# class that can be easily included into any Silverlight project. It can exist in a referenced class library, or can be linked directly into the main project.

To address looping background music, a single method SetBackgroundLoop() is supplied. This will begin playback of a single audio clip, and will automatically repeat it. Only one track can be played as the background loop – calling this method again will terminate the running track and start the new one. You can also pass String.Empty to stop all background music.

To address typical sound effect clips. two overloads of the PlaySoundEffect() method are supplied. The simpler of the two methods will simply play a clip once it has been downloaded. The extended version allows you to specify a callback for when the clip has been downloaded and started playing, and a second callback that can be used for notification that the clip has ended.

To address the scenario where multiple sound effects might be played at the same time, the engine internally maintains a queue of MediaElements. When a new sound needs to played, it pulls an unused element and puts it into service. Once the sound is finished, the element is returned to the queue. This allows Silverlight itself to handle media mixing, and by caching those MediaElements, it does so without placing undue stress on the environment.

To address the issue of download delays, the startedCallback and completedCallback parameters of PlaySoundEffect() were introduced.

To address caching of audio files, a WebClient is used (which in turn leverages the browser’s cache). Furthermore, the engine will reuse any downloaded file streams (and is smart enough to not re-queue the same file if it already queued for download).

By using a MediaElement for playback, audio tracks are automatically supported from streaming sources and Content Delivery Networks, and can be of any type supported by Silverlight.

To support chaining of audio effects, and to support synchronization of UI with audio, the PlaySoundEffect() method accepts callback events that are fired when the clip has been downloaded, and again when it has completed playback. To further help with UI synchronization, a second utility class is provided (DelayedAction) which provides a simple wrapper for BackgroundWorker that can be used to easily delay execution of a block of code after a specified amount of time.

To support pre-caching of audio files, the PreloadMedia() method can be used.

Typical usage:

In order for the sound effects engine to function properly, it must be provided with a top-level XAML container (MediaElement currently will not perform playback without a parent object). This is done by calling the Initialize() method, typically from your program’s startup code:

SoundEffects.Initialize(this.LayoutRoot);

 

After this has been done, background music can be played, and we can also queue up some sound effect clips for later:

SoundEffects.SetBackgroundLoop("cautious-path.wma");
SoundEffects.PreloadMedia("pop1.wma");

 

Then, at various points throughout the application, we can play the sound effect (for example, in response to a control event):

SoundEffects.PlaySoundEffect("pop1.wma");

 

If at any point we need to delay the sound effect slightly, we can control this be introducing a short delay:

DelayedAction.Execute(2.0, () => SoundEffects.PlaySoundEffect("pop1.wma"));

 

Complete Source Code for DelayedAction.cs:

   1: using System;
   2: using System.ComponentModel;
   3: using System.Threading;
   4:  
   5: namespace Wintellect.SilverlightToolbox
   6: {
   7:     public class DelayedAction
   8:     {
   9:         class DelayedCallback
  10:         {
  11:             public TimeSpan Delay { get; set; }
  12:             public Action Callback { get; set; }
  13:         }
  14:  
  15:         public static void Execute(double seconds, Action callback)
  16:         {
  17:             BackgroundWorker Delay = new BackgroundWorker();
  18:             Delay.DoWork += (s, e) =>
  19:             {
  20:                 DelayedCallback DelayCallback = (DelayedCallback)e.Argument;
  21:                 Thread.Sleep(DelayCallback.Delay);
  22:                 e.Result = DelayCallback.Callback;
  23:             };
  24:             Delay.RunWorkerCompleted += (s, e) =>
  25:             {
  26:                 Action Callback = e.Result as Action;
  27:                 Callback();
  28:             };
  29:             Delay.RunWorkerAsync(new DelayedCallback
  30:             {
  31:                 Delay = TimeSpan.FromSeconds(seconds),
  32:                 Callback = callback
  33:             });
  34:         }
  35:     }
  36: }

 

Complete Source Code for SoundEffects.cs:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.IO;
   4: using System.Net;
   5: using System.Windows;
   6: using System.Windows.Controls;
   7: using System.Windows.Media;
   8:  
   9: namespace Wintellect.SilverlightToolbox
  10: {
  11:     public static class SoundEffects
  12:     {
  13:         static Panel Root;
  14:         static MediaElement BackgroundLoop = new MediaElement();
  15:         static WebClient EffectDownloader = new WebClient();
  16:  
  17:         static Queue<MediaElement> AvailableSoundEffectGenerators = new Queue<MediaElement>();
  18:         static Dictionary<string, Stream> DownloadedEffects = new Dictionary<string, Stream>();
  19:         static Queue<string> PendingDownloads = new Queue<string>();
  20:         static Queue<QueuedEffect> PendingEffects = new Queue<QueuedEffect>();
  21:         static Dictionary<MediaElement, Action> PendingStartupCallbacks = new Dictionary<MediaElement, Action>();
  22:         static Dictionary<MediaElement, Action> PendingCompletionCallbacks = new Dictionary<MediaElement, Action>();
  23:  
  24:         enum TargetType
  25:         {
  26:             BackgroundMusic,
  27:             SoundEffect,
  28:         }
  29:  
  30:         class QueuedEffect
  31:         {
  32:             public string MediaName { get; set; }
  33:             public TargetType Target { get; set; }
  34:             public Action StartedCallback { get; set; }
  35:             public Action CompletedCallback { get; set; }
  36:         }
  37:  
  38:         public static void Initialize(Panel root)
  39:         {
  40:             Root = root;
  41:             InitializeTarget(root, BackgroundLoop);
  42:             EffectDownloader.OpenReadCompleted += (s, e) =>
  43:             {
  44:                 DownloadedEffects[(string)e.UserState] = e.Result;
  45:                 DownloadEffects();
  46:                 PlayEffect();
  47:             };
  48:         }
  49:  
  50:         static void DownloadEffects()
  51:         {
  52:             if (PendingDownloads.Count == 0)
  53:                 return;
  54:             string MediaName = PendingDownloads.Dequeue();
  55:             EffectDownloader.OpenReadAsync(new Uri(MediaName, UriKind.Relative), MediaName);
  56:         }
  57:  
  58:         static void InitializeTarget(Panel root, MediaElement target)
  59:         {
  60:             target.Width = 0;
  61:             target.Height = 0;
  62:             target.Visibility = Visibility.Collapsed;
  63:             root.Children.Add(target);
  64:             target.AutoPlay = false;
  65:             target.MediaOpened += (s, e) =>
  66:             {
  67:                 MediaElement Target = s as MediaElement;
  68:                 Target.Volume = 0.35;
  69:                 Target.Play();
  70:                 if (PendingStartupCallbacks.ContainsKey(Target))
  71:                 {
  72:                     Target.Dispatcher.BeginInvoke(PendingStartupCallbacks[Target]);
  73:                     PendingStartupCallbacks.Remove(Target);
  74:                 }
  75:             };
  76:             target.MediaEnded += (s, e) =>
  77:             {
  78:                 MediaElement Target = s as MediaElement;
  79:                 Target.Stop();
  80:                 if (s == BackgroundLoop)
  81:                     Target.Play();
  82:                 else
  83:                     AvailableSoundEffectGenerators.Enqueue(Target);
  84:  
  85:                 if (PendingCompletionCallbacks.ContainsKey(Target))
  86:                 {
  87:                     Target.Dispatcher.BeginInvoke(PendingCompletionCallbacks[Target]);
  88:                     PendingCompletionCallbacks.Remove(Target);
  89:                 }
  90:             };
  91:         }
  92:  
  93:         static MediaElement GetUnusedEffectGenerator()
  94:         {
  95:             if (AvailableSoundEffectGenerators.Count > 0)
  96:                 return AvailableSoundEffectGenerators.Dequeue();
  97:             else
  98:             {
  99:                 MediaElement Result = new MediaElement();
 100:                 InitializeTarget(Root, Result);
 101:                 return Result;
 102:             }
 103:         }
 104:  
 105:         static void PlayEffect()
 106:         {
 107:             lock (PendingEffects)
 108:             {
 109:                 if (PendingEffects.Count == 0)
 110:                     return;
 111:                 QueuedEffect Effect = PendingEffects.Dequeue();
 112:                 if (DownloadedEffects.ContainsKey(Effect.MediaName))
 113:                 {
 114:                     MediaElement TargetElement = null;
 115:                     switch (Effect.Target)
 116:                     {
 117:                         case TargetType.BackgroundMusic:
 118:                             { TargetElement = BackgroundLoop; break; }
 119:                         case TargetType.SoundEffect:
 120:                             { TargetElement = GetUnusedEffectGenerator(); break; }
 121:                     }
 122:                     if (Effect.StartedCallback != null)
 123:                         PendingStartupCallbacks.Add(TargetElement, Effect.StartedCallback);
 124:                     if (Effect.CompletedCallback != null)
 125:                         PendingCompletionCallbacks.Add(TargetElement, Effect.CompletedCallback);
 126:                     TargetElement.SetSource(DownloadedEffects[Effect.MediaName]);
 127:                 }
 128:                 else
 129:                 {
 130:                     PendingEffects.Enqueue(Effect);
 131:                 }
 132:             }
 133:         }
 134:  
 135:         static void PlaySound(TargetType target, string mediaName, Action startedCallback, Action completedCallback)
 136:         {
 137:             if (target == TargetType.BackgroundMusic)
 138:                 if (BackgroundLoop.CurrentState != MediaElementState.Stopped)
 139:                     BackgroundLoop.Stop();
 140:  
 141:             if (mediaName != String.Empty)
 142:             {
 143:                 lock (PendingEffects)
 144:                 {
 145:                     if (!DownloadedEffects.ContainsKey(mediaName))
 146:                     {
 147:                         PendingDownloads.Enqueue(mediaName);
 148:                     }
 149:                     PendingEffects.Enqueue(new QueuedEffect
 150:                     {
 151:                         MediaName = mediaName,
 152:                         Target = target,
 153:                         StartedCallback = startedCallback,
 154:                         CompletedCallback = completedCallback
 155:                     });
 156:                 }
 157:                 DownloadEffects();
 158:                 PlayEffect();
 159:             }
 160:         }
 161:  
 162:         public static void SetBackgroundLoop(string mediaName)
 163:         {
 164:             PlaySound(TargetType.BackgroundMusic, mediaName, null, null);
 165:         }
 166:  
 167:         public static void PlaySoundEffect(string effectName)
 168:         {
 169:             PlaySound(TargetType.SoundEffect, effectName, null, null);
 170:         }
 171:  
 172:         public static void PlaySoundEffect(string effectName, Action startedCallback, Action completedCallback)
 173:         {
 174:             PlaySound(TargetType.SoundEffect, effectName, startedCallback, completedCallback);
 175:         }
 176:  
 177:         public static void PreloadMedia(string mediaName)
 178:         {
 179:             if (!DownloadedEffects.ContainsKey(mediaName))
 180:             {
 181:                 PendingDownloads.Enqueue(mediaName);
 182:                 DownloadEffects();
 183:             }
 184:         }
 185:     }
 186: }
Monday, June 09, 2008 5:59:22 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [7] | 

# Tuesday, May 13, 2008

Gem Blaster updated and enhanced for Silverlight 2

I finally got around to updating my Gem Blaster game from Silverlight 1.1 alpha to the 2.0 beta bits. Since there were very heavy changes to the control model and other aspects of the managed runtime, I had to rewrite a lot of the original code (this was fully expected by the way). While I was in there, I also took the opportunity to add a number of other new features such as a simple sound FX engine, a self-playing "demo mode", and a bunch of other improvements.

I intend to update CodePlex soon with the new source code, but for now you can try out the game here (embedded below). It is hosted on the Silverlight Streaming service, so feel free to pass the link around (it won't kill *my* servers). If you like, you can also directly embed the game using the following embeddable HTML snippet:

<iframe 
    src="http://silverlight.services.live.com/invoke/5683/GemBlasterV2/iframe.html"
    scrolling="no"
    frameborder="0"
    style="width:800px; height:625px">
</iframe>

 

Now that this project has been updated for Silverlight 2, I can move on to my next game project idea which (I am hoping) should really push the runtime to its limits :)

Tuesday, May 13, 2008 5:37:56 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Sunday, March 02, 2008

Atlanta Code Camp 2008

We are happy to announce that the 2008 Atlanta Code Camp is coming up soon. We have confirmed the event date of Saturday, March 29th, and it will be held at the Devry University campus in Decatur (this is the same place as last year).

We are actively seeking speaker submissions for the event. You can get the speaker form from our speakers page. We are also looking for volunteers to help on the day of the event. If you are interested in volunteering, please sign up here.

Attendee Registration is not open yet, but check back often because it is likely to fill up quickly once opened.

.NET | Events | General
Sunday, March 02, 2008 9:16:11 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

Speaking at the Atlanta Cutting Edge / Atlanta MS Professionals Tomorrow

Monday night, March 3rd (tomorrow), I am lined up to present on the topic of "Surviving the Multi-core Revolution". This presentation focuses on the concepts and skills needed to bring scalability and performance to server-based processing.

.NET | Events | General
Sunday, March 02, 2008 9:06:33 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Wednesday, February 27, 2008

Heading to MIX this year

This year I will be heading to MIX in Vegas along with thousands of other UX enthusiasts. I have always had a deep interest in all things related to User Experience, and for the past couple years have wished I could attend a MIX event, and finally this year I get to go!

blings_9_25_d[1]

What will I be doing at MIX? Well I will certainly be soaking up any and all information related to Silverlight and WPF. I will also stick my head into some of the designer-oriented sessions. It's a good thing to see how the other half lives. In between sessions I am hoping to meet all kinds of people who are also passionate about UX. And of course this is Vegas, so I am sure I will lose a few dollars in a casino at some point and drink more booze than is healthy.

Joining me will be a number of Wintellectuals including Steve Porter, Sergio Loscialo, Rik Robinson, Sara Faatz, and Todd Fine. I know of a number of other local Atlanta folks will be making the trip as well: Sean Gerety, Doug Turnure, and Shawn Wildermuth to name a few. Are you going too? If so, let me know and we can get together for a cup of coffee or a beer.

.NET | Events | General | Silverlight | WPF
Wednesday, February 27, 2008 9:11:59 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [1] | 

# Sunday, February 24, 2008

Slides and Code from Alabama Code Camp 6

I have uploaded my slides and associated source code that was demonstrated, for the benefit of those who were not able to attend my session, or for those who have asked for copies of the code and slides.

I understand that these will be made available from the Alabama Code Camp web site, but I am also making them available for download from my server as well: http://www.mindfusioncorp.com/weblog/content/binary/AlabamaCC6-Silverlight-KeithRome.zip

Sunday, February 24, 2008 7:20:18 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Friday, February 22, 2008

Heading to Alabama Code Camp 6

I am packing my bags and heading out to Huntsville AL tonight. In the morning I will be kicking off the Silverlight Track at the Alabama Code Camp with a presentation titled "Tapping into the power of Silverlight 1.0". My goal with this presentation is to show that although 2.0 will indeed be a phenomenal release of the Silverlight platform, the currently shipping version is still very powerful and offers a tremendous amount of value.

If you are planning on attending this Code Camp event, please stop by and listen in!

Friday, February 22, 2008 11:15:08 AM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Thursday, January 31, 2008

Source Code for Gem Blaster finally published to CodePlex

Last fall I showed off a new game that I had built using Silverlight 1.1 at a few User Group meetings across the southeast. I showed the internal "guts" of the puzzle game, and I think people generally thought it was a really cool project. I promised that I would make the code available, but never actually got around to publishing it.

Until tonight.

Gem Blaster is now (finally!) published to CodePlex at http://www.codeplex.com/gemblaster

Full source code is available there.

Also, if you just want to play the game (after all, it IS a game, and somewhat addictive too), I have a "live demo" posted to the Wintellect server here: http://demo.wintellect.com/gemblaster/default.html

image

Enjoy!

Thursday, January 31, 2008 12:00:56 AM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Wednesday, January 30, 2008

PolyGraph3D: Making 3D happen with Silverlight 1.0!

Yes, you read that right. Silverlight 1.0 - as in unmanaged JavaScript - and 3D.

Last week I was reminded of the FarSeer Physics engine for XNA and Silverlight 2.0. I have a strange fascination for 3D software - stemming back from the years when I was a beta tester and plugin developer for Caligari trueSpace 3D - so I decided to poke around in the source code from CodePlex to see what they were doing. Turns out it was just mostly linear algebra and some simple mechanics - things I remembered working with many years ago before the age of managed runtimes and rich visual APIs. Back then we had to do all the heavy lifting with highly optimized C++ routines and drawing directly to an HWND. But things are different now, and what seemed incredibly hard in years past really didn't seem all that hard anymore.

So I was inspired I guess.

I know I could have started with the FarSeer code, and built upon that using C# and targeting the managed runtime. But oh no - that was too easy! I figured that if it can be done using simple trig and a solid model design, I bet I could make it work in JavaScript. After all, JavaScript's Math intrinsic object supports Sin() and Cos(), extensible objects, and arrays - and at the end of the day, that's all one really needs in order to create a 3D runtime. Sure, it involves a fair amount of matrix operations and dot-products and cross-products, but all those things can be learned by reading up on Wikipedia these days (or mathreference.com).

So with that, I set out to create an unmanaged 3D visualization engine for Silverlight...

I am making the code freely available and have already published out to CodePlex here: http://www.codeplex.com/polygraph3d

My efforts so far are looking pretty good (I think). Over the course of about 8 hours of coding and testing, I have the basics working. I can create a 3-dimensional polyhedron (a mesh if you will), and I can display the object in a Silverlight Canvas. I can apply scaling, rotations, and positioning of the polyhedra, and I can also build complex objects using polyhedron groups, each of which has its own local scaling/rotation/position transforms. It also supports a movable camera and performs rudimentary perspective correction as well as small optimizations for backface-culling. It currently only supports simple brushes for the object faces - I would like to implement a real texture mapping system, but that will require some very creative use of image skewing to pull it off.

I have a test page up that demos a simple 3D cube that you can move around the virtual viewport space...

image

For sure, it is a very simple demo. Clicking the red, green, and blue axis bars will move the cube around. The "spin" button introduces a gradual rotation around the Y axis... but since my rotation transform code is currently broken, the effect isn't quite what I had in mind. Hopefully I will figure that particular bug out soon.

One major hurdle I encountered was the fact that Silverlight does not let you draw directly on a Canvas, nor does it let you create your own controls. This posed a problem since I wanted to display things that simply could not be expressed using 2D XAML. I "solved" this problem by performing all of the mathematics needed to project the 3D scene into a 2D viewport, and then I use the vertex data from the projected mesh to build a series of 2D Path elements. It was indeed a dirty trick - but hey, sometimes you just have to make do with the capabilities of the platform.

Wednesday, January 30, 2008 10:33:45 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Saturday, December 01, 2007

Silverlight Bug: MediaElements will restart if their containment lineage changes

I have not yet found a workaround for this problem.

The setup is simple: Create two Canvas elements. In one canvas, place a MediaElement. Point the media element to a valid video source. It doesn't matter if it is set to AutoPlay or not (but if using manual play, then you will need to initiate playback in some manner after loading).

Now once that video playback has begun (it doesn't matter how), if you remove the MediaElement from the original canvas using Children.Remove() and then add it to the other canvas using Children.Add(), then the playback position will reset and will start playing from the beginning.

I would possibly expect this behavior if the MediaElement has the AutoPlay property enabled, but this also happens when AutoPlay is false. Basically, as long as the media is active, it is restarted if you relocate the element to another parent control. I am guessing this is a bug in the MediaElement's OnLoad implementation that is not respecting the AutoPlay setting if the media is currently being played, and is internally calling Stop() and Start().

Saturday, December 01, 2007 12:24:02 AM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

Silverlight Bug: Using a packaged image source for multiple Image elements

I ran into this nasty little bug today... it is not easy to reproduce, but when it happens it is very annoying to debug.

First, this bug only occurs when you are using a ZIP file to package your external resources and using a Silverlight Downloader object to bring the package to the browser, and subsequently using Image.SetSource() to provide the image files to the visual elements.

Second, it's not really a bug in functionality exactly, but more of a nuisance to the viewer. You see, the images get displayed correctly, but Silverlight throws extra error messages.

The problem occurs when you reuse a single image resource from a downloaded zip archive for multiple Image elements. And it only happens when the two images are assigned to the same resource consecutively. Example:

function downloadComplete(sender, eventArgs)
{
  // this one is OK
  sender.GetHost().FindName(“Image1”).SetSource(sender, “picture.png”);
  // this one fails
  sender.GetHost().FindName(“Image2”).SetSource(sender, “picture.png”);
}

This is using Silverlight 1.0, but I assume the same issue also happens in 1.1.

The problem appears to be related to referencing the same resource twice consecutively. If you reference another resource from the Downloader between the two calls to SetSource(), then the problem goes away. Also, if you simply don't reuse the same resource like this, then it can be avoided.

UPDATE January 2008: My previous "fix" of referencing another resource in between uses of the same resource does not seem to always work. In addition, some Silverlight installations (not all!) are also raising spurious ImageError 4001 messages. The only complete fix I have found is to implement a custom error handler, and ignore those ImageErrors:

function handleError(sender, errorArgs)
{
  if (errorArgs.errorType == "ImageError" && errorArgs.errorCode == 3002)
    {
      // This error is raised sporadically by SetSource
      return;
    }
    if (errorArgs.errorType == "ImageError" && errorArgs.errorCode == 4001)
    {
      // This error is raised sporadically by SetSource
      return;
    }
  Silverlight.default_error_handler(sender, errorArgs);
}

Saturday, December 01, 2007 12:15:55 AM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Friday, November 30, 2007

The Atlanta .NET Doubleheader: Visual Studio 2008 Loadfest and XBox Gaming Night

This coming Monday night would normally be our monthly Atlanta MS Pros / Atlanta Cutting Edge .NET / Atlanta VB.NET user group meeting, but this month we have a special treat lined up...

Microsoft (aka Doug Turnure) will be providing a FREE copy of Visual Studio 2008 (Professional Edition) to the first 150 people that arrive. This is a GREAT way to get an upgrade right away without having to convince your boss to buy a license! Well, technically we will be giving out DVDs with the trial version, but as soon as the Retail Packages are ready, each person that gets a Trial copy on Monday will receive a full Retail Boxed copy.

So bring your laptop. Most folks will be loading it up right there, so you might as well join in and get your upgrade on.

And then, after the LoadFestivities, everyone will be welcome to come join in some XBOX fun... we have 9 (yes, NINE) xbox 360 consoles and 9 matching big-screen TV's, so there should be plenty of room for everyone to have a good time. The name of the game is Halo3, so put on your MJOLNIR armor and get ready to frag your buddies! And if John-117 is too intense for you, we will also have Guitar Hero cranking on some of the consoles... so you can come and rock out to some Hit Me With Your Best Shot on Easy.

I hear the Master Chief himself might be there to take on challengers!

Please register in advance, so that we can have an accurate count of attendees. The registration link is here.

Location:

Microsoft Corporation [Alpharetta]
1125 Sanctuary Pkwy.
Suite 300
Atlanta, GA 30004

See you there!

.NET | Events | Games | General
Friday, November 30, 2007 11:59:37 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Tuesday, October 23, 2007

10 interview tips that will help you land a better job

My last post was somewhat negative. I acknowledge that. I was annoyed. Let me make amends by posting some useful, positive information for those who find themselves on the other end of the interview table (or phone).

  1. Google Live Search your interviewer. Most recruiters will tell you who will be performing your interview. If they don't venture the information, then ask for it - chances are if they know then they will tell you. Take that name and do some research. Get to know what your interviewer is most likely to be questioning you about. If they have written a book on security best practices, then there is a pretty good chance they will ask you questions about security. Do drop subtle hints that you read their weblog - most tech people like to hear that - just be sparing in it. You don't want to come off as a stalker.
  2. Be honest about your skill level. Many interviewers will ask you how you rate yourself, so that they can judge just how delusional you are. Be honest here. If you claim to be a 10 out of 10 in a subject area, then you had better be an absolute expert. A 10 out of 10 is expected to know that subject inside and out, perhaps even teach the interviewer a thing or two. Don't be too humble though. Rating yourself as a 2 out of 10 is highly unlikely to get you into the interview room in the first place.
  3. Don't interrupt. When the interviewer is speaking, never (and I mean NEVER) forcibly interrupt them. I have had many interviews where the candidate would inject words, statements, or questions while I was trying to guide the interview towards the next topic. Doing that does not impress the interviewer with your profound wisdom. What it does is send a clear message that you feel your thoughts are more important than the interviewer's... which is nothing but a fast track to bottom of the resume stack.
  4. Speak clearly. No need to shout, but you should be certain that you speak confidently and with ample volume to be heard clearly. Avoid slang terms - especially cursing! Try to provide concise and accurate answers, with as few "umms" as possible. And for heavens sake, if you don't know the answer to a question, just say it rather than trying to BS your way through it.
  5. Be prepared to ask questions about the employer's business and work environment. Even if you already know the answers (you did research the company's website beforehand, didn't you?). This shows an interest in the company and team.
  6. Be prepared to answer strange, sometimes seemingly irrelevant questions during the interview. Good interviewers are not looking for right or wrong answers to every question - they are looking for clues about how you work your way through problems and how you are able to handle stressful situations. This is especially true in the Consulting industry, where your reaction to a crisis is often more visible and more important than the act of correcting the underlying problem itself.
  7. Follow-up. If you already did a technical screening and are now in for the "big face to face" interview, chances are good that you missed at least one of the questions during the screening. You should note those questions during the initial interview, and research them before going to the main interview - especially if the interviewer is the same person. Let them know that you felt compelled to research the topic on your own time, and that you now have an answer for that missed question if they would like to hear it. Chances are they won't want to hear the answer, but they will take notice that you followed up and did your homework in between the interviews.
  8. Be calm. It is normal to be nervous. Some folks even have obvious nervous twitches that come out in full color during something as stressful as an interview (sweating, fast talking, jittering). Take a few steps to defeat those demons beforehand - exercise rigorously the morning before your interview, this will clear your mind and stabilize your metabolism, which helps control sweating problems. Learn some deep breathing exercises if you need help calming down beforehand. Never, under any circumstances, drink a "Double Vente Latte Machiatto" or other "energy drink" less than an hour before the interview. All that caffeine will lead to a panicky interviewee that talks WAY too fast and incoherently, and that is trying to hold their bladder for an hour. Nothing good can come of that.
  9. Sleep well the night before. Don't study your "interview cheat sheet" late into the night. Go to bed early, and go to bed with a clear mind. You will not sleep well if you spend the night ruminating over those questions and answers. In fact, I understand that taking an over-the-counter aid (if you are healthy enough) can help. Seasickness medications such as Bonine can clear nausea from "stomach butterflies" that might precede a stressful interview, and also have the nice side effect of being a sleeping aid (causes drowsiness). As always, check with your doctor before taking something like that.
  10. Smile. The interviewer is not only looking to see if you know the technical answers to their questions, they are also evaluating whether they would want to work with you on a team or not, and if you know how to enjoy working with others. When interviewing, the measuring stick I often use is to ask myself "Would I be comfortable having a beer after work with this person?". You might be surprised how often the answer to that is "no" (especially in the ultra-bizarre circus of tech workers).

And here is a "bonus" tip submitted by David Daughtrey...

11. Dont eat at the Wing Factory on the night before an interview. Or any hot wing establishment for that matter.

Tuesday, October 23, 2007 2:22:18 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

How to Botch an Interview and Ensure that you will Never get an offer

I have been in this industry for quite a while... about 15 years. I have spent the majority of that time in upper-tier roles, or at least as "upper tier" as it can be without losing touch with the technology itself. I am one of those "hands-on" folks that would never ask a person on my team to build something that I wasn't 100% positive that I could (and would) do myself. As a result, my technical skills have always been kept sharp.

And because of those very solid technical skills, I have almost always been deeply involved in the recruitment and interview process at whatever companies I have worked for. I typically perform several interviews per month, sometimes more, sometimes less, generally depending on hiring urgency or other market conditions. But this morning I have had without a doubt the WORST interview I have ever had to participate in. I will not divulge the name or anything else about this person, as that's not my style, so please do not ask. But what I can do is provide some advice on things you should NOT do unless you really want to bomb an interview horribly...


What NOT to do in an interview:

  1. If you are asked to "self rate" yourself, give yourself a 9 out of 10 in a new "buzz" technology that you really don't know much about. The interviewer won't know the difference anyway.
  2. Give the recruiter your cell phone number even though you know you get horrible reception where you expect to be taking technical screening calls.
  3. Before starting a technical screening, be sure to tell the interviewer that your skills are "more broad than deep" so that they will see just how fabulously excellent you are even if you miss a bunch of the questions.
  4. When the interviewer asks an entry-level question that you don't know, complain that "those kinds of nitpicking questions are for a more junior person than me", and follow it by "I usually manage people who would answer those kinds of questions".
  5. Try to turn the tables on the interviewer if you don't think you are doing well. Try to convince them that they are being unreasonable by asking them a technical question of your own. The idea here is to make sure that they can't answer it correctly - in fact, just make something up! Here is a good one to try: "what’s the parameter five of the MoveWindow?". Without a doubt, you will have made your point to the interviewer.
  6. Be sure to argue with the interviewer that they are wrong about their own entry-level question. After all, only a moron would claim that "SQL Server" was one of the three "out of the box" configurable options for Session State storage in ASP.NET.
  7. Remember, nothing can prove you wrong, not even Truth itself. If the interviewer isn't asking you the questions that you want them to ask, then it is surely because they are not worth your time. In fact, you should tell them that they ask too many nitpicking questions, and then hang up on them.

What a complete tool.

Tuesday, October 23, 2007 12:56:52 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Thursday, October 18, 2007

Expression Design Service Pack 1

While it probably will not get as much attention as a Visual Studio or Windows Service Pack release, the Expression Team blog announced that there is an SP now available for Expression Design that solves some very nagging issues with the RTM version of the product. These problems mostly impacted those of us using Design and Blend with Silverlight, most were a nuisance and had workarounds, but this update really improves the "flow" of creating a Silverlight or WPF UI.

Some of the "big" fixes from my perspective:

  • Gradient Midpoints are now exported (glass fanatics across the globe rejoiced). This was one of my pet peeves with gradients - you could use Midpoints to create truly spectacular glass and glow effects in Design - but they would end up more along the lines of "craptacular" when exported to XAML. The workaround wasn't 100% equivalent, and was fairly annoying (convert midpoints to new gradient stops before exporting).
  • Exporting to XAML will now emit the correct (forward) slash character in image paths for Silverlight exports. This was an annoying problem when Silverlight 1.0 was sent to RTM and no longer supported the backslash.
  • Text exported as TextBlocks instead of Paths. Thatsa verra niiice!

One thing that hasn't been addressed that still bugs me is how the exporter handles layers: Each layer becomes a canvas stacked, each stacked on top of the other. This isn't inherently troublesome, except that the canvases all start at 0,0 and fill the workspace... which basically means that only the topmost canvas will recieve mouse events by default. It would be better if the exported canvases were only as large as they needed to be, and positioned accordingly.

Then again, I guess I could always file a bug/suggestion report that would be more likely to be seen by the Expression Team...

.NET | General | Silverlight | WPF
Thursday, October 18, 2007 7:23:12 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Wednesday, October 17, 2007

Win a free pass to Devscovery 2008!

John Robbins, the wizard of debugging, is looking for suggestions for the Devscovery 2008 Keynotes. To encourage submissions, he is offering a FREE conference pass to the person with the best idea. Full price for such a pass is $900, which is a bargain in itself, but FREE is even BETTER!

The spring Devscovery will be in New York, and the fall Devscovery will be held in Redmond - the winner will get to choose which event they prefer to attend. Having attended the fall Redmond conference this year, I HIGHLY recommend it! Even if I weren't a Wintellect employee, I would still be comfortable claiming that this is hands-down the best way to spend your training time and budget.

To submit a keynote idea, please either comment on John's post here or email your suggestion directly to him. You can submit as many ideas as you like.

.NET | Events | General | Silverlight | WPF
Wednesday, October 17, 2007 10:16:43 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Saturday, September 01, 2007

No user group meeting Monday night

We have not sent out a bulletin message yet, but we will not be meeting on Monday 9/3 due to the holiday. The next Atlanta Cutting Edge / VBUG / AMP meeting will take place in October.

.NET | Events | General
Saturday, September 01, 2007 4:52:14 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Tuesday, August 28, 2007

Speaking in Charlotte tonight

Steve Porter and myself are driving up to Charlotte tonight to present on Silverlight at the Developers Guild meeting. Steve will be giving an overview of Silverlight features and development, and of course I will be deconstructing my newest Silverlight game - Gem Blaster!

If you remember Popper!, this is the next generation of that game engine, upgraded to work with the newer Alpha 1.1 Refresh, and with better graphics and gameplay. You can also go directly here to play the game: http://www.mindfusioncorp.com/gemblaster/

EDIT: The game has been moved to the Wintellect servers at: http://www.wintellect.com/gemblaster/

I am also working on getting the source code published to CodePlex, but it has taken a while due to my very busy work schedule.

Tuesday, August 28, 2007 11:14:12 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [2] | 

# Wednesday, August 15, 2007

Blend 2 August CTP Refresh

Using the August CTP of Expression Blend 2? Worried about the lack of a registration key and that ever-decreasing "remaining days" counter at startup?

The Expression team has released a new refresh build to address that. This build is supposed to not expire until January 2008. It also has a refreshed Silverlight template that creates projects compatible with the Alpha 1.1 refresh that shipped earlier this month. You can go here to find out more.

Too bad they didn't get in a quick fix for the clipped menus bug too...

Wednesday, August 15, 2007 10:05:39 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Wednesday, August 08, 2007

AirportWait (Silverlight Demo)

Here is a second Silverlight demo you may or may not have seen already... this one is from a former colleage, John West. AirportWait (http://www.airportwait.com/) is a website that provides congestion data for the various checkpoints in your local airport (where provided). It basically lets you get an idea of just how early you should plan on getting to that gate in order to make your flight. Silverlight is being used to create the polar (circular) charts.

Check it out!

Wednesday, August 08, 2007 6:48:16 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

SilverLife (Silverlight Demo) posted

Jeff Prosise just published a new code sample to his Wintellect blog to show his Silverlight adaptation of the classic Game of Life, which he calls "SilverLife".

It's a really cool demo of Silverlight capabilities and programming model, and pretty fun to play with as well. Best of all, he has the source code available to download as well so you can see exactly how things are being done under the hood.

Go check it out!

Wednesday, August 08, 2007 5:19:14 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Monday, July 09, 2007

MVP Award - C#

This year, both Dan Attis and myself recieved MVP awards from Microsoft. I am very honored that my contributions to the developer community have been recognized, and I hope to continue giving to the local community in the years to come... but at least now my wife can see something tangible to show for all of my involvement (she has a hard time with the fact that I spend almost every monday night out at UG meetings instead of being home with her).

Anyways, I am very pleased to have been given this award. Special thanks go to Doug Turnure for supporting us local guys, and also thanks to my wife for putting up with it all, and both my current (Wintellect) and former (Intellinet) employers for having the vision to support involvement in the community.

Monday, July 09, 2007 11:53:33 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [4] | 

Whose Slide is it anyway?

On Monday, July 9th (thats today!), Microsoft is trucking in a bunch of evangelists who will participate in an impromptu user group meeting at the Microsoft campus.

There will be three "tracks" of sessions, one covering Vista Internals (by Brian Hitney - NC), another covering Silverlight (by David Isbitski - PA), and the third covering the ASP.NET Provider Model (by Danilo Diaz - PA). After the main presentations, there will be an open Q&A period followed by "Whose Slide is it Anyway?" featuring Dev Evangelists being asked to present for a couple minutes based on a slide from someone else's decks that they have never seen before.

The festivities will begin as 6:30pm. If you have been to a Microsoft User Group meeting in the past 2 years, then you already know the place. If not, then the map and directions from this page on the Cutting Edge User Group website should get you there.

Doug Turnure has more information about the event on his weblog here.

.NET | Events
Monday, July 09, 2007 11:41:13 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Monday, July 02, 2007

Popper!

Popper! is a simple Silverlight puzzle game. I wrote it as an exercise of my own skill with the platform, but then decided it was a rather fun (at least for a little while...) little game, so I am sharing it with the rest of the developer community. Popper! is written against Silverlight 1.1 alpha, and is mostly in C#, although the initial splash screen is done using unmanaged javaScript (yes, on purpose).

I will be walking through the innards of Popper! at the Atlanta Cutting Edge .NET User Group meeting tonight. So if you will be attending, then come check it out. Or if you just want to kill some time at "work" today... then play with it a little and let me know how it goes (good or bad)...

http://www.mindfusioncorp.com/popper/

I know of one minor bug so far: if you try to click around while a set of bubbles is in the process of "popping", then an error is raised internally, and the game pretty much stops working. I just haven't had the time to get that bug addressed yet.

I intend to post the source for this sometime after this month's meeting. Pretty much that equates to "when I have time to do it".

.NET | Events | General | Silverlight | Web 2.0 | WPF
Monday, July 02, 2007 2:40:42 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Thursday, June 14, 2007

Quick Tip - Input Controls in Silverlight

UPDATE 10/25/2007: Updated this sample to function correctly with the Silverlight 1.0 release. The main changes necessary were the typical 0.9 to 1.0 changes (remove "Sys.", isWindowless now takes a string and not a boolean, event handlers no longer string based), and I also had to explicitly set the z-index of the INPUT element. Thank you Erik for bringing it to my attention.

 

I have seen a lot of questions and confusion regarding capturing input when using Silverlight. There are no Button, TextBox, or other similar controls to work with. I see many folks asking for help with building their own directly within Silverlight - and bless their hearts, that is a daunting task indeed! The UI model currently does not offer basic input capture features such as "focus" or "tabbing", or even control-level keystroke capture. So folks tend to start building those basic services first, before they ever even get to writing code and xaml to support that simple textbox they need.

If you read that first paragraph and thought "thats crazy, it shouldn't be that hard!", then I would agree with you. Fortunately, there is a FAR easier and more robust way to achieve the same thing. In fact, its something that is not new to Silverlight at all, it's been with us for years. I am of course talking about the tried-and-true html <input> tag.

One of the most overlooked aspects of Silverlight is that it is a component, not a platform. Your browser is the platform. It can do a lot of stuff, if you just ask it to. Nobody wants an entire site as a single Silverlight canvas, just like nobody wants an entire site as a Flash canvas (unless possibly it is a mini-game or rich media application)... Flash designers realized this fact years ago. And as a component, a part of the solution if you will, Silverlight can play nicely with it's neighbors. With just a little bit of effort and sprinkling a very minimal amount of javascript pixie dust, we can get a Silverlight applet talking to the rest of our html DOM. And that's exactly what I am going to show in this topic...

You can download the code demonstrated in this article here (QuickTip-TextboxesInSilverlight.zip).

First of all, I am doing this with Silverlight 1.0 beta (the javascript one), as I think the 1.1 alpha is far too likely to change, and this technique should work with either. That, and I am lazy and don't want to come back and revisit this post later to correct the code...

Secondly, I am using the current CTP builds of Visual Studio Orcas and Blend 2 (the May 2007 bits), both with the Silverlight extensions. If you are using something else, then your mileage may vary.

UPDATE 10/25/2007: Code updated for VS2008 beta2 and the RTM version of Silverlight 1.0.

Now on to the code... to be sure we are on the same page, I am creating a new project from scratch...

First, Create a new project in Blend. Select the Silverlight 1.0 (JavaScript) project type. It does not matter what you name the project, but for this example I went with "TextboxesInSilverlight".

Switch to XAML view and replace the default canvas with this markup:

<Canvas
 xmlns="
http://schemas.microsoft.com/client/2007"
 xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
 Width="252" Height="272"
 Background="#FFFF2121"
 >
  <TextBlock Width="64" Height="24" Canvas.Left="8" Canvas.Top="8"
             Text="Opacity" TextWrapping="Wrap"/>
  <Ellipse Opacity="1" Fill="#FF0406FF" Stroke="#FF000000"
           x:Name="TheCircle" Width="180" Height="180" 
           Canvas.Left="36" Canvas.Top="64"/>
</Canvas>

This will create a simple red canvas, with a blue circle.

At this point, I generally switch over to Visual Studio Orcas since Blend does not have Intellisense nor does it really know how to deal with JavaScript. You can do this easily by right-clicking a project item (such as the xaml file) and selecting "Edit in Visual Studio".

Next, we need to do one small housekeeping chore to make sure that our Silverlight canvas plays nicely - specifically, we need to ask it to operate "windowless", which will allow other dhtml elements to overlay it, Open the Default.html.js file, and modify the call to Silverlight.createObjectEx(). We want to add the parameter for isWindowless...

 Silverlight.createObjectEx({
  source: "Scene.xaml",
  parentElement: document.getElementById("SilverlightControlHost"),
  id: "SilverlightControl",
  properties: {
   width: "100%",
   height: "100%",
   version: "0.9",
   isWindowless: "true"
  },
  events: {
   onLoad: sceneLoaded
  }
 });

To make things a bit more "clean", we will create the input element directly from code, however it's always good to control visual styling with CSS. Therefore, open up the Default.html, and alter the <style> tag to match the following:

 <style type="text/css">
  div, body, input
  {
   margin: 0;
   padding: 0;
  }
  #opacity
  {
   margin: -272px 0 0 75px;
   z-index: 100;
  }
  .silverlightHost
  {
   margin: 40px auto auto auto;
   height: 272px;
   width: 252px;
  }
 </style>

This will handle the placement and sizing of the silverlight container <div> as well as the input control itself. The negative margin is not a typo - this is used to pull the input control "on top" of the silverlight canvas. We could have also used absolute positioning, but that is much more brittle, relative positioning FTW. Also, notice the use of "auto" margins for the main Silverlight Host <div>. This is how you can center content without resorting to using <center> or <table>... if you take nothing away from this post, at least remember that one trick.

The last thing we must do is wire the whole thing up. This can be done in many places, in many ways. I consider this particular TextBox to be an extension of the Xaml "scene", so I will add my code to the TextboxesInSilverlight.Scene class which was created for us by the Blend project template. This is not the only place you could do this kind of code, but I found that in this particular example it made the most sense. Had I been building a dialog for a game engine, I might have this code in a seperate script file that manages my game mechanics (but thats another article...).

First, we need to capture a global reference to the Scene object that is created (this object is instantiated by the createSilverlight() function of the Default.html.js script file we edited in a previous step). The purpose of capturing this reference is that we will need it later in an event handler. This will allow our html <input> control to communicate back with the silverlight content. This is easier done than said. Open the Scene.xaml.js file. Just before the definition of the TextboxesInSilverlight.Scene.prototype (look up javascript prototype for what this is if you are interested, but that discussion is out of scope for this article), add a line of code to declare the global reference:

var globalScene = null;

Now we will create a callback function that will be used to create our JavaScript object and initialize it:

function sceneLoaded(control, userContext, rootElement)
{
    globalScene = new TextboxesInSilverlight.Scene();
    globalScene.handleLoad(control, userContext, rootElement);
};

Now, the idea for this example is that the value of the text box will determine the "Opacity" Xaml property of the Ellipse shape in our markup. In order for the event handler we are about to add to be able to do this, we will capture a reference to the circle object (technically we can wait and use findName() later during the event handler, but I prefer to capture it only once - its just my style of coding). Add this line to the handleLoad function:

this.circle = control.content.findName("TheCircle");

Next, we will create the input control and add it to the DHTML document. We will add it directly to the same <div> that Silverlight has injected itself into, and therefore any layout or positioning that affects the Silverlight canvas will also affect our <input> box. Add this code to the end of the handleLoad function:

var opacityEdit = window.document.createElement("input");
opacityEdit.type = "text";
opacityEdit.id = "opacity";
opacityEdit.name = "opacity";
opacityEdit.value = "1.0"
;

We are almost done - only two more steps and then we can fire this thing up! First, we need to add an event handler to react to changes in the value property of the input control. Add this code to the very end of the handleLoad function:

opacityEdit.onpropertychange = function()
    {
        if (event.propertyName == "value")
        {
            globalScene.circle.Opacity = event.srcElement.value;
        }
    }

This effectively creates an anonymous function to handle property change events on the <input> control, which in turn updates the Opacity property of the circle shape. Cool, huh?

The last thing to do is finally add the new <input> element to the page, otherwise all the work until this point will have had no discernable impact at all... add this one last line to the handleLoad function:

this.control.parentElement.appendChild(opacityEdit);

At this point, your Scene.xaml.js file should look like this:

if (!window.TextboxesInSilverlight)
 window.TextboxesInSilverlight = {};

TextboxesInSilverlight.Scene = function()
{
}

var globalScene = null;

function sceneLoaded(control, userContext, rootElement)
{
    globalScene = new TextboxesInSilverlight.Scene();
    globalScene.handleLoad(control, userContext, rootElement);
}

TextboxesInSilverlight.Scene.prototype =
{
 handleLoad: function(control, userContext, rootElement)
 {
  this.control = control;
  
  this.circle = control.content.findName("TheCircle");
  
  var opacityEdit = window.document.createElement("input");
  opacityEdit.type = "text";
  opacityEdit.id = "opacity";
  opacityEdit.name = "opacity";
  opacityEdit.value = "1.0";
  opacityEdit.onpropertychange = function()
    {
      if (event.propertyName == "value")
      {
        globalScene.circle.Opacity = event.srcElement.value;
      }
    }
  
this.control.parentElement.appendChild(opacityEdit);
 } 
}

If the typo gods favor you, then you should be able to use F5 to run the page and see it all working together:

Notice the positioning of the input textboxes, and the interaction of them with the underlying Silverlight canvas. This is just a simple example, but can be a very powerful way to "plug in" Silverlight into the surrounding DHTML.

Thursday, June 14, 2007 4:25:05 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Wednesday, May 23, 2007

Understanding what it means to "hit the curve"

The past few months I have been diving deeper and deeper into the two main pillars of .NET 3.0 - WPF and WCF. This post by Karsten Januszewski, although a year old, totally resonates even today.

I always laugh a little (on the inside) when I hear "senior" developers claim how all the difficult "real" work is to be found in back-end services and components. They assert that all UI development is easy, and doesn't even require much developer skill. Nothing could be further from the truth, and the new UI framwork (WPF) makes this glaringly obvious.

Basic concepts can be difficult to grasp like the layout system - where controls get to "vote" on their size and position, but it is really up to their container to make the decision. Another one that is hard to get a handle on - control templates and data templates... very powerful indeed, but a completely new approach to build an interface. Or just the whole concept of resources and style resolution. It feels a little bit like CSS... until you realize that nothing really cascades, it only overrides.

Now, don't misinterpret this as a bash towards WPF... I really feel the complexity and learning curve are warranted, and that the platform is above and beyond anything that was available before. But XAML is HARD until you get the swing of it, and don't let anyone try to convince you otherwise.

.NET | WPF
Wednesday, May 23, 2007 1:56:33 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [2] | 

# Sunday, May 06, 2007

Atlanta Cutting Edge .NET - May 2007

Tomorrow night is the Atlanta Cutting Edge .NET User Group meeting for May. Actually, it's also the May meeting for the Atlanta MS Pros and VB.NET groups as well. We will all be sharing the facility and sponsorship, as well as having a combined networking period before the meeting and a combined "keynote" presentation for the first half hour. After that, we will split up into 3 rooms (well technically, we will probably just close the walls and divide the main room into individual sections), each of which will offer a seperate track of material. We have a track for Cutting Edge, one for VB.NET, and one for MS Pros.

For more details, including the topics and speakers that are scheduled, please refer to the user group website at http://www.atlantace.com/

.NET | Events | General
Sunday, May 06, 2007 8:30:37 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Monday, April 30, 2007

A storm is brewing

It has been a good while since this industry has had a significant shake-up, where the world as we know it changes almost overnight, and our skills and practices are all made obsolete. We generally seem to have one every few years or so, and according to my calculations, it has been about 7 or 8 years since the last one.

I am sure there were other events, but the first I can recall was the introduction of Object Oriented programming in the 80's. This paradigm shift left multitudes of mainframe COBOL and RPG analysts behind, forever to toil in a world of green on black terminal displays. Then in the early and mid 90's there was an explosion of "client-server" and "N-Tier" applications in the business world. These were all the rage, and again the flock was divided. Many OOP purists were left in the dust, trying to fend off the "younger kids" that embraced the 3GL and 4GL tools of the day. But as luck would have it, only a few years later the terms "client-server" and "N-Tier" took a back seat to the newest technology explosion - the age of the Web. Right or Wrong, everyone wanted to be on the web. Try as they might, the n-tier supporters could not withstand this assault. To this day, there remains a contingent of developers that cling to the world before the web - in the Microsoft kingdom, we call them "Windows Forms Programmers", or perhaps the slightly more dignified "Smart Client Developers". But the significant majority of development work admittedly goes into Web applications.

So for the last few generations of the industry, roughly every five to seven years, we experienced a wholesale disruption in the status quo. Things are no longer what we thought they were. Skills become unmarketable. Management becomes confused. Projects get scrapped. We have to retool - retool or else go the way of the Do-Do Bird (extinct).

The only problem is - it has been about eight years now since the last paradigm shift (I do not count .NET as a paradigm shift - it is simply a consolidation and improvement on ideas and methods already in place). It has been eight years, and I fear that we are long overdue. More than that though - I feel that perhaps, just perhaps, the paradigm shift has already begun - and that I can't see it due to my own Myopia. And what if the shift has already passed me by, and I have missed it entirely?

In conclusion, I think the shift is just now underway. I have smelled the crispness in the air that precedes a thunderstorm. I think the industry is about to change again, in a very significant way, and I hope to be a small part of it yet again. But in order to accept and participate in a significant change, a person must adapt to the new way of things. To that end I have begun the arduous task of retooling and rebranding myself. This will not be the first time, nor likely the last. As a as/400 specialist, converted to PC technician, converted to Delphi developer, converted to DBA, converted to Web Developer, and finally to .NET windows/web developer, I can say that I have definately been through this process before, and it does not scare me. What scares me is the thought of not adapting.

Some of the people I know and trust feel that they too have "seen the light". Some have their own theories about where to be when the music stops playing. My good friend Scooter seems to think that Sharepoint is the entire future. I don't necessarily agree with that. I have heard similar theories about the grand direction of things from others as well ("Linux is the future!", "Everything will be AJAX!", "OMGZ It's all going to Pocket PC format!") - most of which I cannot find reason with either. Everyone seems to agree that the winds are changing, only nobody appears to agree on the direction. But I have my own ideas and theories and will once again be betting the next half-decade or longer of my career on that insight. It hasn't let me down in the past - I trust it will not let me down this time either.

.NET | General | Silverlight | Web 2.0 | WPF
Monday, April 30, 2007 4:29:00 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [2] | 

# Monday, April 16, 2007

WPF/E Gets a Name

Soma tells us that WPF/E has finally recieved a more inspiring name. The announcement was made at the National Association of Broadcasters (NAB) conference in Vegas.

What's the new name? Silverlight. They even have a slick logo for it:

You can also see how it stacks up against Flash here.

.NET | Silverlight | Web 2.0 | WPF
Monday, April 16, 2007 3:09:06 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Wednesday, April 04, 2007

Expression tools for MSDN Subscribers and Partners

Today I was on MSDN Subscriber Downloads to pull down an ISO that I needed. First I noticed this in the Partner VLA Keys section:

Then I noticed the new download in the downloads area:

Then I checked my RSS Reader and saw these posts by Somasegar, Walt, Tim, and Forest.

To make a long story short, Expression Web is now available to folks with MSDN Premium subscriptions, and Expression Blend will be available upon release. If you have one of the flavors of VS Team Suite w/ MSDN Premium then you will also have access to the full Expression Suite (I think this includes Expression Design and Expression Media?).

And while it was not reported on any of the above blogs, I assume that Certified and Gold level Microsoft Partners will also be granted a certain number of licenses for internal use - since I currently see it listed in that section.

This is great news for WPF fans. Tool availability is one of the biggest things holding back adoption of Fx 3.5, and this move to make Expression tools available to MSDN subscribers (without jacking up the price ala TFS) will help smooth the transition.

.NET | General | WPF
Wednesday, April 04, 2007 6:45:43 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Friday, March 30, 2007

Alabama .NET Code Camp

In case you missed the highly successful Atlanta Code Camp, there is another one coming up in Mobile, Alabame on April 14th. Registration is currently open, and I do not think they are sold out (yet). Like always, this Code Camp is a free event and it is jam-packed with lots of great topics being delivered by great speakers.

If you are anywheres near Mobile that weekend, it would be worth signing up for.

http://www.alabamacodecamp.com/

.NET | Events | General
Friday, March 30, 2007 8:56:22 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Monday, March 05, 2007

Longest Posts EVAR

I catch a lot of crap from my peers about the length of my posts and their apparent lack of reasonable brevity. Well complain no more, because my pal Dan has totally jumped the shark with his pair of matching Longest Posts Evar:

 

Office SharePoint Server 2007 - Forms Based Authentication (FBA) Walk-through - Part 1

and the sequel to the bestselling novel:

Office SharePoint Server 2007 - Forms Based Authentication (FBA) w/MySites Walk-through - Part 2

 

Heck, even the titles are huge.

Monday, March 05, 2007 2:12:22 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Saturday, March 03, 2007

Atlanta Cutting Edge .NET User Group Meeting - Monday March 5th

Please join us on Monday, March 5th at 6:00 PM for the monthly Atlanta Cutting Edge .NET User Group meeting.

**************************************

This month we have two speakers:

Paul Lockwood will be presenting Semi-Advanced Production Debugging - a brief discussion on little known debugging techniques including WinDbg and the sos.dll.

About the speaker:

Paul maintains a weblog at http://www.dotnetworkaholic.com/.

Also speaking this month is Eric Engler who will be presenting ASP.NET AJAX: Beyond the UpdatePanel. This session will provide an overview of ASP.NET AJAX. Eric will briefly cover the basics of ASP.NET AJAX, and then he'll drill down on some of the less commonly known, but very powerful aspects. Among the subjects to be discussed will be:

  • The parts of the AJAX Distribution
  • UpdatePanel - a brief obligatory overview
  • The ScriptManager
  • AJAX Control Toolkit: design of server-side control extenders and custom controls
  • JavaScript: how to use objects in a non-OOP language
  • AJAX Client Library: micro sized version of the .NET Framework written in JavaScript
  • ASP.NET AJAX Application Services
  • Calling Web Services from the Client
  • Debugging AJAX applications

About the speaker:

Eric is a Senior Software Engineer at ZC Sterling, a real estate insurance and tax servicing company in Atlanta. He has over 20 years of experience programming many languages, on many platforms. His current focus is on Visual Studio and C#, including all types of applications: Windows, Web, and middle-tier. He holds a MCSD.NET certification.

Website: http://www.EricEngler.com

Thanks go to our sponsor Intellinet (www.intellinet.com) for graciously providing refreshments during the meeting.

This month's agenda (Monday, March 5th)

    * Networking starting at 6:00
    * Announcements at 6:15
    * Paul Lockwood – Production Debugging at 6:30
    * Break at 7:00
    * Eric Engler – ASP.NET AJAX at 7:15

We will be meeting at the Microsoft Regional Headquarters at the Sanctuary Park complex in Alpharetta (Mansell Rd. Exit). The meeting begins at 6 PM so folks can mingle, however the announcements and presentations are not scheduled to begin until 6:15 PM.

For more information on this month's meeting, please visit our website at:

http://www.atlantace.com/

If you are not familiar with the meeting location, please print out the driving directions for reference:

http://www.atlantace.com/MeetingLocation.aspx

**** A CALL FOR SPEAKERS ****

If you have a topic that you would like to present to the group, please contact me to discuss your ideas. We have lots of available time slots in the coming months, and our group is a fantastic place to hone your public speaking skills and to contribute back to the user group community.

*****************************************

NOTE: You have received this message because your email address was registered at the Atlanta Cutting Edge .NET website at http://www.atlantace.com/ or the Atlanta C# Developers Group website at http://www.atlantacsharp.org/.

*****************************************

Thanks, and I hope to see everyone at this month's meeting!

Keith Rome
MCPD-EAD MCSD MCDBA MCAD

.NET | Events | General
Saturday, March 03, 2007 2:45:10 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Wednesday, February 21, 2007

New Job

For those who know me well, this will be old news.

As of last Monday, I have been a consultant with Wintellect. This new position gives me the opportunity to "get in early" and help shape a consulting organization from the ground up. I will also get to continue building my technical and management skills and perhaps have a chance to get in on some more exciting projects that leverage the newest technologies.

My two years at Intellinet were a great employment experience, and I would definately recommend them to prospective employees and clients without hesitation. I still have many good friends there. Frank Bell and the Intellinet EMT have managed to build a great working environment, and they have some of the best technical specialists in the region. I wish them the very best, as it was a very difficult decision when I decided to move on to this next phase of my career.

Wednesday, February 21, 2007 10:11:56 AM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Thursday, February 08, 2007

Project Planning Basics

At this month's Atlanta Cutting Edge, I presented a short talk on basic project management and estimation using PERT techniques. This is a topic that I find most developers (and managers too!) tend to ignore because they assume it woul dbe uninteresting or perhaps "fake science". Quite the opposite is actually true, and it can be astounding how much positive impact some of these techniques can bring to a software development project.

So if you were there and requested the slides, or if you were simply not able to make it, here they are.

.NET | Events | General
Thursday, February 08, 2007 9:08:08 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Tuesday, January 09, 2007

Adventures in Databinding ~ Part 2 ~ Simple versus Complex Binding

Databinding in .NET is immensely powerful. You can bind nearly any property of any object to any property of any control. The source object can be any .NET object - a business component, a DataSet, a built-in .NET class, or even another Control! Of course like any powerful feature, the Devil is in the Details.

Simple versus Complex Binding

To understand the databinding system first requires acknowledgement that there is in fact two "flavors" of databinding. You can bind to two very different categories of objects, and this is what differentiates the flavors of binding. The two flavors are called Simple and Complex binding. This is somewhat of a misnomer in my opinion as there is nothing inherently more complicated about Complex binding - it's just different. I would prefer to call these two forms of binding Item and List binding, as that more accurately describes their use. In fact, I will try to refer to them as such throughout these posts.

Item Binding

Item Binding refers to the connection of a source object property value to a target control's bindable property. These connections are typically two-way, in other words you can change either side of the connection and the databinding system will push the change to the other side. Another cool aspect is that you can bind many controls to the same source property - however you cannot bind a control's property to more than one source. An example of this would be binding the Text property of a Label control to the FirstName string property of a Customer object.

List Binding

List Binding refers to the connection of a source list of objects to a target control that is capable of display and/or navigating between multiple items in the list. The source list can be any .NET object that implements IList, ICollection, IEnumerable or IBindingList, including arrays, collections, generic lists, and DataTables. In more advanced scenarios, an object that implements IListSource can also be used - IListSource simply defines a list of lists. Controls that are able to participate in List Binding include the ubiquitous DataGrid/DataGridView, and many other controls that consume lists of items for various reasons - DropDowns, ListBoxes, and TreeViews to name a few.

Mixing and Matching

Unfortunately, you usually cannot mix (or should not mix) both Item and List Binding in the same source objects. Due to the way the databinding system discovers and uses databinding interfaces (will be discussed in a followup topic), it is not possible to have both Item and List bindings on the same object. An example of this would be binding to Customer entries in a list as well as the Count property of the list itself.

Examples

Item Binding Examples

When creating Item Binding connections, you always begin with the target control, and add to its DataBindings collection a list of property names and their sources. DataBindings.Add() is an overloaded method with two main usage scenarios. Most of the time you will use the form of Add(PropertyName, DataSource, SourcePropertyName). In more rare situations you might want to create a Binding object directly and and use the form Add(Binding)... this can be useful when you want to override default formatting and parsing of values.

  • Binding to a property of a business object

Customer C = new Customer("John");

TextBox TextBox1 = new TextBox();

TextBox1.DataBindings.Add("Text", C, "FirstName");

-or-

Binding B = new Binding("Text", C, "FirstName");

TextBox1.DataBindings.Add(B);

  • Binding to a public field of a business object

You can't do it in this version of the framework!

  • Binding to a field in a DataTable

DataTable CustomerDT = new DataTable("Customers");

CustomerDT.Columns.Add("FirstName", typeof(string));

CustomerDT.Rows.Add(new object[1] {"John"});

TextBox TextBox1 = new TextBox();

TextBox1.DataBindings.Add("Text", CustomerDT, "FirstName");

  • Binding multiple controls to the same source data

CheckBox CheckBox1 = new CheckBox();

TextBox TextBox1 = new TextBox();

TextBox1.DataBindings.Add("Enabled", CheckBox1, "Checked");

List Binding Examples
  • Binding a grid to a DataTable

DataSet CustomerDS = new DataSet();

DataTable CustomerDT = CustomerDS.Tables.Add("Customers");

CustomerDT.Columns.Add("FirstName", typeof(string));

DataGrid CustomerGrid = new DataGrid();

CustomerGrid.DataSource = CustomerDT;

Note that the following can also replace the above DataSource assignment:

CustomerGrid.DataMember = "Customers";

CustomerGrid.DataSource = CustomerDS;

However, it is very important to realize that while on the surface they may appear to give identical results, these datasource assignments are not the same! I will explain this further in part 6 of this series.

  • Binding a ComboBox to an array

string[] StatusList = new string[2] {"Active", "Canceled", "Completed"};

ComboBox CurrentStatus = new ComboBox();

CurrentStatus.DataSource = StatusList;

Note that with a ComboBox, the List Binding is what is used to supply the list of possible values displayed when activating the control.

  • Binding a ListBox to a Business Object Collection

List<Customer> CustomerList = new List<Customer>;

CustomerList.Add(new Customer("John"));

CustomerList.Add(new Customer("Mary"));

ComboBox CustomerSelection = new ComboBox();

CustomerSelection.DisplayMember = "FirstName";

CustomerSelection.ValueMember = "CustomerID";

CustomerSelection.DataSource = CustomerList;

Note that ListBox controls, like ComboBox controls, use a List Binding to supply values for the range pf possible values. They both can also use an Item Binding to connect the actual currently selected value to a data source object.

To Be Continued...

Tuesday, January 09, 2007 12:21:26 AM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [2] | 

# Sunday, January 07, 2007

Adventures in Databinding

Why would I care about Databinding?

Perhaps you are just writing some server code. Maybe XML processing, web services, or even some good old-fashioned application server components. If so, then maybe you really shouldn't care about Databinding.

But maybe - just maybe - you are building the User Interface for an application. Or perhaps a set of business objects that will eventually be displayed in a User Interface. And maybe, just maybe, that interface happens to live in the world we now call "Smart Clients". If so, then three paths will lay before you:

  1. You can pretend that databinding does not exist and manually update/read data values directly from UI controls.
  2. You can try to ignore the intricacies inherent to databinding and hope that everything works out (might be OK if nothing in your UI is "outside of the box").
  3. You could embrace the beast that is .NET Databinding, study and plot against your foe, and finally prevail against that poorly documented adversary which has terrorized legions of .NET developers.

OK, well maybe it's not quite that exciting, but there is definitely some interesting (I think) stuff to be learned when you take a deeper dive into the world of .NET Databinding.

In a series of topics I hope to shed some light on this dark and often cursed part of the .NET infrastructure. In my past few years of .NET experience I have had to tackle databinding from many angles, and have managed to develop a fairly good grasp of the subject (I think - ...always more to be learned). Hopefully I can share some of that with readers. So let's see where this goes...

Sunday, January 07, 2007 3:52:55 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [2] | 

# Friday, January 05, 2007

Crawling back out of my cave

For nearly a year I have been bogged down in what I can only describe as a quagmire of a project. But this week that all changes - I am moving on to some new work finally, and maybe - just perhaps - I will have more time to blog about the things I have learned and re-learned during that time...

Friday, January 05, 2007 4:22:26 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

2007 Atlanta Code Camp - Registration is OPEN

As announced earlier today by Jim Wooley:

 

 

Fellow Code Campers,

I hope you all had a wonderful holiday season and I want to wish everyone a Happy New Year.

Registration for the 3rd annual Atlanta Code Camp is now open. Please register on the Click to Attend website to guarantee your spot at the Code Camp.

Here's the link:
https://www.clicktoattend.com/invitation.aspx?code=113135

Just a reminder. The 3rd annual Atlanta Code Camp will take place on January 20th. The event is completely free and lunch is included. Doors open at 7:30am at the Decatur campus of DeVry University

250 North Arcadia Ave
Decatur , GA 30030

If you are coming in from out of town, we have a recommended hotel near the event. Call the Holiday Inn and ask for the DeVry University rate to get a $99/night rate. Parking is extra and costs $7/day

Holiday Inn

130 Clairemont Ave
Decatur, GA 30030
404-372-0204

During the Code Camp, lunch will be provided at no cost to you. After the event, we are planning on gathering in a local eatery to continue any discussions which we were not able to complete by our 5:30 pm end time. Location information will be made available at the event.

The Atlanta Code Camps have historically "sold out" extremely rapidly and we don't expect this time to be any different. Please register quickly to lock in your spot as we are capping registration and attendance due to facility limitations.

.NET | Events | General
Friday, January 05, 2007 3:55:47 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Tuesday, November 14, 2006

Microsoft Lunch and Learn

Join Doug Turnure and guests on the third Monday of every month at the Microsoft regional headquarters in Alpharetta for a "Lunch and Learn" event.

These events are 1 hour in length, held from noon to 1pm. Lunch is not provided - you will need to bring your own if you wish to eat. The content itself is level 100 to 200.

This month, the topic is WPF and Cardspace. Visit Doug's weblog for more information if you are interested... Lunch and Learns at Microsoft

.NET | Events | General
Tuesday, November 14, 2006 9:54:58 AM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [1] | 

# Saturday, November 11, 2006

MCPD - EAD

I am very pleased. Today I took the second of two upgrade tests needed to convert my existing MCSD certification to the new MCPD-EAD (MS Certified Professional Developer - Enterprise Application Developer) - and passed it by a comfortable margin! I am fairly sure this makes me the first Intellinet consultant to carry this new certification.

The test itself was pretty tough - I am very lucky to have had enough exposure to deep WSE and Remoting. A good 20 of the 58 questions were directly related to WSE3 implementation details - and quite picky too. SOAP Filters, policy, addressing, referral cache, signing/encryption, etc... this test hit nearly everything. For remoting, the test covered client and server declarative as well as imperative configuration of the channels and services/clients. There were even a significant number of questions on message queueing and serviced components. In all, I am quite impressed with the depth and breadth of testing coverage.

I actually wanted to take this test a few months ago (I took part 1 while the tests were still in "beta"), but I was holding out to see if my employer was going to institute a reward policy for obtaining certifications - something that many of our competitors do. I finally just gave up on waiting and scheduled the test before my free test voucher expired. Intellinet would have paid for the test - but free is free.

Now I just need to decide whether I want to pursue updating of my MCDBA credentials...

Saturday, November 11, 2006 10:31:29 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Tuesday, September 05, 2006

Atlanta Cutting Edge .NET - September 2006

Tonight is the September meeting for the Atlanta Cutting Edge .NET User Group. Jim Wooley (RSS ) will be presenting on LINQ - the new language integrated query extension technology. This is really cool stuff IMO.

Normally we meet on the first Monday of every month, but with yesterday being a holiday, we moved this month's meeting to tonight.

In case you don't have it yet - our new User Group's URL is http://www.atlantace.com/.

.NET | Events | General
Tuesday, September 05, 2006 9:47:33 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [2] | 

# Wednesday, May 31, 2006

CANCELLED: Atlanta C# User Group Meeting for June 2006

Just in case you happen to monitor this weblog, but have not registered with the group's mailing list:

------------------------------------

Please be aware that due to inability to secure a speaker for this month, the Atlanta C# User Group will NOT be meeting in June.

Also, the July meeting would fall adjacent to the Independance Day holiday, and therefore there will not be a C# Meeting in July either.

Our next scheduled meeting is currently expected for August, more details will be posted when we get nearer to the meeting date.


**** A CALL FOR SPEAKERS ****

If you have a topic that you would like to present to the group, please contact me to discuss your ideas. We have lots of available time slots in the coming months, and our group is a fantastic place to hone your public speaking skills and to contribute back to the user group community.


**** SPONSORS ****

If your company is interested in sponsoring a month (or more) of the Atlanta C# Developers Group, please contact me to discuss. Sponsorship is inexpensive and a great way to market your organization.


*****************************************

NOTE: You have received this message because your email address was registered at the Atlanta C# Developers Group website at
http://www.atlantacsharp.org/ .

*****************************************

 

Keith Rome
MCSD MCDBA MCAD

.NET | Events | General
Wednesday, May 31, 2006 10:00:16 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Sunday, April 30, 2006

2006 Atlanta Code Camp

In case you haven't heard, the 2006 Atlanta Code Camp site has now begun accepting registrations. This year promises to be even more successful than last, we have nearly thirty topic submissions, so many in fact that we will not be able to accept them all due to the realities of physical meeting space and event logistics.

We are planning on 5 different topic tracks, so there should be a little bit of something for everyone.

You can now register for the Atlanta Code Camp by clicking on the registration link on http://www.atlantacodecamp.com/ or go directly to the registration site at https://www.clicktoattend.com/invitation.aspx?code=108776.

 

.NET | Events | General
Sunday, April 30, 2006 11:48:09 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [3] | 

# Tuesday, February 28, 2006

Unit testing and Test Driven Development

Paul Lockwood gave an interesting presentation last night to the .NET UG on TDD. I will admit that haven't integrated this methodology deeply into my own development habits (yet). I do however recognize the benefits, and fully intend to incorporate it into my habits, just taking things one step at a time as I push my own skills to ever higher levels. So to me, the discussion was quite timely.


Listening to audience feedback, it appears that a number of folks (Rusty, Marcie, etc) are already leveraging this technique... and have some really positive opinions of it. When smart people are recommending something with such enthusiasm, it is generally a wise thing to pay attention.

One thing I would have liked to have seen is an end-to-end example of the process itself. I have seen unit tests before, I have even used NUnit on a few projects, but never to much success. I always felt like I was "not getting it". I get the impression (mainly from Rusty's comments), that this is normal, and there is a point of critical mass, serendipity if you will, where it all just starts to "make sense", and your Unit Tests become the first-class citizens that they deserve to be. I want to reach that point, but am shooting blind right now... a slight nudge towards that light is really what I need I think.

My current development habits have served me well (I have been told on more than one occasion that I am the most meticulous developer ever to pick up a keyboard), but I wish to push it to the next level. Zero defects in QA Iteration 1 is the Holy Grail. So now I at least have an idea of what I need to work towards. The next step is finding the best path to get there.

.NET | Events | General
Tuesday, February 28, 2006 7:11:32 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [4] | 

# Tuesday, February 21, 2006

Atlanta MS Professionals UG

Last night, the Atlanta MS Professionals User Group was treated to an outstanding presentation by one of the great gurus of Windows programming - Jeffrey Richter of Wintellect. His coverage of the internals of CLR thread termination and associated concerns was extremely enlightening. I would rank this talk as easily being in the top 5 presentations I have ever had the opportunity to attend (and I have seen a LOT in recent years).

Anyways, Jeffrey has a new book coming out in March ("CLR Via C#: Applied Microsoft .Net Framework 2.0 Programming"), which he claims will be his last. I made sure to pre-order a copy ($50!) so I can divine some of his wisdom and insight.

 

.NET | Events | General
Tuesday, February 21, 2006 1:30:46 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Monday, January 30, 2006

Adding a Google or MSDN2 search to VS2005

Rik explains how to use a Visual Studio macro to search for highlited text using Google (or alternatively from MSDN2 online) directly from within the IDE... its a pretty cool trick.

Which reminds me - Rik R has been a friend of mine for a few years now (a former coworker from 2001/2002), we were building highly interactive websites years ago using javascript, xml, and XmlHttpRequest. Today, we would call such a system a "Web 2.0 AJAX site". But back then, it was seen as heretical - since postbacks were the status quo. Anyways... I finally talked him into blogging... you can catch the feed at www.r2musings.com as he writes about his journey in the land of .NET

Speaking of new bloggers.... I also convinced Dan Attis to pick up the habit not too long ago... and as you can tell from the activity on his weblog, he is quite the prolific writer!

 

Monday, January 30, 2006 3:52:21 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [0] | 

# Thursday, January 05, 2006

PageFlakes

I came across this site tonight... it is another ajax framework with some interesting stuff going on behind the scenes. This approach really lowers the entry bar for building simple ajax-driven portlets (it can literally suck in a functional page and inject the content into a new web part / portlet)... a nice and simple approach.

Check it out at http://www.pageflakes.com/

They are also claiming to be giving away an xBox 360 in a "flake building" contest through february.

Thursday, January 05, 2006 1:56:28 AM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [1] | 

# Tuesday, December 06, 2005

Interested in AJAX?

I have been following this blog for a while now - it is quite active and has great timely information on AJAX technologies (not just .NET either - they talk about anything ajax):

 

http://www.ajaxian.com/

.

Tuesday, December 06, 2005 12:46:48 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [2] | 

# Sunday, December 04, 2005

Weird HTTP header issue in Internet Explorer 6

I recently needed to implement an HttpHandler in a project to handle retrieval of rendered PDF reports from a database. It shouldn't have been a big deal, very few lines of code, even less than typical since my Business Logic Layer encapsulates all of the aspects of the data retrieval itself into a single line of code... my handler only had to set the ContentType, add a couple of headers (Content-Length and Content-Disposition), and then BinaryWrite() the data. Easy as pie, or so I thought.

The file streamed fine out of the database - no surprises there. Content-Length had no issue and once I remembered to install Acrobat Reader into my VPC where I was testing this, then the ContentType of "application/pdf" worked as well.

But try as I might, I could not seem to get that darn Content-Disposition to be recognized by Internet Explorer! Every time I tested it, the "Save" dialog would always display a random file name, instead of the one I supplied in the header.

I double-checked, then triple-checked my code. I had two other web developers look at the code, and give it a thumbs-up. I even resorted to tracing the HTTP protocol traffic just to be 100% certain that IE was getting the HTTP header. Sure enough, the header was being set and IE was seeing it. But it wasnt obeying it.

It turns out there seems to be a maximum length to the filename you can supply using the attachment notation of the Content-Disposition header. And my filename was in excess of that limit, causing it to be ignored by IE. While I am not sure what the exact limit is (or if it is some other kind of esoteric bug in IE), and do not have time to experiment and discover that limit, simply reducing the length of my attachment filename has resolved the issue.

By the way, the length of the filename causing a problem was only something like 40 to 50 characters, which really isn't unrealistic. I was embedding the report execution date/time (in a string format that is valid in a file name), in order to prevent saved reports from being overwritten.

Sunday, December 04, 2005 10:55:51 PM (Eastern Standard Time, UTC-05:00) #  Disclaimer | Comments [2] | 

# Thursday, November 03, 2005

A peek into the future of managed OS's

The folks at Microsoft Research have been working on a "research" operating system they call Singularity.

So what's so cool about this?

Singularity turns current preconceptions of operating systems upside-down. 95% of the microkernel is written in a variant of C# called Sing# (the rest is assembly and C). They use a native compiler to turn that MSIL into real bytecode. So there isn't a "CLR", at least not in the kernel.

The concepts of Processes, Threads, Drivers, and Communications is totally up-ended as well. Everything in Singularity runs in a "SIP" (software isolated process)... applications, services, even drivers. These SIPs all run close to the metal in ring-0, cannot reference memory addresses in the kernel or any other SIP, and are required to be verifiably safe. SIPs are only allowed to communicate with each other via something called the "ExchangeHeap", and then only by tight message/protocol contracts. A side effect of the way they forced the strong-typed "owned messages" is that certain data transfers that were traditionally heavy on bitcopies are now zero-copy operations. They also defined some S# language extensions to define these message patterns - it's pretty slick stuff really.

You can read the entire project overview whitepaper to find out all the other cool stuff they managed to do in this Concept OS.

I read the paper, and was totally expecting the cost of executing everything in isolated SIPs to be a performance dog. I was shocked to see that in actuality, the performance was equivalent (or in some cases phenomenally better) than other *tweaked* modern operating systems.

Anyways, this is some cool research. I suspect parts of this work will wind up in future OS products - I recall the CLR team was reluctant to discuss the ideas of "hardware CLR" - perhaps they are further along in that regard than they are leading people to believe...

 

Thursday, November 03, 2005 8:08:21 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Tuesday, November 01, 2005

Much h8 for VB

Who in the hell at Microsoft came up with the briliiant idea of 1-based arrays? And why oh why didn't they discard that abomination when transitioning from VB6 to VB.NET?

Of all the stupid VB quirks - THAT one has caused me unending grief.

VB is supposed to be INTUITIVE, but I am sorry... if I DIM or REDIM an array, asking for ZERO elements, I damn well expect that array to hold ZERO elements afterwards. Not one NULL element!

Arghh!!!

Tuesday, November 01, 2005 10:39:57 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

# Friday, October 21, 2005

VMWare Player

I saw this come across on slashdot this morning...

It seems VMWare has a new free "player" product. It appears to be the same as vmware 5 workstation, except that you cannot create new virtual machines or add hardware to existing ones - you can only use machines created using one of the full-featured versions (Wkstn/GSX/ESX). Aside from that, it's supposed to be fully-functional.

And it claims to support Virtual PC / Virtual Server images as well.

And thats pretty cool, since vmware has always been a better virtualization product than VPC. The only reason most shops use VPC right now is because it comes with MSDN subscriptions.

Friday, October 21, 2005 2:42:21 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Monday, October 17, 2005

C# UG Presentation: Engineering an Application Foundation using Code Generation

This was a presentation I gave earlier this month (October 2005) to the Atlanta C# Developer Group.

Code generation is one of those "cool" techniques in software development where you just don't know what you have been missing until you see it in action... and then once exposed to it, you find yourself wondering "how did I ever get along without this?".

In this presentation, I discussed the reasons and benefits of using code generation tools, and the problems they can solve (or avoid entirely). I focused on the benefits of consistent code, building upon a solid foundation, and simplification of complex application features.

We designed and built the code for a basic application foundation, supporting simple features such as lightweight enforced transactions, entity persistence, and other baseline features. Then a series of linked templates were created that take advantage of that code foundation. Finally, we built an example UI that leverages the generated middleware to dramatically simplify and streamline the actual development process. It was pretty durn cool IMO.

All templates were built using CodeSmith, which is a fantastically useful tool. I feel like I might have been giving a sales pitch for that product by showing off many of the way too cool features of the new version of CodeSmith, but it's one of those things I strongly feel is worth every penny.

The powerpoint slide deck and all relevant source code can be downloaded from the presentation archive of the Atlanta C# Developer's Group website at: http://www.atlantacsharp.org/PresentationArchive.aspx

 

Monday, October 17, 2005 2:55:57 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [3] | 

C# UG Presentation: Custom Exceptions

I actually gave this short presentation to the Atlanta C# Developer Group back in September, but never got around to blogging about it...

The presentation covered why you should be using custom exception classes in your own code, and how to structure your exception class inheritance to gain the most benefit. It showed working examples of the concepts. It also touched on a few related practices such as only catching exceptions that you can deal with, and designing a meaningful exception taxonomy.

The slides and source code can be downloaded from the Atlanta C# Developer Group's presentation archive at: http://www.atlantacsharp.org/PresentationArchive.aspx

 

Monday, October 17, 2005 2:41:25 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Monday, October 10, 2005

More FREE Sharepoint Training!

The third installation of the Sharepoint 1, 2, 3! training series is next Monday and Tuesday. This session goes deeper into the capabilities of SharePoint than our previous two sessions did. We will be covering advanced topics such as connectable web parts, Office integration, Document Library Events, Workflow Implementation, the SharePoint Object Model, and SharePoint Web Services!

We have thirteen detailed demos packed into this session, so this is definately tailored for folks who are comfortable writing code. Just like last month, attendees of the Hands-On Lab will also recieve a DVD containing the training materials loaded on a trial version of Windows Server 2003 (VPC image). This is a really cool take-away that allows you to share what you have learned with your cohorts back in the office. It also makes a great way to demonstrate the power of Sharepoint to that skeptical manager! We also expect to have Content CDs available that contain the presentation slides as well as the Hands-On Lab manual and code snippet files. All of this will be made available at the Hands-On Lab on Tuesday night (we are still debating on whether or not to offer the Content CDs after Monday night's seminar as well).

Our first two sessions were extremely popular, with fantastic positive comments from across the board. The Hands-On Lab for Tuesday night is already fully-booked, but it you show up with a laptop and are willing to be slightly inconvenienced we most likely will not turn you away (our training room is only designed to hold about 20 people, but as we proved at the first HOL session we can manage to fit up to about 40).

There is still room to sign up for the seminar on Monday night however. You can get more details and find a registration link on our main website at http://www.sharepoint123.com/. Just like the previous sessions, the coming Sharepoint sessions are FREE.

Like last month, Intellinet (our corporate sponsor) is providing refreshments and any giveaways. There will also be a number of Sharepoint experts from Intellet on hand to handle "sideline" discussions and to lend their expertise to the presentations.

.NET | Events | General
Monday, October 10, 2005 2:37:56 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Wednesday, September 28, 2005

WSS SP2 available now

So I guess this clears the way for biztalk 2006, team server 2005, and a few other things that require it...

Windows SharePoint Services Service Pack 2

 

Wednesday, September 28, 2005 2:02:23 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Sunday, September 18, 2005

SharePoint v3 video

There is a 24-minute video On "channel 9" that discusses the upcoming Sharepoint 2006 ("v3") release...

 

Sunday, September 18, 2005 10:57:59 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

# Friday, September 16, 2005

More on Sharepoint SP2

Rik asks:

"Keith, do you have a link to the details of SP2 of Sharepoint?"

Certainly!

Mike Fitzmaurice is talking a lot about it on his blog

Maurice Prather is also talking about it on his blog

I also dug up a little more about it to satisfy my own curiousity. Man they have got some COOL stuff coming down the pipe. I wish I was at PDC to attend these talks...

SP2:

  • Will support ASP 2.0, but only on WSS. SPS will not support this until v3 next year.
  • Apparently there is a new version of SmartPart that allows ASP 2.0 Web Part user controls to be hosted in WSS SP2.
  • Not much else being talked about that I have seen except bug fixes in SP2.

SPS/WSS "v3":

  • Due after Q2 of 2006.
  • Ghosting isn't such a big concern anymore. Why? Because v3 will allow you to use ASP 2.0 Master Pages, and Frontpage 12 will be able to work with it. Sweet!
  • You won't be limited to windows integrated authentication anymore. Why? Because v3 will support authentication providers from ASP 2.0! Extranet developers of the world rejoice!
  • All sharepoint lists can be exposed via RSS. Also some templates for Blogs and Wikis.
  • Huge improvements to Workflow support.
  • A document recycle bin.
  • Item-level security.
  • A new Business Data Catalog - you can define your line of business data and web parts can consume it. Sounds like an enterprise level data dictionary of sorts.
.NET | Events | General
Friday, September 16, 2005 3:15:00 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

# Thursday, September 15, 2005

Cool Sharepoint News

I am not at PDC, but thanks to the wonders of modern technology I am still able to get the scoop on some of the things being discussed. And there is some really cool things being announced. Things related to Sharepoint.

We can look forward in the near-term future to WSS SP2, which has some cool new features. Primarily, it will support .NET 2.0 web parts! Thats like TOTALLY Awsome! The downside? Portal Server will not support 2.0 until the next major release in 2006. I wish they would reconsider that descision, but in the meantime at least we can use 2.0 with WSS.

Another cool feature coming is the "Slide Library"... you upload a powerpoint slide deck and it breaks it apart into individual slides. You can then incorporate the slides into a new deck, but the slide remains linked to the first (I guess until you extract the deck into a .ppt file). How I WISH we had that feature while building the slide decks for the Sharepoint 1, 2, 3! sessions!!!

There were other cool things mentioned as well, but those two stuck out to me as too cool to forget.

 

.NET | Events | General
Thursday, September 15, 2005 6:04:52 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

FREE Sharepoint Training

The second installation of the Sharepoint 1, 2, 3! training series is next Monday and Tuesday. This session is aimed squarely at the developer who is interested in "cutting their teeth" in developing code that targets the Sharepoint environment. We will be covering basic Web Part development, debugging, and deployment. We will also be covering things more on the customization side, such as page and template customization. Really cool stuff!

If you attended the first session last month, you will recall that there was very little code to be seen. It was almost exclusively slides. This session will be very much different - we have a healthy number of demos lined up for the Level 200 topics. Just like last month, attendees of the Hands-On Lab will also recieve a DVD containing the training materials loaded on a trial version of Windows Server 2003 (VPC image). This is a really cool take-away that allows you to share what you have learned with your cohorts back in the office. It also makes a great way to demonstrate the power of Sharepoint to that skeptical manager!

Our first session was extremely popular, with fantastic positive comments from across the board. The Hands-On Lab for Tuesday night is already fully-booked, but it you show up with a laptop and are willing to be slightly inconvenienced we most likely will not turn you away (our training room is only designed to hold 20 people, but we had 45 at last month's HOL session).

There is still room to sign up for the seminar on Monday night however. You can get more details and find a registration link on our main website at http://www.sharepoint123.com/. Just like the first session, the coming Sharepoint sessions are FREE.

Like last month, Intellinet (our corporate sponsor) is providing refreshments and any giveaways. There will also be a number of Sharepoint experts from Intellet on hand to handle "sideline" discussions and to lend their expertise to the presentations.

 

.NET | Events | General
Thursday, September 15, 2005 5:43:04 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [2] | 

# Sunday, September 11, 2005

Good security article

Ever since Eric Marvets excellent presentation on applied security to our C# user group, I have had a renewed interest in architecture and development of [more] secure systems. So I ran across this interesting article today that I thought I would share...

(Not that it needs any more link-juice, it was slash-dotted)

The Six Dumbest Ideas in Computer Security

The main takeaway points: Secure by default is good, Rewarding those who participate in hacking activities is bad, relying on penetration tests is dumb, and user education is just not working.

 

Sunday, September 11, 2005 9:36:07 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Monday, August 22, 2005

Code Camps are everywhere!

It seems there is a code camp every other week now! I just got back from the Portal "Mini" Code Camp in Charlotte this weekend, and now I see that there are two more coming in the Southeast!

Jacksonville Code Camp on August 27th

and

Charleston Code Camp on September 17th

Both are looking pretty good.

 

.NET | Events | General
Monday, August 22, 2005 9:58:13 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [3] | 

First Sharepoint 123! training session a resounding success!

This post is about a week late, as we kicked off the first month of the Sharepoint 1, 2, 3! training series last monday night. Feedback has been overwhelmingly positive. With hardly any promotion (we were too busy working on the material), we still managed to draw about 65 for the seminar and 35 for the Hands-On Lab on tuesday. Early indications are that we will have far more than that at our level 200 and 300 sessions. I think we are already "sold out" on some of the future sessions.

There is LOTS of buzz circulating, which is a great feeling since the four of us (Matt, Brendon, Dan, and myself) have put a tremendous amount of work into it. The Hands-On Lab "experiment" went over especially well... it's not every day that you get to attend free training and take home a DVD with a running Virtual PC of the lab materials!

Intellinet has been an extremely supportive sponsor, and we are already working hard on making the next two months' sessions even better! There are some truly awesome ideas floating around right now centered on the work we are doing with the 1, 2, 3! Training series... so keep your eyes and ears open.

 

 

.NET | Events | General
Monday, August 22, 2005 9:52:30 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Wednesday, August 03, 2005

Designing a Service, Part 2

In my previous post, I talked about how to properly design a service. However, I did not give any real examples of it. All talk and no code. In this post, I hope to show how to actually do it.


Example: Hello, World!

Because you can never wear out an old example, and everyone already knows the Software Requirements Specification (SRS) for "Hello, World!".

Contract-First Design

Starting out, we need to first define the contract of the service that will be known as HelloWorldService. While I could demonstrate the purist's SOA approach by starting out with actual XSD schema, I will instead show what 9 out of 10 developers will be more comfortable with - a .NET interface contract.

HelloWorldService is a simple service, it's functionality is comprised of only one operation, "HelloWorld". HelloWorld accepts a single string input: "PersonName". It also returns a single string value: "GreetingText". With these requirements in mind, I will lay out the following interfaces and supporting class types:

namespace HelloWorld.Interface
{
    public class HelloWorldRequest
    {
        public string PersonName;
    }
    public class HelloWorldResponse
    {
        public string GreetingText;
    }
    public interface IDocHelloWorldService
    {
        // This is the document-centric design method
        HelloWorldResponse HelloWorld(HelloWorldRequest Request);
    }
    public interface IRpcHelloWorldService
    {
        // This is the Rpc-centric design method
        string HelloWorld(string PersonName);
    }
}

All of these definitions are placed in a single assembly, HelloWorld.Interface.dll. This part is important if you decide to provide a Remoting option, as this will function as the shared assembly (the equivalent to COM's type library and WebServices' WSDL).

Define Seperate Endpoints and Implementations

Here is where the rubber hits the road. The guts of the service will live in the Implementation assembly. Actual endpoints will live in their own assemblies, or web projects. I will start out by building the Implementation assembly, named HelloWorld.Implementation.dll, which contains the following code:

namespace HelloWorld.Implementation
{
    using HelloWorld.Interface;
    public class DocHelloWorld: MarshalByRefObject, IDocHelloWorldService
    {
        public HelloWorldResponse HelloWorld(HelloWorldRequest Request)
        {
            HelloWorldResponse Response = new HelloWorldResponse();
            Response.GreetingText = "Hello, " + Request.PersonName + "!";
            return Response;
        }
    }
    public class RpcHelloWorld: MarshalByRefObject, IRpcHelloWorldService
    {
        public string HelloWorld(string PersonName)
        {
            return "Hello, " + PersonName + "!";
        }
    }
}

Notice the difference in the amount of code needed to support each design method. Document-centric can require more code, but the trade-off is for increased control and flexibility.

Now, we can define endpoints.

The simplest "endpoint" is to merely add a direct reference to HelloWorld.Implementation.dll, and use the service classes directly. This will result in an in-process working instance, just like any other .NET object.

The next simplest endpoint is to configure the service as a Remotable object. You might have noticed that I chose to derive my implementation classes from MarshalByRefObject. This decision allows the Remoting system to expose my implementation classes as Remoting objects - objects that run in one process/machine, but are used in another process/machine transparently [almost] to the calling code.

I will not go into details of how to set up Remoting, Ingo Rammer does a MUCH better job than I could ever hope to in his book "Advanced .NET Remoting". In essence, you will need a remoting host (an IIS web application is the easiest), and you will need to add the web.config entries to expose IDocHelloWorld and IRpcHelloWorld as "well-known services". Note that you are exposing the interfaces here, and NOT the implementation objects... an important distinction. Then you simply dump the Interface and Implementation assemblies into the web's bin folder.

On the Remoting client side, you create a similar entry in the application's config file (alternatively, you can make calls in code to Remoting.Configuration to achieve the same effect). The client-side configuration causes .NET to channel requests for the service interface to be forwarded across the network to the target server. In your client application code, you simply use Activator.GetObject(typeof(IDocHelloWorld), "remoting url....") to request the remote instance. The framework takes care of the rest.

Finally, we can define a traditional Web Service endpoint. Since asmx is the simplest way to do this, we will use that technology in this example, although you could alternatively use WSE's non-asmx transport ability. We just create a plain-vanilla Web Service asmx in a web project (named DocHelloWorldWebService), and add a reference to HelloWorld.Interface.dll and HelloWorld.Implementation.dll. We modify the web service code like so:

public class DocHelloWorldWebService : System.Web.Services.WebService, IDocHelloWorld
{
    using HelloWorld.Interface;
    using HelloWorld.Implementation;
    /* .... IDE generated stuff .... */
    [WebMethod]
    public HelloWorldResponse HelloWorld(HelloWorldRequest request)
    {
        DocHelloWorld = new DocHelloWorld();
        return DocHelloWorld(request);
    }
}

We can also provide an RPC-centric version by adding a RpcHelloWorldWebService like this:

public class RpcHelloWorldWebService : System.Web.Services.WebService, IRpcHelloWorld
{
    using HelloWorld.Interface;
    using HelloWorld.Implementation;
    /* .... IDE generated stuff .... */
    [WebMethod]
    public string HelloWorld(string personName)
    {
        RpcHelloWorld = new RpcHelloWorld();
        return RpcHelloWorld(personName);
    }
}

Obviously, you would need to also do a few other things to complete the web service, such as giving a non-default namespace, etc.

Wrap-up

So, there you have it. An example of how to properly design a service in .NET. While not terribly difficult, it certainly is a totally new way of thinking about system design for many people. Hopefully this is of some benefit to you, who knows it might save you from a costly code refactoring when you suddenly have to support a new transport or service endpoint type.

In conclusion, I would also like to point out a few excellent resource books that are relevant to the subject:

"Advanced .NET Remoting", Ingo Rammer
"Expert Service-Oriented Architecture in C#", Jeffrey Hasan

Wednesday, August 03, 2005 6:39:11 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

Designing a Service, Part 1


Last week I hooked up with a few other smart guys after the Atlanta .NET User Group meeting. We were at the regular post-nerd-meeting hangout - Buffalo Wild Wings on Mansell Road.

We talked about a number of interesting topics, including AJAX/Atlas, Vista, and Indigo. At one point, someone questioned the validity of Remoting in light of WebServices, and wondered why anyone was using it now that is is supposedly on the way out. And my perspective was "why choose at all?". It is perfectly feasible and dare I say it "good practice" to design your system to support both. In fact, if you do things right, you will even be prepared for a smoother migration to Indigo or WSE.

So what is the secret trick to designing a service like this? Simple: it's called "contract-first design". Back in the days of COM, you might have known it as "interface-first".


Contract-First Service Design

The concept is surprisingly simple. A "service", whether it be a Web Service, system Service, or logical in-process service, can be defined as a unit of system functionality that operates independently of other units, and provides a well-known and concise interface. What this means is that no matter how complex a peice of functionality may be, it can be described in terms of some abstract interface. In Service nomenclature, this interface is called the "contract". The "contract" states the individual methods (operations) that a given service implements.

When we talk about Web Services, the "contract" is expressed as a WSDL document. When we talk about Remoting, this contract is expressed as compiled IL in a shared assembly. In COM, the contract was expressed in the Type Library. Indigo's name for this idea is by far the most explicit and clear, the "ServiceContract".

When you define a contract, you are declaring the exact functionality that a service MUST provide, and which a client MAY consume. The Service is not allowed (theoretically) to provide funtionality that exceeds or falls short of that contract, and the Client is not able to request any functionality that falls outside the scope of the contract. Furthermore, the contract also defines the specifics of HOW the functionality is to be addressed... for example, an operation requires a specific set of inputs, and will not respond (or should not) to inputs which are invalid or incomplete.

Therefore, a Service Contract ensures a consistent and predictable interaction between client and service.

So HOW do we go about designing a .NET solution in such a manner?

Plan ahead.

It is far easier to produce an adaptable architecture if you plan ahead for the adaptability. This means thinking about your interface before you think about the implementation.

At a minimum, start with defining your interface(s). You will need to define a seperate interface for each logical service. If you are a SOA purist, then this is where you bust out with the XSD editor and define your messages, operations, and portTypes. If you are not an SOA purist, then this is where you start laying out .NET interface definitions (yes, the language constructs that are defined with the "interface" keyword). Even if you are going the pure-SOA route, you will want to run the xsd.exe compiler against your schema to create some .NET stubs.... then change those from "class" to "interface" definitions. Either way, on the .NET side you want a set of interface definitions for the services, and class definitions for the complex structures.

And here you must make a choice. Do you want to (A) design a completely document-centric service, or (B) an rpc-centric service? If you want document-centric services, then you will want to create explicit types for every operation/method, one for the input and one for the output... even if the content is not complex. If you want RPC-centric services, then you can save a small amount of effort by only defining explicit types for cases where you wish to return or accept complex structures.

  Design Method A
    OperationAResponse = {complex type or simple type...}
    OperationARequest = {complex type or simple type...}
    OperationA = function(OperationARequest), returns OperationAResponse
  Design Method B
    OperationB = function(complex or simple type(s)), returns simple type or void

One word of warning: stay away from "ref" or "out" parameters if you choose to follow Design Method A.

One thing you might notice about Design Method A is that all operations will have a similar pattern, regardless of inputs and outputs. This is not coincidental. The Request and Response structures are what we call "documents" in a document-centric SOA (also called "message-centric"). There is great flexibility and power in a message-centric design.

Define Seperate Endpoints and Implementations

This is what fouls up most attempts at designing a good service. Having the contract pre-defined is not enough - you must also differentiate the service from the consumer. In the real world, your service will almost always be centralized, but the consumer(s) will be dispersed. This means that one (1) service may have multiple (N) endpoints. An endpoint is merely an identifiable address where the implemented service functionality can be found.

The problem is that most people do not distinguish between the endpoint and the implementation. They simple fire up a new asmx file and start dumping code into it. This is a BAD PRACTICE. The asmx is simply and endpoint, and should not be doing any work except passing the calls over to a real implementation. In other words, the asmx should be nothing more than a Facade.

A better approach is to implement the service itself in an external class... better yet, in an external assembly. This implementation class should implement the defined interface, just as you would implement any other .NET interface in a class. Then, you also implement that very same .NET interface in your asmx, however in the asmx you simply forward the calls to an instance of the external implementation class. Your Web Service methods become extremely simple shells that are marked up with the [WebMethod()] attribute and delegate the work to the external class. Very clean and tidy.

Once you have implemented your service like this, many more options become available. You get the flexibility to create new endpoints, possibly with differing authorization abilities (external facing ones might enforce WSE security, while internal ones might not). You also get the ability to very easily expose the service via other transports... such as Remoting. Either create a new endpoint object that derives from MarshalByRefObject, or make the service implementation itself derive from MBRO. Then you can add a entry to an application config file, and your service is now exposed via Remoting, with an identical interface to the web service! And finally, you enable the consumer of your service to simply reference it directly as an assembly, if that is desired for performance or security.

Wrap-up

That wraps it up for this (somewhat basic) discussion of how to design good services. My next post will follow up with a concrete example of this process.

In conclusion, I would also like to point out a few excellent resource books that are relevant to the subject:

"Advanced .NET Remoting", Ingo Rammer
"Expert Service-Oriented Architecture in C#", Jeffrey Hasan

 

Wednesday, August 03, 2005 6:26:59 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Tuesday, August 02, 2005

8/1 C# Users Group Meeting

If you missed this month's c# user group meeting, you definately missed out on some good information.

Chris Wallace started out by showing us the slick new profiling capabilities in VSTS 2005 for a few minutes. This will certainly be a handy set of tools available in VSTS.

Then Eric Marvets gave the main presentation on .NET Encryption. He did not show us a single line of code (there are plenty of examples on the web), but instead he felt it was more important to teach people how and [more importantly] when to apply or not apply particular cryptographic solutions. We all learned how Electronic Code Book ciphers and Chained Block ciphers work, their attack vectors, and in what situations they work best. We learned why when using CBC, you MUST ALWAYS generate a new Initialization Vector whenever the encrypted data is modified, and just exactly how that IV is used to make certain cryptographic solutions more secure. As a final tidbit of wisdom, we learned how DPAPI, while certainly an improvement over clear-text storage, is fundamentally no more secure than a good DACL.

8 out of 10 doctor's agree - The Atlanta C# Users Group lowers cholesterol while reducing hair loss and brightening your smile!*

 

 

* These statements have not been evaluated or approved by the FDA.

.NET | Events | General
Tuesday, August 02, 2005 9:58:56 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

# Saturday, July 30, 2005

FREE Sharepoint training - coming to Atlanta

For the past few months myself and a few other Local Developer Event Activists (hey, I like the sound of that title!) have been secretly working on some interesting new ideas.

Well, the proverbial cat is now out of the bag as we have opened up registration to the Sharepoint 1, 2, 3! series of events. These are a totally new concept in regional developer events. Inspired by the recent popularity of the many "Code Camp" events that have been popping up all over the east coast, we wondered "well, instead of a huge swathe of topics, how about we try delivering very tightly focused training events on hot but neglected subjects?". Well, Sharepoint is definately one of those HOT topics - just ask any recruiter these days, or surf over to Monster.com or ComputerJobs.com. EVERYONE wants to hire Sharepoint experts, but NOBODY is helping developers to learn those skills. Same thing goes for BizTalk, and various other hot technologies.

With these ideas in mind, myself, Matt Ranlett, Dan Attis, and Brendon Schwartz have teamed up and formed the Atlanta MS Professionals User Group. This "User Group" is unlike any other. We plan on providing high-quality training sessions to the community, with a 3-month focus on each technology. By concentrating on specific technology areas over several consecutive months, we feel that a superior level of learning and understanding can be accomplished. And this is how the Sharepoint 1, 2, 3! series came about.

So by now if you are still reading, you probably want to know what this is all about. You want details such as topic coverage, number of events and dates, target audiences, difficulty level, and cost. You might even be wondering how to go about reserving your spot...

  • Topic Coverage: Sharepoint from a user's perspective, Installing configuring and deploying, basic portal concepts, site customization, enterprise integration, and webpart development.
  • Number of Events: 3 Seminars (Level 100, 200, and 300), and 3 follow-up Hands-On Labs, spread over the course of three months.
  • Target Audiences: Primarily web developers who are curious about the whole "sharepoint thing". But also administrators, end users, and IT managers might find value as well from the level 100 session.
  • Difficulty Level: We are trying our best to make the difficulty level progressive - this is to encourage individual attendee's growth as the series progresses. The first session is Level 100, and is intended for technically-savvy people who are just getting their feet wet with Sharepoint. Level 200 builds upon the core concepts, and adds Customization and simple Webpart Development among other things. Level 300 goes deeper into complex Webparts, and touches on more advanced issues such as deployment and recovery.
  • Cost: FREE! Totally, completely FREE!! We are doing this as an INVESTMENT into the local developer community, hoping to build up a stronger skillbase here.
  • How to reserve a place: Please use on of the registration links on the event's website at http://www.sharepoint123.com. PLEASE do not sign up your entire development staff! We have limited space (especially for the HOLs), so be thoughtful of your peers and only register places for folks on your team who are truly interested in learning these skills.

Please refer to the event's website via any of the above hyperlinks for even more details about this fantastic series.

We are really excited to be providing this kind of event to the Atlanta developer community. This is something we had been talking about doing for a very long time - and now we have finally gotten off our tails and put it all together!

 

.NET | Events | General
Saturday, July 30, 2005 12:21:45 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Friday, July 29, 2005

Atlanta Enterprise Architecture Group

I ran into a nice fellow, Burr Sutter from BravePoint, at last monday's .NET User Group meeting. I seems he is forming an Atlanta chapter of the International Association of Software Architects (IASA). This is a platform-agnostic group that is interested in moving this emerging field forward - and they don't care if you are J2EE, .NET, or WebSphere, or any other platform advocate. The basic concepts and issues are the same, and we can all share the many flavors of kool-aid without any name-calling. At least thats the idea...

I for one plan on attending these meetings as often as I can. The kick-off meeting announcement goes something like this:

======================

International Association of Software Architects - IASA announces the opening of the Atlanta Chapter.

IASA Atlanta has an established network of Atlanta's most elite software engineers, executives and architects.  Please join us on August 10,
2005 for our
first public meeting for a discussion on Enterprise Architecture.

Topic: Enterprise Architecture
Speaker: Angela Yochem, Vice President, Portfolio Architecture - SunTrust Banks, Inc.
Description:
Angela Yochem will talk about the responsibilities, complexities and significant challenges of Enterprise Architecture in today's enterprise. A facilitated panel discussion will follow, featuring some of the industry's notably impactful enterprise architects.

Whether you consider Enterprise Architecture to be an effort, a team, a diagram of systems, a method of governance or otherwise, this event provides an excellent forum for discussion and examination of the field of Enterprise Architecture.


Panelists:
Les Phillips, Enterprise Architect - UPS Supply Chain Solutions
Jason Chambers, Principal Architect - Delta Air Lines
Patrick McClellen, Senior Technical Architect - SunTrust Banks
Andrew McSherry, Vice President of Technology Services - Fujitsu

 

Location: MATRIX Resources
115 Perimeter Center Place, NE
Suite 250
Atlanta, GA 30346
Directions:
- I-285 Exit 29 Ashford-Dunwoody Road (East of 400)
- Pass Perimeter Mall on your left
- Turn left at the 4th traffic light onto Perimeter Center West.
- The 3rd driveway on right will be marked SOUTH TERRACES and 115 Perimeter

Center Place.
- Turn right into the curving driveway and enter parking garage.
- Feel free to park in any unmarked space on any floor. Visitor
parking is also available on the 2nd level, but is limited to a
maximum of 2 hours.

Time: 6:30 to 8:30 PM

Contact:
Burr Sutter - burrsutter@gmail.com
Phone: 770-714-3292
Website: www.iasarchitects.org

IASA Atlanta is open to all professional software architects regardless of
development platform.

 

.NET | Events | General
Friday, July 29, 2005 11:12:24 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Wednesday, July 20, 2005

VS 2005 b2 VPC

Cool - in the Subscriber Downloads section of MSDN there is now a pre-built VPC of beta 2 Visual Studio, with Team System installed.

It's all trial installs (Server 2003, etc), mostly set to expire in 2006... but it's a very easy way to get some exposure to VS2005 and Team System without spending half a day loading up your own system image.

It's not that small (2.85 G) of a download, but at least you don't have to sit through 6 hours of installation prompts.

 

Wednesday, July 20, 2005 4:03:37 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

VB's default 1-based arrays are stoopid

Please see the post title for details.

Wednesday, July 20, 2005 3:10:15 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [1] | 

# Tuesday, July 12, 2005

Eh, does anyone else bother with transactional integrity these days?

This question occurred to me today as I sacked through YADAL (yet another data-access layer):

Does anyone else even understand transactional integrity these days?

It used to be that you didn't dare write a bit of code unless it supported at least some rudimentary transactional guarantees. But now it seems that the only transactionally-safe code I ever see "in the wild" anymore is the code I actually put out there. Countless data-access layers, monolithic systems, and even ingenius multi-tiered highly scalable systems.... but none even provide the most basic of consideration to transactions in their architecture.

I see tremendous effort made to encapsulate and abstract away the details of database access... O/R mappers, hand-rolled business classes, custom "code blowers", point-n-clicked typed datasets, pretty much everything under the sun. But pretty much never any love for SqlTransaction.

Come to think of it - this isn't a .NET problem either. I noticed the dreadful lack of transaction support even prior to .NET when I was a Delphi code jockey.

Perhaps nobody else builds applications that need to write to more than one table in a logical work unit? Nah, can't be.

Just please if you happen to run across this weblog one day and reading this,... please find out how (and why) you might need to be using transactions in your application architectures. I would like to one day encounter a custom developed application (other than my own) that actually implements transactions.

And on the other hand, hopefully you don't go to the other extreme and start peppering transaction locks all over your code "just in case"... cuz that can be an even worse situation...

Thanks, getting off the soapbox now...

 

Tuesday, July 12, 2005 8:22:00 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [9] | 

# Sunday, July 10, 2005

Interested in SharePoint and other portal technologies?

If so, then you try your best to make it to the FREE Portal Development mini- Code Camp in Charlotte on August 20th.

If you were in Atlanta for the May Code Camp, you might remember Maxim Karpov [you might even have been one of the many who wrote "Maxim ROCKS" in your event survey comments]. Well, Maxim is the host for this mini- Code Camp, and on his agenda are sessions for Portal Design Patterns, Sharepoint, DotNetNuke, and ASP.NET 2.0 Portal Frameworks.

This should be a pretty good event to attend if your schedule is open, and I highly encourage everyone to attend.

Attendance IS limited, so it would be a good idea to register now and reserve your place!!

 

.NET | Events | General
Sunday, July 10, 2005 3:56:11 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Friday, June 24, 2005

The shallowing

As you can tell from my last post, I have been on the recieving end of quite a few interviews lately. But on the flip side, I have also been performing just as many interviews myself on behalf of AfterHours.

So when did I miss the big shallowing of the talent pool?

The last time I helped an employer with interviewing, there was a certain quality bar that everyone recognized. People with skills below that bar were not submitted. People above the bar were submitted for consideration - and almost always at an hourly rate that was in line with their experience level (we are talking contractors here).

This time however, I continue to be surprised - nay, astounded - at the audacity of recruiters that have been submitting resumes to us for consideration. Easily four out five have been so incredibly overinflated that once it gets to a real interview, the candidate cannot support their own resume claims. For example, I interviewed a person only a few days ago that claimed to be a "senior .NET developer" and "proficient with SQL Server". Yet this person was unable to answer correctly a single basic technical question in either subject area. I wish this were the exception, but it is seemingly the norm. I am sorry, but when a contractor is presented as "senior" with a billing rate approaching $100/hour, they had damn well be able to stand up to a basic technical interview.

I won't even talk about the cases (yes, plural) where the person being interviewed was obviously not even the same person described on the resume itself...

Now granted not all submissions have been so bad. Most from Circle Consulting and Project Solutions have been relatively solid (or at least acceptable).

Recruiters: you need to get your act together. I think you need to pass the same certifications that we (developers, architects, etc) need to pass. You need to understand the technologies so that you can adequately screen these people out before their resumes make it to us (and piss us off enough to never call on you again). I mean, isn't that YOUR JOB??

Job Seekers: Stop lying on your resumes. Dishonesty on a resume is the BEST way to ensure that you will be passed up by an employer. You might be able to bullshit your way past the recruiter's screening process, but you aren't going to make it any further than that, and you definately will not survive long once your new employer discovers that you really don't posess the skills they asked for.

 

OK, I have blown off enough steam for now. I know it won't make one iota of a difference, but it at least makes me feel better to shout into the \dev\null abyss...

 

Friday, June 24, 2005 2:37:16 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [9] | 

# Friday, May 13, 2005

Book Review: "Microsoft BizTalk Server 2004 Unleashed"

Publisher: Sams Publishing
Author(s): Scott Woodgate, Stephen Mohr, Brian Loesgen, et al.
Categories: .NET, EAI, Web Services, BPEL
Published: 2004
ISBN: 0-672-32598-5
Online Order Links: Amazon, BN.Com, Buy.Com

Summary:

BizTalk Server 2004 Unleashed is a deep exploration into Microsoft's flagship orchestration and integration product.

This book covers a lot of ground. In 680 pages it covers everything from the basics of building schemas and maps all the way up to Business Activity Services and Human Workflow Services. In between, it spends time on Pipelines, Orchestrations, Adapters, the Business Rule Engine, and even Single Sign-On. For the developer, it goes into detail on debugging as well as the creation of all BizTalk elements. For the Architect, it outlines the various messaging and orchestration patterns, and how they are normally handled in a BizTalk implementation. For the Administrator, it explains deployment as well as ongoing monitoring, instrumentation and management. It takes an especially deep look at scaling up/out of BizTalk deployments at all four tiers of the product's architecture.

In all, this book does a good job of dealing with the details of BizTalk development and administration. It caters to those who already have a grasp of the product, definately not a beginner's book. In fact, even for those familiar with BizTalk, the chapters on HWS, BAS, and BAM might be a little too difficult. One thing the book does an outstanding job of is describing the scale-out strategies available in large deployment situations.

This book is most useful to:

  • Messaging Architects
  • Messaging Developers
  • Messaging Administrators

Recommendation:

4 out of 5 stars

I am holding back on a 5-star rating on this one. While it does a great job at handling the details, and leaves no stone unturned in many areas, the treatment of the advanced services such as BAS, BAM, HWS, and HAT is a bit too dry - even for a reader like myself who normally can make it through such material. Unless you are actually using these features in your day-to-day work, these chapters will likely not make much sense. They come off more as a "user manual" than as a reference-class book. In other words, lots of "how" and "when", but rarely does it answer the more important question of "why".

The remainder (and bulk) of the book however is top-notch. And since it is effectively the only book available today for BizTalk 2004, it would not be right to give this one any less than a 4 out of 5.

 

Friday, May 13, 2005 5:55:05 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [4] | 

Team System Licensing finally recognizes the Big Little Company

Fantastic!

Microsoft finally remembered that the majority of their MSDN subscribers are not huge enterprise customers, but rather the smaller one to five developer teams that permeate the industry.

In response to heavy feedback, they are introducing a five-seat version of Team Foundation Server with the version of MSDN that replaces Universal.

 

Friday, May 13, 2005 8:39:59 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

Atlanta Code Camp is upon us!

In less than 24 hours the festivities will begin.

Towards the end of the day, my presentation will be a deep look into asynchronous programming, with particular emphasis on multithreading. This is more or less the same presentation I gave a few months ago to the C# User Group, but with information about the new Semaphore support in 2.0 (with a corresponding example project).

The other major difference is that with the C# UG version of this presentation, it took me an hour and 20 minutes to cover it... moving through it all very quickly. However at Code Camp, we are limited to under an hour! More slides, more demos, and less time to do it!

I am also posting the Slide Deck and Sample Code here, for anyone who misses the presentation or that just wants to see what the session is covering before deciding which one they want to attend.

 

.NET | Events | General
Friday, May 13, 2005 8:26:19 AM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [0] | 

# Tuesday, April 26, 2005

Refactor!

At last night's Atlanta .NET User Group meeting, Alan Griver showed us the new Refactoring tool that is free for VB.NET 2005.

In a nutshell - this tool is amazing!

And the first question posed was "how do we get this in c#?"

It turns out that if all you need is VB.NET 2005, you can use the free version. But there is also a "pro" version for $99. This pro version supports C# as well as VB, but not only that - it supports both languages in all versions of Visual Studio!

PLUS, there is a 30-day free trial available for this pro version. After downloading it and playing around for less than 5 minutes I can safely say this tool is a MUST HAVE for anyone involved in writing code!

You can find out more about the Pro version at this URL:

http://www.devexpress.com/Products/NET/Refactor/

And you can find the trial installation download at this URL:

http://www.devexpress.com/Downloads/NET/Refactor/

 

.NET | Events | General
Tuesday, April 26, 2005 2:51:29 PM (Eastern Daylight Time, UTC-04:00) #  Disclaimer | Comments [2] | 
View Keith Rome's profile on LinkedIn

On this page....

A Simple Sound Effects Engine for Silverlight 2
Gem Blaster updated and enhanced for Silverlight 2
Atlanta Code Camp 2008
Speaking at the Atlanta Cutting Edge / Atlanta MS Professionals Tomorrow
Heading to MIX this year
Slides and Code from Alabama Code Camp 6
Heading to Alabama Code Camp 6
Source Code for Gem Blaster finally published to CodePlex
PolyGraph3D: Making 3D happen with Silverlight 1.0!
Silverlight Bug: MediaElements will restart if their containment lineage changes
Silverlight Bug: Using a packaged image source for multiple Image elements
The Atlanta .NET Doubleheader: Visual Studio 2008 Loadfest and XBox Gaming Night
10 interview tips that will help you land a better job
How to Botch an Interview and Ensure that you will Never get an offer
Expression Design Service Pack 1
Win a free pass to Devscovery 2008!
No user group meeting Monday night
Speaking in Charlotte tonight
Blend 2 August CTP Refresh
AirportWait (Silverlight Demo)
SilverLife (Silverlight Demo) posted
MVP Award - C#
Whose Slide is it anyway?
Popper!
Quick Tip - Input Controls in Silverlight
Understanding what it means to "hit the curve"
Atlanta Cutting Edge .NET - May 2007
A storm is brewing
WPF/E Gets a Name
Expression tools for MSDN Subscribers and Partners
Alabama .NET Code Camp
Longest Posts EVAR
Atlanta Cutting Edge .NET User Group Meeting - Monday March 5th
New Job
Project Planning Basics
Adventures in Databinding ~ Part 2 ~ Simple versus Complex Binding
Adventures in Databinding
Crawling back out of my cave
2007 Atlanta Code Camp - Registration is OPEN
Microsoft Lunch and Learn
MCPD - EAD
Atlanta Cutting Edge .NET - September 2006
CANCELLED: Atlanta C# User Group Meeting for June 2006
2006 Atlanta Code Camp
Unit testing and Test Driven Development
Atlanta MS Professionals UG
Adding a Google or MSDN2 search to VS2005
PageFlakes
Interested in AJAX?
Weird HTTP header issue in Internet Explorer 6
A peek into the future of managed OS's
Much h8 for VB
VMWare Player
C# UG Presentation: Engineering an Application Foundation using Code Generation
C# UG Presentation: Custom Exceptions
More FREE Sharepoint Training!
WSS SP2 available now
SharePoint v3 video
More on Sharepoint SP2
Cool Sharepoint News
FREE Sharepoint Training
Good security article
Code Camps are everywhere!
First Sharepoint 123! training session a resounding success!
Designing a Service, Part 2
Designing a Service, Part 1
8/1 C# Users Group Meeting
FREE Sharepoint training - coming to Atlanta
Atlanta Enterprise Architecture Group
VS 2005 b2 VPC
VB's default 1-based arrays are stoopid
Eh, does anyone else bother with transactional integrity these days?
Interested in SharePoint and other portal technologies?
The shallowing
Book Review: "Microsoft BizTalk Server 2004 Unleashed"
Team System Licensing finally recognizes the Big Little Company
Atlanta Code Camp is upon us!
Refactor!

Archives

Navigation

Categories

About

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Sign In

Certification Logo Certification Logo Certification Logo Certification Logo Certification Logo

Powered by: newtelligence dasBlog 2.3.9074.18820