Personal Twitter Client Counter

Get a count and percentage of how many updates you've had with each twitter tool.

Download C# 3.5 WPF Source Code
Note: This source code is mostly a quick hack to get the data I wanted. Also, if you run this on your own data, note that you may need to wait a few minutes for results to come back.

In testing out various twitter clients, I wanted to get a feel for my personal usage (how much I've used each client), so I decided I'd write some code around it. To begin, here are the results:

web, 1770, 41.549%  Clipboard02
im, 1214, 28.498%
txt, 713, 16.737%
SnapFoo, 153, 3.592%
twigadge, 146, 3.427%
Twadget, 128, 3.005%
TwitterFox, 61, 1.432%
Snitter, 21, 0.493% 
Jott, 17, 0.399%
TwitBin, 16, 0.376%
twitterfeed, 7, 0.164%
Spaz, 6, 0.141%
Twitter Opera widget, 3, 0.070%
twhirl, 3, 0.070%
Twittearth, 2, 0.047%

I snagged an API code sample and fired up my trusty Visual Studio 2005. Thankfully (so I could step out of my box a bit), the code sample was in C# 3.5! So... I popped open my laptop and set out coding (finally, for the first time outside of dragging some controls around) in Visual Studio 2008.

As part of this, I wrote my first LINQ-to-XML query!

This code makes a request to twitter (you have to be authenticated first) and gets an anonymous type list called sc that has the key (the name of the source, as shown above) and the count from that page. After that I work some magic to aggregate them across all pages, though I'm investigating how to do the aggregation by first combining the XElement-s from each page (though that would take up a lot of memory).

url = "http://twitter.com/account/archive.xml?page=" + x.ToString();

WebRequest Request = HttpWebRequest.Create(url);
Request.Credentials = new NetworkCredential(userName, password);
WebResponse Response = Request.GetResponse();
Stream stream = Response.GetResponseStream();
TextReader reader = new StringReader(new StreamReader(stream).ReadToEnd());
XElement statuses = XElement.Load(reader);

// My first LINQ query!
var sourceNames = from source in statuses.Descendants("source")
                  group source by source.Value into sc
                  orderby sc.Count() descending
                  select new { sc.Key, MyCount = sc.Count() };

I also got to play around in WPF just a little. Nothing fancy at all, but it was nice to see the new IDE in action. It feels much more powerful.

I may play around with this some more, add graphing, toy around with it as a Silverlight 2 app. Or it might just sit there and do nothing ;-)

Latest tool: XPath query field extractor for InfoPath 2003

Update: This tool seems to be only relevant with InfoPath 2003. A co-worker pointed out that due to customer pains around a the lack of a feature like this, in InfoPath 2007 you can right-click a node in the data source and choose "Copy XPath". Cool! Thanks to Scott Heim for pointing this out.

So, I love making tools. One-off things that process something. Batch files that lessen monotony. Sexy little WinForm apps for displaying data. XSL transformations that regurgitate and pre-process XML.

My latest tool is a small WinForms app that pulls out a list of fields form an InfoPath document so they can be referenced as XPath. This is pretty neat because my client needed a documentation artifact, and this saved quite a bit of tedium. Getting this data also proved difficult because the Namespace URI for the "my" namespace is always changing because it includes a timestamp (see solution below).

Here's a sample of the output. You can use each of these lines as XPath queries against the document:

my:MyFields/my:secMain my:MyFields/my:secMain/my:secPhysicalDescriptionHeader my:MyFields/my:secMain/my:secDualCitizenshipMain my:MyFields/my:secMain/my:secDualCitizenshipMain/my:secDualCitizenshipName my:MyFields/my:secMain/my:secDualCitizenshipMain/my:secDualCitizenship
.
.
.

The tool uses the CAB SDK's extract.exe via a command shell to pull out the template.xml file from the InfoPath XSN file.

