What Was I Thinking?

Follies & Foils of .NET Development

  Home  |   Contact  |   Syndication    |   Login
  30 Posts | 0 Stories | 78 Comments | 0 Trackbacks

News

Archives

Post Categories

Check These Out

Gurus

Wednesday, February 11, 2009 #

At PDC this year, Microsoft announced a major release of the Windows Workflow Foundations (WF); WF4.0

WF4.0 promises better performance, scalability, control, visibility, and usability than its predecessor.

Gone are code-asides and the dreaded code activities, replaced with 100% XAML markup and custom activities.  MFST has seriously stepped up its tooling to make custom activities easier (including defining a custom WF syntax which gets “compiled” to XAML), an improved designer and debugging support.

Interop support is available to run your soon-to-be-legacy 3.x Workflows under 4.0, but it sounds as if a refactoring of current workflows and activities is the best way to leverage the 4.0 improvements.  Looks like I’ll be releasing a new version of the Custom Activity Generator

The new WF runtime allows WF’s in app, data, or UI tiers. WF articulation is gaining momentum in the other MFST initiatives too, including Azure, office and of course Sharepoint.

Here’s a link to some session screencasts relating to WF 4.0.

 

Update:

Here’s a link to an article by David Chappell, which explains the high level interactions between some new MS technologies including WF 4.0, Oslo, and Dublin (Server extensions)


Tuesday, December 23, 2008 #

Ever need to convert a List of strings in a comma delimited list?  In the past I'd write a foreach loop. Something like:

public static string FlattenStringList(List<string> items)
     {
         StringBuilder str = new StringBuilder();
         bool firstOne = false;
         foreach (string item in items)
         {
             if (!firstOne)
                 str.Append(",");
             else
                 firstOne = false;
             str.Append(item);
         }
         return str.ToString();
         
     }

Now, thanks to String.Join and  Linq, I can compress it to a single expression:

string.Join(",", items.ToArray());

Also useful when the source is IEnumerable<T>, and I want a property of T flattened, consider a list of people, to get a comma delimited list of all the first names is a simple matter of:

var firstNames = string.Join(",", (from person in people select person.FirstName).ToArray());
   

If you need it a quote qualified, comma delimited list of first names:

var firstNames = string.Join(",", (from person in people select "\""+person.FirstName+"\"").ToArray());

Wednesday, July 09, 2008 #

Often during development I end up with "Constants" classes, classes of constant or static values that I want design time Visual Studio intellisense support for, and run-time domain checking.

Consider the following class:

public static classConstants
 
{
       public static classClaimTypes
     
{
           internal static stringClaimTypeNameSpace = "http://schemas.wtfsolutions.com/2008/07/claims/profile/";
           public static stringFirstName = ClaimTypeNameSpace + "firstname";
           public static stringLastName = ClaimTypeNameSpace + "lastname";
           public static stringDateOfBirth = ClaimTypeNameSpace + "dateofbirth";
           public static stringFavoriteColor = ClaimTypeNameSpace + "favoritecolor";
       }

   }

 

This class is handy at design time.  When I type "Constants.ClaimTypes." up pops an intellisense list of the valid claim types for my application.

The problem with this list is that you can't iterate through it at runtime, ensuring the value of a variable is in the valid ClaimType domain of values.  Ideally I'd like to be able to do this: ** THIS DOES NOT WORK ***

private bool validateClaimType(string claimType)
{
    return Constants.ClaimTypes.Contains(claimType);
}

Fortunately, we can use reflection to build a runtime dictionary of the field name and field values

private Dictionary<string, string> staticFieldsToList(Type targetType)
{
    var list = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    var fields = targetType.GetFields(BindingFlags.Public | BindingFlags.Static);
    foreach (var field in fields)
        list.Add(field.Name, field.GetValue(null) as string);
    return list;
}

and validate our claim type as follows: ** THIS WORKS **

private bool validateClaimType(string claimType)
{
    return staticFieldsToList(typeof(Constants.ClaimTypes)).ContainsValue(claimType);
}

In my real application I store the dictionary to a static field to avoid multiple reflection-based calls, but for the purposes of demonstrating functionality, the above code reflects the static class each call.

 

The best of both worlds, design-time IDE support and run-time domain validation. 

I love it when a plan comes together.


Friday, July 04, 2008 #

I've been using Google Desktop Search for some time now.  Most of it however, I don't find useful.  I never search my desktop, and store my mail on a different server, so I miss out on a lot of the Google Desktop value proposition.  So why use it at all?  The answer is Google Quick Search. 