The code for using the SDK was pretty straightforward. In this case (since we want the XML template in the InfoPath, the variable ExtractionFileName is defined as:

private const string ExtractionFileName = "template.xml";

And fileName is the location of the XSN file. The code for the extraction is:

// Use the CAB SDK to grab the template file from the InfoPath XSN package
Process proc = new Process();
proc.StartInfo.FileName = ".\\EXTRACT.EXE";
proc.StartInfo.Arguments = string.Format("\"{0}\" {1}", fileName, ExtractionFileName);
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.Start();
proc.WaitForExit();

Dealing with the ever-changing "my" namespace

One particular challenge arose. Since the "my" namespace in InfoPath is defined with a timestamp, every time you change the schema the namespace URI changes. So, I had to do a little preprocessing before I could read the fields (since they're all in the "my" namespace). Thankfully the timestamp is of fixed length.

XmlDocument doc = new XmlDocument();
doc.Load(extractionFilePath);

// Use a low-tech way to get the "my:" namespace URI, since it 
// differs by form and when changes are made
string fileContents = File.ReadAllText(extractionFilePath);
int myIndex = fileContents.IndexOf("xmlns:my=") + 10;
string myNamespace = fileContents.Substring(myIndex, 75);

XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("my", myNamespace);

XmlNode myFieldsNode = doc.SelectSingleNode("//my:myFields", mgr);

After you get the "myFieldsNode" you can recursively iterate through the nodes and output the fields.

Live Writer: Word+Social media, for bloggers

I just started using Windows Live Writer to update my blogs*. I'm thoroughly impressed with what I see, both from the practical sense and just how much cool seems to surround this thing.

1) My Apartment Building, Washington, DC

Software+Services is Microsoft's answer to the debate about where the future of computing is going in the near future. My take on what this means is a badass WinForms interface with a sexy back-end built around some Web 2.0-ish stuff. That's the technical explanation.

Live Writer epitomizes all of this. It's a lightweight, feature- and graphics-rich editing environment, and it's very closely integrated with a bunch of "Web 2.0" sites, including a pile of blog packages and social media sites.

There are some neat plug-ins "out of the box", including one that took me exactly 12 seconds to show you an image of my apartment building (see image 1).

Plus, there seems to be an active plug-in community developing things to better pretty up source code, integrate with Flickr, Facebook and other sites. Some of em are crap, but the architecture seems like it must be easy enough to be accessible. One cool one is the Amazon Book Lookup plugin (see example below)

Some of the interface features I'm falling in love with include the ability to match the style to the blog's style (so I can switch between the three blogs and see how it'll look in each one), and the ability to pull up old posts from the "Open" menu.

Party of One: The Loners' Manifesto
by Anneli Rufus

Read more about this book...

* My blogs:

Synchronize XSD from an InfoPath document with a SharePoint project for server-side XSD validation.

In order to implement server-side XSD validation against an InfoPath form submission, I had to pull the XSD from the InfoPath document archive (XSN file) and use that to update an embedded resource in a SharePoint solution project (including automated checkout/checkin in TFS). I was able to do it using a batch file.

Pretty specialized need, but maybe somebody could make use of it someday ;).

@echo off

rem ***********************************************************
rem This batch file is used to extract the XSD files from each of the InfoPath forms, and copy them into the source tree
rem Download and install the Microsoft CAB SDK from http://support.microsoft.com/kb/310618 to c:\cabsdk
rem ***********************************************************

rem IMPORTANT: Set these values to your system. Do not include trailing slashes, and include values in quotes if necessary

set CABSDK_PATH=c:\cabsdk\bin
set ROOT=C:\projects\projectname
set TFS_USERNAME="domain\user.name"
set TFS_PASSWORD=password

rem These should be relatively fixed
set FORMS_ROOT=%ROOT%\Project.Namespace\12\TEMPLATE\Layouts\infopathForms
set XSD_ROOT=%ROOT%\Project.Namespace\12\Resources
set TF_PATH=C:\Program Files\Microsoft Visual Studio 8\Common7\IDE

echo.
echo ********* InfoPath Form 1 *********
echo.
set FORM_PATH=%FORMS_ROOT%\Form 1\Form1.xsn
set XSD_PATH=%XSD_ROOT%\Form1.xsd
set RETURN=FINISH
goto UPDATE_SCHEMA

:FINISH
goto FINISH_BATCH

:UPDATE_SCHEMA
echo Checking file out...
"%TF_PATH%\tf.exe" edit "%XSD_PATH%" /login:%TFS_USERNAME%,%TFS_PASSWORD% /noprompt >/nil

echo Extracting file...
del myschema.xsd
"%CABSDK_PATH%\extract.exe" "%FORM_PATH%" myschema.xsd >/nil

echo Replacing file...
copy myschema.xsd "%XSD_PATH%" >/nil

echo Checking file in...
"%TF_PATH%\tf.exe" checkin "%XSD_PATH%" /login:%TFS_USERNAME%,%TFS_PASSWORD% /noprompt /comment:"Automated checkin from XsdExtractor script" >/nil

goto %RETURN%

:FINISH_BATCH

Use the DescriptionAttribute with an Enum to display status messages.

I've been working on various forms of displaying status messages from enums, and here's the latest preferred iteration of how to do this. Regurgitated and tweaked from WayneHartman.com.

        public enum XmlValidationResult
        {
            [Description("Success.")]
            Success,
            [Description("Could not load file.")]
            FileLoadError,
            [Description("Could not load schema.")]
            SchemaLoadError,
            [Description("Form XML did not pass schema validation.")]
            SchemaError
        }

        private string GetEnumDescription(Enum value)
        {
            // Get the Description attribute value for the enum value
            FieldInfo fi = value.GetType().GetField(value.ToString());
            DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attributes.Length > 0)
            {
                return attributes[0].Description;
            }
            else
            {
                return value.ToString();
            }
        }