Google Quick Search is the little dialog that pops up whenever you press Ctrl twice.  I enter a phrase and hit enter and the phrase is automatically sent to the Google search page, rendering the search results in my browser window.  Its just so darn handy.. Google is literally at my (pinky's) finger tips.

image

I got a new PC recently and installed 64 Bit Windows 2008 Server.  During my "setup and configuration" phase, I was shocked to find Google had no support for 64 bit Windows operating systems.  Apparently it was available at one time but got pulled because of performance and compatibilities issues.   Oh Google, why has thou forsaken me?

Since I only really wanted the Quick Search functionality, I decided to write my own Google Quick Search clone.  Enter WTF Quick Search.

After installation (it installs itself in the startup folder), pressing Ctrl twice invokes the Quick Search dialog, which looks *ahem* slightly familiar.

wtfQuickSearch

Most of the original Google Quick Search functionality is replicated in the WTF Quick Search.  Since it doesn't leverage the Google Desktop engine, you can't search your local desktop, and support for Google Suggest is on the horizon, but not yet implemented.  Instead this version uses Auto-Complete to remember your previous search terms and offers them as suggestions as you type.

There are a number of Hot keys available for targeted searches.  Pressing Enter searches the web, Ctrl+I performs an image search, Ctrl+N a news search.  You get the idea.  There is a full list of hot keys available in the Options page.

If you like Google's Quick Search, and have either a 64 bit, or 32 bit version of windows, but don't want/need the overhead of local desktop searching, download WTF's Quick Search. (you'll need to rename the .msi_ file extension to .msi before executing it).

As always, I welcome your feedback and suggestions.

 

July 5, 2008 - Update: I've released an new version.  This version fixes a bug with the Search Mode option (web vs program files), adds an Icon to the system tray which lets you show/hide the dialog and exit the application.  I've also added multiple monitor support, the dialog will pop up on the monitor that currently houses the mouse pointer.  Want it to do something else?  something better?  Let me know.  I'm always open to your feedback.

July 22, 2008 - Update: A new version is available that adds hot key support for searching Google Finance (Ctrl+F)

July 29, 2008 - Update: Don't like the Control+Control hotkey?  Define your own.  Video Card doesn't support transparency?  Try the "basic" interface.  Lookup MLS Listings by MLS number with customized MLS market codes. Download it here.


Friday, May 23, 2008 #

As I've done more and more WCF work recently, I've noticed an intermittent problem running my unit tests.

The host seemingly hangs for no obvious reason.  Eventually the connection times out and produces the following in the service log:

System.ServiceModel.CommunicationObjectAbortedException, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

Stopping the host and client and re-running the test allows it to pass without issue. 

The problem is related to the way I managed my WCF channels and client proxies.  In my code I make use of the ChannelFactory<T> object to create my wcf channels dynamically from my configuration information, like the following:

 

       #region IdentityService Proxy
        private static IIdentityService _identitySvc;
        private static IIdentityService identitySvc
        {
            get
            {
                if (_identitySvc == null)
                {
                    var factory = new ChannelFactory<IIdentityService>("IdentityService");
                    _identitySvc = factory.CreateChannel();
                }
                return _identitySvc;
            }

        }
        #endregion
 

The client proxy produced implements the typed interface "IIdentityService" in the above example. It natively supports no operations for channel management and cleanup. However, failing to clean up the client proxy may cause channel timeouts and resource blocking on the server. So channel cleanup is important, but if its not implemented in the client proxy, how do you manage it?

The secret lies in the casting.  The transparent proxy produced implements a number of useful interfaces.  For our purposes we care about IDisposable and IClientChannel. When we're done with the proxy,  we must close the channel and dispose of it.  I've seen some examples like this:

using (IClientChannel client = (IClientChannel)channelFactory.CreateChannel())
{
    IIdentityService proxy = (IIdentityService)client;
}

This is Bad. Yes, you are disposing of the channel resource, but you haven't closed the wcf channel, you've only disposed of your handle to it. You must explicitly call close then dispose on the proxy like so:

            if (_identitySvc != null)
             {
                 ((IClientChannel)_identitySvc).Close();
                 ((IDisposable)_identitySvc).Dispose();
                 _identitySvc = null;
             }
 

Optionally, since IClientChannel implements IDisposable, you could call ((IClientChannel) proxy).Dispose().  If you prefer, and your design allows, you can still use the using statement, just be sure to add try/catch blocks and call the close() method on the casted proxy before the closing brace. I tend to have static references to my proxy classes so I have to explicitly call close() and dispose() when I complete my WCF operation.

Now that I'm properly cleaning up my proxies, my WCF services run all my tests without hanging.


Tuesday, May 13, 2008 #

I've been using the Thunderbird mail client for a while now, and overall I like it.  I've got a number of add-ons that let me download my web mail from Yahoo, GMail, Hotmail and the like.

I've got all my email accounts available in a single client application.  So far so good.

I do have a pet peeve however, maybe its a bug, maybe not.  It sure feels like a bug.  I did some googling but found no one else reporting this behavior, so maybe its my configuration.  But I found no configuration setting to support it, so if its not a program bug, its at least (in my opinion) a usability bug.

When I view my inbox for an email account, I like it sorted by Date descending, so my latest mail is at the bottom of the list.  Its easy enough to sort it, just click on the date column header in the list view.   The problem however, is that the setting doesn't seem to stick.  For some reason, its always sorted by sender.

If I sort my inbox view for email account A to Date, then I click on the inbox view for email Account B, and click back on the inbox view for email Account A, my previously specified sort order of date is not persisted, and the view is once again sorted by sender.

Has anyone experienced this?

UPDATE:  As I was writing this I was playing more with the Thunderbird UI, following along with my post to ensure I hadn't missed some salient point or user operation.  Suddenly, much to my surprise as I clicked from account to account, the sort order preference was getting preserved. The bug has mysteriously vanished.  Its like taking your car to the mechanic.  When its at the repair shop, it refuses to  act up. 

If I knew all I had to do was write a blog entry about it, I could have had this fixed weeks ago <g>.

I'll post another update should the bad behavior return.  I've also configured my client to show a View dropdown in the menu bar (I think this was an add-on).  I suspect this may have something to do with my sort order problem, but can't verify it until it starts acting up again.


Saturday, May 10, 2008 #

I've been developing and debugging a windows service for my current project. Working with a Windows service is very much like working with a console app, with the startup and shutdown logic separated into the servicebase's start and stop methods.

 

Debugging a Windows Service

Unlike a console app, however Visual studio can't run a windows service and automatically attach the debugger (no Run-with-Debugger (F5) support).  Not to fear, its easily enough to attach the debugger to the windows service.  In my case, my service was starting and stopping right away, with no opportunity to attach the visual studio debugger to the running service.  Instead I added this handy dandy line of code to the constructor of the service class:

 

            #if DEBUG
             Debugger.Launch(); 
            #endif 

when the service starts, Windows prompts you to attach a debugger.

image

Select the debugger of choice and step through your windows service.

 

Removing and Reinstalling a Windows Service

I ran into a problem attempting to uninstall  and reinstall my windows service.  I was able to delete the service fine, but when I attempted to reinstall the windows service I received a "The Specified Service has been marked for deletion" exception.

Microsoft recommends rebooting to solve this problem; a solution that is not very conducive to a development cycle.  Fortunately I stumbled upon a easier solution.

It seems that when the windows service list is visible (Start->Control Panel->Administrative -> Services), the list of windows services is cached and locked resulting in the "The Specified Service has been marked for deletion" exception.  The fix, close the services dialog.  With the dialog closed, I was able to re-install the windows service without issue.

I've switched my process to starting and stopping the service using Net Start/ Net Stop batch files.


Wednesday, April 30, 2008 #

I've often thought about making my own implementation of a Dictionary<K,V> where the key values are case insensitive.

Its been one of those things on my ever-growing to-do list. I usually end up casting the key values to all uppercase and try to encapsulate all my calls the the dictionary with my own logic that performs the case conversion.  A case insensitive dictionary would avoid all that nastiness.

Sometimes it's helpful to read the tooltip overloads. As I coded a new dictionary instance today, I stumbled upon the

Dictionary<(Of <(TKey, TValue>)>) Constructor (IEqualityComparer<(Of <(TKey>)>)) overload.  

Apparently I can pass my own equality comparer into the constructor which tells the dictionary how to compare key values.   Could it really be that easy?

Yep, it exactly that easy.  To make my dictionary<string,string> use case insensitive keys, declare the dictionary as follows:

Dictionary<string, string> argList = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);

Now  args["Test"] and args["TEST"] return the same item from my dictionary.

I love it when I can mark things done on my to-do list without actually having to do any work.


Monday, April 14, 2008 #

This is another one of those "Posted here for MY convenience" tips.

You can use the Visual Studio Debugger to debug a .vbs (vbscript) file executed with cScript.exe by using the //X flag at the command line.  

 

To debug MyTest.vbs

cscript.exe MyTest.vbs //X

 

The //X will set a breakpoint and invoke the "select a debugger"  dialog where you can choose Visual Studio and step into your vbs code.  I haven't found a way to directly edit from the debugger however, so I end up having to debug, break execution, fix my bug and restart the vbs script file again to see my changes.


Monday, April 07, 2008 #

I know this is available other places on the web, but I'm posting it here because I often have to search for it.  This tip is more for my benefit than others :)

class Program
{
   public static void Main()
   {
      Thread t = new Thread(delegate() { 
         SayName("Lou","Costello");
         });
      t.Start();
   }

   protected static void SayName(string firstName, string lastName)
  {
        Console.WriteLine(firstName + " " + lastName);
  }
}