It's possible to do something even cooler like cache the values or add a ToDescription() method (in C#3.0), but I just wanted an simple, repeatable way to do this.

Recap of VS2008 InstallFest in Indianapolis



I just got back from the Visual Studio 2008 InstallFest in Indianapolis. Dave Bost from Microsoft was on hand with some awesome prizes from the source. I won a IndyTechFest polo shirt. There was Xbox360 to be had, awesome catered food (lasagna, salad, cake!), and some good networking.

There were also open-mic style code demos. Topics included:

- Syndication services
- Unit testing
- Javascript debugger in VS2008
- Code metrics
- System.HashSet
- System.AddIns

I twittered from the event and took some pictures with SnapFoo



We collected Toys for the WRTV6 toy drive. I brought one of those things that you stick your hand or whatever on and it makes a 3d "image" out of the impression in pins. I have one and love it, hopefully some kid gets as excited about it as I do. Haha.

Fix for Firefox not rendering GridView columns properly

Doesn't seem to be super well documented, so I figured I'd regurgitate it here. In Firefox, apparently whitespace in a table is treated as "important" by default, and prevents wrapping. To turn this off add this little CSS nugget <style type="text/css">
{
white-space:normal !important;
}
</style>
Source: http://www.telerik.com/community/forums/thread/b311D-ehhed.aspx

Access deep object graph properties by string with LLBGen

PDF form and template-based emails often require accessing property values deep within an object graph. For example, in my current project the first name property of an employee is accessed via Employee.Person.FirstName.

The following method takes an object path as a string (such as "Employee.Person.Address.Line1") and, using recursion, returns its property value no matter how deep within the graph the desired property exists.

private static string GetObjectFromPath(string objectPath, EntityBase2 currentEntity)
{
   string[] parts = objectPath.Split('.');
   string firstPath = null;
   object propertyValue = null;

   if
(parts.Length > 0)
   {
      firstPath = parts[0];

      PropertyInfo
prop = currentEntity.GetType().GetProperty(firstPath);
      if (prop != null)
      {
         propertyValue = prop.GetValue(currentEntity,
null);
      }

      if
(propertyValue is EntityBase2)
      {
         objectPath = objectPath.Replace(firstPath +
".", "");
         return GetObjectFromPath(objectPath, propertyValue as EntityBase2);
      }
   }

   if (propertyValue == null)
   {
      return null;
   }
   return propertyValue.ToString();
}

Social content in context with Google Reader's "Next" bookmarklet

I don't regularly use desktop or web-based RSS feed aggregators for the fact that they take the content away from its context. It usually doesn't add much, but sometimes I can gauge things like professionalism and creativity of the writer (such as is the case with Scott Hanselman's blog--it's snappy layout reinforces its content). Besides, tech blogs usually come through with code samples all screwy, images out of whack, and a variety of other distortions.

What I do enjoy about them, however, is independent of their presentation: knowing what I've read, informing me of new content, and allowing me to categorize feeds.

Enter Google Reader's "Next" bookmarklet. I'll admit I glossed over the "official" blog post back in June, which reminded users about the feature. If I want "Next" I'll just go to the web site and hit "j", I may have thunk. But alas, it's not that at all.

It's a web link that takes you to the site itself, in it's original context. Plus, it logs that you've read the post. Keep clicking the link, keep getting the next unread post in line. Plus, you can have separate links for different categories. It reminds me of a self-controlled webring (remember those?), which is always in tune with my interests. Brilliant!

Next step--Figure out how to hotkey that sucker. I can do some goofy stuff with the default bookmarks, but since I use the del.icio.us plugin, I'd rather keep it in there and have it hotkeyed...

Serialize and deserialize objects as Xml using generic types in C# 2.0

I've been using Object<>Xml serialization in .NET based on this post for a while. I decided to enhance it a tad bit with some generics, so I could use it more broadly. Here's what I came up with:

using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;

/// <summary>
///
To convert a Byte Array of Unicode values (UTF-8 encoded) to a complete String.
///
</summary>
///
<param name="characters">Unicode Byte Array to be converted to String
</param>
///
<returns>String converted from Unicode Byte Array
</returns>
private static string UTF8ByteArrayToString(byte[] characters)
{
   UTF8Encoding encoding = new UTF8Encoding();
   string constructedString = encoding.GetString(characters);
   return (constructedString);
}

/// <summary>
///
Converts the String to UTF8 Byte array and is used in De serialization
///
</summary>
///
<param name="pXmlString"></param>
///
<returns></returns>
private static Byte[] StringToUTF8ByteArray(string pXmlString)
{
   UTF8Encoding encoding = new UTF8Encoding();
   byte[] byteArray = encoding.GetBytes(pXmlString);
   return byteArray;
}

/// <summary>
///
Serialize an object into an XML string
///
</summary>
///
<typeparam name="T"></typeparam>
///
<param name="obj"></param>
///
<returns></returns>
public static string SerializeObject<T>(T obj)
{
   try
   {
      string xmlString = null;
      MemoryStream memoryStream = new MemoryStream();
      XmlSerializer xs = new XmlSerializer(typeof(T));
      XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
      xs.Serialize(xmlTextWriter, obj);
      memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
      xmlString = UTF8ByteArrayToString(memoryStream.ToArray());      return xmlString;
   }
   catch
   {
      return string.Empty;
   }
}

/// <summary>
///
Reconstruct an object from an XML string
///
</summary>
///
<param name="xml"></param>
///
<returns></returns>
public static T DeserializeObject<T>(string xml)
{
   XmlSerializer xs = new XmlSerializer(typeof(T));
   MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(xml));
   XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
   return (T)xs.Deserialize(memoryStream);
}

Javascript debugging in VS.NET

To simply regurgitate another post from GWB here (so that I can remember it), Javascript debugging is possible in Visual Studio .NET. In essence, it's not very good, but it's better than nothing and its integration with the common IDE keeps it familiar.

Sort a generic list (IList) by ToString() value

For whatever reason, Microsoft didn't provide a Sort method in IList. So it seems like sorting a generic list requires that the list be adapted to an ArrayList. Here's a class and method call that supports sorting any list by the ToString() value of its members.

public class ToStringComparer : IComparer 
{
   public int Compare(object x, object y) 
   {
      return x.ToString().CompareTo(y.ToString());
   }
}

ArrayList.Adapter(list).Sort(new ToStringComparer());

 

Using msbuild to change App.config and Web.config files

Using the msbuild community tasks project it becomes easy to change App.config and Web.config files as part of the build process. I've recently implemented a build script for a smart client application that allows building in multiple locations connecting to different application servers.

First, download the msbuild community tasks project. You can get this from subversion using the following command:

svn checkout http://msbuildtasks.tigris.org/svn/msbuildtasks/trunk msbuildtasks --username guest

Check the project out, build it and transfer the library and the .targets file to the desired directory. You can then import all of the tasks and start using the XmlUpdate task.

In order to work with App.config and Web.config you must add the appropriate namespace and reference the nodes in the xpath based on a custom-defined prefix. Here is a sample of this task in action: 

<Import Project=".\MSBuild.Community.Tasks.Targets"/>

<Target Name="UpdateConfigs" DependsOnTargets="GetVersion">
  <XmlUpdate
   Namespace="
http://schemas.microsoft.com/.NetConfiguration/v2.0"
   XmlFileName="$(SourceDir)\Core\ABSuite\ABClient\App.config"
   Xpath="//configuration/appSettings/add[@key='Main.ConnectionString']/@value"
   Value="$(DatabaseConnectionString)"
  />
  <XmlUpdate
   Namespace="
http://schemas.microsoft.com/.NetConfiguration/v2.0"
   XmlFileName="$(SourceDir)\Core\ABSuite\ABClient\App.config"
   Xpath="//configuration/appSettings/add[@key='Main.WebServer']/@value"
   Value="$(AppServiceServer)$(AppServiceVirtualDir)/"
  />
  <XmlUpdate
   Namespace="
http://schemas.microsoft.com/.NetConfiguration/v2.0"
   XmlFileName="$(SourceDir)\Core\ABSuite\GenesisAppServer\WebService\Web.config"
   Xpath="//configuration/appSettings/add[@key='Main.ConnectionString']/@value"
   Value="$(DatabaseConnectionString)"
  />
  <XmlUpdate
   Namespace="
http://schemas.microsoft.com/.NetConfiguration/v2.0"
   XmlFileName="$(SourceDir)\Core\ABSuite\GenesisAppServer\WebService\Web.config"
   Xpath="//configuration/appSettings/add[@key='CatalogNameToUse']/@value"
   Value="$(DatabaseName)"
  />
  <XmlUpdate
   Prefix="n"
   Namespace="
http://schemas.microsoft.com/.NetConfiguration/v2.0"
   XmlFileName="$(SourceDir)\Core\ABSuite\GenesisAppServer\WebService\Web.config"
   Xpath="//n:configuration/n:appSettings/n:add[@key='Server.Version']/@value"
   Value="$(Major).$(Minor).$(Build).$(Revision)"
  />
  <XmlUpdate
   Prefix="n"
   Namespace="
http://schemas.microsoft.com/developer/msbuild/2003"
   XmlFileName="$(SourceDir)\Core\ABSuite\ABClient\ABClient.csproj"
   Xpath="/n:Project/n:PropertyGroup/n:PublishUrl"
   Value="$(ClickOnceServer)$(ClickOnceVirtualDir)/"
  />
  <XmlUpdate
   Prefix="n"
   Namespace="
http://schemas.microsoft.com/developer/msbuild/2003"
   XmlFileName="$(SourceDir)\Core\ABSuite\ABClient\ABClient.csproj"
   Xpath="/n:Project/n:PropertyGroup/n:BootstrapperComponentsUrl"
   Value="$(ClickOnceServer)$(ClickOnceVirtualDir)/"
  />
  <XmlUpdate
   Prefix="n"
   Namespace="
http://schemas.microsoft.com/developer/msbuild/2003"
   XmlFileName="$(SourceDir)\Core\ABSuite\ABClient\ABClient.csproj"
   Xpath="/n:Project/n:PropertyGroup/n:ApplicationVersion"
   Value="$(Major).$(Minor).$(Build).$(Revision)"
  />
 </Target>

 

 

 

 

TableLayoutPanel positioning and controlcell relationships

I've been working with the Windows Forms 2.0 TableLayoutPanel, have run into some stumbling blocks, and was hoping somebody can help.

1) There doesn't appear to be a way to equate controls with their cell position. I have a need to determine where “this.txtFirstName” is in the row 3, cell 4 position.

2) There doesn't appear to be a way to get the location of a cell, short of calculating the offset, which I've done.

Is there some way to dig into the panel, maybe using reflection or something, to get the internal relationship between cells and controls, and the cell locations?

Thanks in advance!

Code snippet for event handler

Code snippets are pretty neat. Here's the first one I've created. It sets up a custom event and a handling routine. To use it, you'll need to download the .snippet file because uploading the code into the blog proved to be too much of a pain.

You can import the snippet with Tools->Manage Code snippets, or just put the file in C:\Program Files\Microsoft Visual Studio 8\VC#\Snippets\1033\Visual C#