Archive

Archive for the ‘General Development’ Category

Creating Local Git Repositories – Yeah, it’s that simple!

We’re in the process of evaluating several source control systems here at the office.  It’s a JOYOUS experience and I mean that… sorta.  Currently, we have a montage of files dumped into two SourceSafe repos.

At this point, most of you are either laughing, crying, or have closed your web browser so you don’t get caught reading something with the word ‘SourceSafe’ in it.  That’s cool, I get that.

As part of my demonstrations (for the various toolings we’re looking at), I wanted to show how simple it was to create a local GIT repository.

Since I’m discussing ‘local’, I’m taking a lot of things out of the picture.

  • Authentication/authorization is handled by Windows file permissions/Active Directory.  If you can touch the repo and read it, then knock yourself out.
  • Everything is handled through shares, no HTTP or that goodness.  Users are used to hitting a mapped drive for SourceSafe repos, we’re just emulating that.

So what do we need to do to create a Git repository? Three easy steps (commands).

1. Create your directory with the .git extention.

mkdir example.git

2. Change into that new directory.

cd example.git

3. Initialize the repository using Git.

git init —bare

Our new Git repository is now initialized. You can even see that PowerShell picks up on the new repository and has changed my prompt accordingly.

Local Git Repository - example.git

Now that we have example.git as our ‘remote’ repository, we’re ready to make a local clone.

git clone H:\example.git example

Now we have an empty clone (and it’s kind enough to tell us).

Empty clone.

All of our Git goodness is packed into the standard .git directory.

Git clone contents.

To test things out, let’s create a quick file, add it to our repo, and then commit it in.

First, let’s create/append an example file in our clone.

Create/append an example file to Git

(note: this is called ‘so lazy, I don’t even want to open NotePad’)

Now, we can add and verify that our newly added ‘example.text’ file shows up:

Git - add file and verify

Finally, commit…

git commit -a -m “this is our first commit”

First commit

… and push!

git push origin master

Push to origin repo.

The last step is to ensure that our new ‘remote’ repository can be reproduced.  Here’s a quick single line to clone our repository into another new folder, list out the contents, and verify the log has the commit we made in the first repo.

Finished Second Clone to Verify

It’s amazing how quick and easy it is to setup local Git repositories.  From here, we can look at the file system/Windows for authentication/authorization and focus on our migration AWAY from Visual SourceSafe. :)

Tags: ,

PowerShell : TGIF Reminder

November 6, 2009 David Longnecker 1 comment

Jeff Hicks’ TGIF post yesterday was a fun way to learn a bit of PowerShell (casting, working with dates, etc) and also add something valuable to your professional toolbelt—knowing when to go home. :)

I tweaked the date output a bit to be more human readable, but also moved it from just a function to part of my UI.  I mean, I should ALWAYS know how close I am to quittin’ time, right? Especially as we joke around our office during our ‘payless weeks’.

# Determines if today is the end of friday! (fun function)
function get-tgif {
 $now=Get-Date
 # If it’s Saturday or Sunday then Stop! It’s the weekend!
 if ([int]$now.DayOfWeek -eq 6 -or [int]$now.DayOfWeek -eq 7)
 {
  ”Weekend!”
 }
 else {
  # Determine when the next quittin’ time is…
  [datetime]$TGIF=”{0:MM/dd/yyyy} 4:30:00 PM” -f `
   (($now.AddDays( 5 – [int]$now.DayOfWeek)) )
  
  # Must be Friday, but after quittin’ time, GO HOME!
  if ((get-date) -ge $TGIF) {
   ”TGIF has started without you!”
  }
  else {
   # Awww, still at work–how long until
   # it’s time to go to the pub?
   $diff = $($tgif – (get-date))
   ”TGIF: $($diff.Days)d $($diff.Hours)h $($diff.Minutes)m”
  }
 }
}

NOTE: My “end time” is set to 4:30PM, not 5:00PM—since that’s when I escape.  Change as necessary. ;)

The code comments explain most of it.  As you can see, I added in one more check—let me know when it’s simply the weekend.  I also removed the Write-Host calls, since I simply want to return a String from the function.  I could use the function, as necessary, with formatting, and add it to other scripts and such.  For example:

Write-Host $(get-tgif) -fore red

The next step was tapping into the $Host variable.  Since I use Console2, my PowerShell window is a tab rather than the whole window.  Console2 is aware of PowerShell’s $Host.UI methods and adheres to the changes.

To add get-tgif to my prompt’s window title:

$windowTitle = “(” + $(get-tgif) + “) “
$host.ui.rawui.WindowTitle = $windowTitle

Easy enough.  Now my window title looks like (ignore the path in there for now):

TGIF countdown in WindowTitle

But that only sets it when you log in… and I want to update it (and keep that path updated as I traverse through directories).  To do that add a function called ‘prompt’ to your PowerShell Profile.  Prompt is processed every time the “PS>” is generated and allows you a great deal of customization.  See the post here for further details on how I’ve customized my prompt to handle Git repositories.

So, move those two lines into our prompt function, and our TGIF timer now updates every time our prompt changes… keeping it pretty close to real time as you work.

function prompt {
 $windowTitle = “(” + $(get-tgif) + “) ” + $(get-location).ToString()
 $host.ui.rawui.WindowTitle = $windowTitle

[…]

}

This could be tweaked to any type of countdown.  I’m sure a few of those around the office would have fun adding retirement countdowns, etc. ;)

Happy TGIF!

Automating Extracts Using External .SQL Files and PowerShell

September 29, 2009 David Longnecker Leave a comment

Rather than rely on a system task, I wanted to be able to kick off an export of one of our SQL databases on the fly, have it generate a CSV, then email the CSV to one of our developers.

Sounds like a task for PowerShell!

Why PowerShell? Well, frankly, because moving jobs around and such on our mixed-mash of SQL versions and servers is a bit annoying and I wanted to see if it worked.

So, to start off, I have a file, call it export_data.sql that contains all of the logic of my SQL query and the format I require.

I’ll also be using the Microsoft SQL query script I discussed in this blog post.

The tricky part is reading in the .sql file as a single “entity”—not the array of rows that get-content usually provides.  Thankfully, there is an easy way to do it.

@(gc ‘export_data.sql’ -readcount 0)

According to the PowerShell documentation, the readcount parameter serves two purposes: one is to set the number of lines to read at a time, the second (when set to zero) is to pull in all of the lines at once.  Great, that’s exactly what we need.

From there, it’s simply feeding our query to the sql-query function I wrote and exporting to CSV.  Nice enough, CSV exports are built-in to PowerShell!

The final command looks something like this:

@(gc ‘export_data.sql’ -readcount 0) | 
   % { sql-query server db $_ } |
   export-csv dump.csv

I could then add another field to mail the csv using the built-in command Send-MailMessage.

<3 PowerShell.

ASP.NET Development Server From ‘Here’ in PowerShell

September 9, 2009 David Longnecker Leave a comment

Long title… almost longer than the code.

I used to have an old registry setting that started up the ASP.NET Development Server from the current path; however, since I rarely open up Explorer—and then opening up FireFox was even more painful—I needed a script.

What does it do?

The script starts up the ASP.NET Development server with a random port (so you can run multiples…) at your current location.  It then activates your machine’s DEFAULT BROWSER and browses to the site.  FireFox user?  No problem.  Works like a champ!

The Script (Full Code)

$path = resolve-path .
$rand = New-Object system.random
$port = $rand.next(2048,10240)
$path_to_devserver = “C:\\Program Files (x86)\\Common Files\\microsoft shared\\DevServer\\9.0\\Webdev.WebServer.exe”

& $path_to_devserver /port:$port /path:$path
(new-object -com shell.application).ShellExecute(“http:\\localhost:$port”)

The $path_to_devserver can be updated—depending on 64–bit vs. 32–bit machines.  Simple, easy, and to the point.  Now, no more fumbling around to launch a quick web application!

Ramping up with PSake

September 8, 2009 David Longnecker Leave a comment

I’ve been tetering back and forth with PSake and my trusty NAnt scripts for quite a while now.  For those not familiar with PSake, it’s build automation that makes you drunk—but in a good way. ;)   You can read James Kovacs’ original post here or check out the repository here for the latest bits.

I originally looked at rake scripts (after exposure working with Fluent NHibernate) as PowerShell is loathed in our organization—or was.  That mindset is slowly changing (being able to show people how to crank out what was originally scoped at a week in two lines of PowerShell script helps out); so I’m using PSake as further motivation.

My prior PSake scripts were a bit tame.  Launch msbuild, copy a few files.  With the latest release of xUnit 1.5 hitting the wires over the weekend (and a much needed x86 version for my poor, cranky Oracle libraries), I decided to bite the bullet and dig in to PSake.

I had two goals:

  1. Build a reliable framework “default.ps1” file that I could drop into almost any project and configure with little or no effort.
  2. Compile, test, and rollout updates from a single PSake command task.

I borrowed the basic layout from Ayende’s Rhino Mocks PSake; however, I couldn’t get msbuild to run correctly simply by calling it.

Here’s what I ended up with for our internal core library.  The core library, isn’t so much a “utilities” container, but just as it sounds—the framework all of our applications are built on to keep connections to our various applications (HR, student systems, data warehouses, etc) consistant as well as hold our base FNH conventions.

CODE: Full code available on CodePaste.NET

Properties

The properties area holds all of the configuration for the PSake script.  For me, it’s common to configure $solution_name, $libraries_to_merge, and $libraries_to_copy.  With our naming standards, the $test_library should be left unchanged.  I also added in the tester information so we could change from XUnit to MBUnit (if Hell froze over or something)).

properties {

 

  # ****************  CONFIGURE ****************

       $solution_name =           “Framework”

       $test_library =            “$solution_name.Test.dll”

 

       $libraries_to_merge =      “antlr3.runtime.dll”, `

                                  “ajaxcontroltoolkit.dll”, `

                                  “Castle.DynamicProxy2.dll”, `

                                  “Castle.Core.dll”, `

                                  “FluentNHibernate.dll”, `

                                  “log4net.dll”, `

                                  “system.linq.dynamic.dll”, `

                                  “xunit.dll”, `

                                  “nhibernate.caches.syscache2.dll”, `

                                  “cssfriendly.dll”, `

                                  “iesi.collections.dll”, `

                                  “nhibernate.bytecode.castle.dll”, `

                                  “oracle.dataaccess.dll”

      

       $libraries_to_copy =       “system.data.sqlite.dll”

 

       $tester_directory = “j:\shared_libraries\xunit\msbuild”

       $tester_executable = “xunit.console.x86.exe”

       $tools_directory =         “$tools”

       $base_directory  =         resolve-path .

       $thirdparty_directory =    “$base_directory\thirdparty”

       $build_directory =         “$base_directory\build”

       $solution_file =           “$base_directory\$solution_name.sln”

       $release_directory =       “$base_directory\release”

}

Clean and easy enough.  You’ll notice that $libraries_to_merge and $libraries_to_copy are implied string arrays.  That works out well since string arrays end up as params when passed to commands… and our $libraries_to_copy can be iterated over later in the code.

Tasks – Default

task default -depends Release

The default task (if just running ‘psake’ without parameters) runs Release.  Easy enough.

Tasks – Clean

task Clean {

  remove-item -force -recurse $build_directory -ErrorAction SilentlyContinue | Out-Null

  remove-item -force -recurse $release_directory -ErrorAction SilentlyContinue | Out-Null

}

Clean up those build and release directories.

Tasks – Init

task Init -depends Clean {

    new-item $release_directory -itemType directory | Out-Null

    new-item $build_directory -itemType directory | Out-Null

    cp $tester_directory\*.* $build_directory

}

Restore those build and release directories that we cleaned up; then copy in our unit testing framework so we can run our tests (if necessary).

Tasks – Compile

task Compile -depends Init {

       # from http://poshcode.org/1050 (first lines to get latest versions)

       [System.Reflection.Assembly]::Load(‘Microsoft.Build.Utilities.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’) | Out-Null

       $msbuild = [Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFrameworkFile(“msbuild.exe”, “VersionLatest”)

      

       # adding double slash for directories with spaces. Stupid MSBuild.

       &$msbuild /verbosity:minimal /p:Configuration=”Release” /p:Platform=”Any CPU” /p:OutDir=”$build_directory”\\ “$solution_file”

}

Compile is a bit tricky.  As noted in the code, I ended up using a SharePoint example from PoSH code to get MSBuild to behave.  The standard exec methodology provided by PSake kept ignoring my parameters.  Maybe someone has an good reason.. but this works.

You also see that my OutDir has TWO slashes.  It seems that directories with spaces require the second.  I’m sure this will somehow bite me later on, but it seems to be working for now. ;)

Tasks – Test

task Test -depends Compile {

  $origin_directory = pwd

  cd $build_directory

  exec .\$tester_executable “$build_directory\$test_library”

  cd $origin_directory       

}

I want to thank Ayende for the idea to dump the origin directory into a parameter—brilliant.  This one is pretty simple—just calls the tester and tests.

Tasks – Merge

task Merge {

       $origin_directory = pwd

       cd $build_directory

      

       remove-item “$solution_name.merge.dll” -erroraction SilentlyContinue

       rename-item “$solution_name.dll” “$solution_name.merge.dll”

      

       & $tools\ilmerge\ilmerge.exe /out:”$solution_name.dll” /t:library /xmldocs /log:”$solution_name.merge.log” `

              “$solution_name.merge.dll” $libraries_to_merge

                          

       if ($lastExitCode -ne 0) {

              throw “Error: Failed to merge assemblies!”

       }

       cd $origin_directory

}

Merge calls ILMerge and wraps all of my libraries into one.  Do I need to do this?  Nah, but for the framework, I prefer to keep everything together.  I don’t want to be chasing mis-versioned libraries around.  Again, since $libraries_to_merge is a string array, it passes each “string” as a separate parameter—which is exactly what ILMerge wants to see.

I also have ILMerge generate and keep a log of what it did—just to have.  Since the build directory gets blown away between builds (and isn’t replicated to source control), then no harm.  Space is mostly free. ;)

Tasks – Build & Release

task Build -depends Compile, Merge {

       # When I REALLY don’t want to test…

}

 

task Release -depends Test, Merge {

       copy-item $build_directory\$solution_name.dll $release_directory

       copy-item $build_directory\$solution_name.xml $release_directory

      

       # copy libraries that cannot be merged

       % { $libraries_to_copy } | %{ copy-item (join-path $build_directory $_) $release_directory }

      

}

Build provides just that—building with no testing and no copying to the release directory.  This is more for testing out the scripts, but useful in some cases.

Release copies the library and the xml documentation out ot the release directory.  It then iterates through the string array of “other” libraries (non-manged code libraries that can’t be merged, etc) and copies them as well.

 

 

 

Rendering the Web Equally on Mobile Devices

June 26, 2009 David Longnecker Comments off

I’ve been digging through the Interwebs for a while now and, I thought, had worked out all of the “kinks” of rendering on a mobile device—specifically iPhones.

The special ‘viewport’ meta tag means the world to iDevices.

meta name=“viewport” content=“width = device-width” />

I’m faced with a new challenge—the Palm Pre’s built-in web browser.  My shiny new phone is great, but it isn’t without glitches.

The first glitch I’ve found appears to be a DNS issue— http://myserver/web won’t resolve; however, http://123.45.67.89/web will.  It seems to be touchy.  Most of our webs work just fine, others don’t.  I haven’t narrowed it down to a single server or architecture as it seems to be a bit of everything.  Wonky.

The next glitch is more important—the rendering.  One of our tools is a simple form-based tool that looks great on the iPhone; however, renders partial screen and “garbles” when you move around the screen.

Palm Pre:

Garbled image

iTouch/iPhone:

I’ve also found that anything in an ASP.NET Update Panel (like those Select buttons) are unusable.  Other webs I’ve used (Bank of America, etc) use AJAX just fine, so I don’t think it’s that—probably a coding issue I need to dig into and resolve.

UPDATE: Explicitly adding “LoadScriptsBeforeUI=’true’” to the ASP.NET ScriptManager seems to help with this.. a little.

Anyone else worked specifically with the Pre devices and rendering?  I’d appreciate any meta tags or layout ideas that worked. :)   The Pre isn’t a common device in our organization—yet.

Auto Incrementing Visual Studio Project Versions

March 9, 2009 David Longnecker Comments off

I’m not using NAnt or anything fancy for most of my projects—so I needed a simple, MSBuild way to automate my version numbers in a project..

<tangent>
HOLY CRAP! Why isn’t this built into Visual Studio Pro?
</tangent>

Here we go:

1. Download the latest build of AssemblyInfoTask (download here) (was 1.0.51130.0 for me).  This is a semi-Microsoft supported MSBuild task that gives you a lot of flexibility over your AssemblyInfo.cs files.

2. Install AssemblyInfoTask.  When prompted where—install into the GAC.  If you don’t have access to the GAC on your workstation, then why aren’t you developing on a VM? ;)

3. Locate the Microsoft.VersionNumber.targets file.  If you installed to the GAC, it should be at %ProgramFiles(x86)%\MSBuild\Microsoft\AssemblyInfoTask Or %ProgramFiles%\MSBuild\Microsoft\AssemblyInfoTask (depending on your architecture).

4. Copy the Microsoft.VersionNumber.targets file into a location in your solution or project.  I recommend $(SolutionDir) so you can share it amongst all of your projects.  The guilde recommend pointing to the file directly; however, you can’t modify the base Major versions that way (without setting the same major version for ALL projects you ever work on).  You can also rename it as approprate.

“Int16s Are Too Small” Or “Why 2007 Broke Versioning” Fix

According to experts who are much smarter than me, the build version numbers are Int16s—meaning 65535 caps out the number.  Unfortunately, the year 2007 breaks this (070101 or 70101 for 07 jan 01) doesn’t fit within an Int16.  Stellar.

The MSBuild team recommended taking out the year and simply placing a 1 infront of it.  That works; however, I really like having the year in there somewhere.

For me, I’ve placed the year into the MinorVersion.  After reviewing most of our practices, the minor version for most of our projects changes with annual maintenance OR not at all (we bump the major version).  This, if nothing else, will help standardize when it changes. :)   As always, YMMV.

No matter which solution you choose, you’ll need to remove the year from the BuildNumberFormats.

In your Targets file, you can change the two lines to report out the MMdd (0309, for example, today) to work around the bug.  I’ve bolded the two lines below.  As you can see, I also added the “9” to the MinorVersion to represent 2009. 

<PropertyGroup>

  <AssemblyMajorVersion>3</AssemblyMajorVersion>

  <AssemblyMinorVersion>9</AssemblyMinorVersion>

  <AssemblyBuildNumber></AssemblyBuildNumber>

  <AssemblyRevision></AssemblyRevision>

  <AssemblyBuildNumberType>DateString</AssemblyBuildNumberType>

  <AssemblyBuildNumberFormat>MMdd</AssemblyBuildNumberFormat>

  <AssemblyRevisionType>AutoIncrement</AssemblyRevisionType>

  <AssemblyRevisionFormat>00</AssemblyRevisionFormat>

</PropertyGroup>

 

<!– Properties for controlling the Assembly File Version –>

<PropertyGroup>

  <AssemblyFileMajorVersion>3</AssemblyFileMajorVersion>

  <AssemblyFileMinorVersion>9</AssemblyFileMinorVersion>

  <AssemblyFileBuildNumber></AssemblyFileBuildNumber>

  <AssemblyFileRevision></AssemblyFileRevision>

  <AssemblyFileBuildNumberType>DateString</AssemblyFileBuildNumberType>

  <AssemblyFileBuildNumberFormat>MMdd</AssemblyFileBuildNumberFormat>

  <AssemblyFileRevisionType>AutoIncrement</AssemblyFileRevisionType>

  <AssemblyFileRevisionFormat>00</AssemblyFileRevisionFormat>

</PropertyGroup>

 

This results in a version string that looks like 3.9.0309.{increment}.

5. Open up your project’s solution and unload the project you are wanting to auto-increment. Towards the end of the file, you’ll see the default MSBuild C# build path; add the location to your new .targets file in your solution directory.

<Import Project=$(SolutionDir)MyProject.VersionNumber.targets />

7. Save and Close and Reload the project.

8. Build/Rebuild your project and the AssemblyInfo.cs should set to the specified increment scheme.

You’re done!

“Too Many WebResources?” Fix 

My project references numerous resources for images and style sheets; however, having these inside of AssemblyInfo.cs seems to cause it to go haywire and throw array errors (assumingly because there is more than one [assembly:WebResource()] call).

To fix this, I moved my WebResources out of AssemblyInfo.cs and into a new file under Properties called WebResources (Add New Item > Assembly Information File).  Strip out everything except the WebResources you copy in and the project now compiles like a champ.

For additional setup details and options within the .targets files, the AssemblyInfoTask installer comes with a CHM help file that covers additional customizations available.

Part 2: Converting Generic Collections to CSVs

February 6, 2009 David Longnecker 1 comment

Part 1 | Part 2

In my last post, I wrote up the tests needed to meet our customer’s requirements, now I’m ready to flush out the tests.

Objective #1 – Export Collection to CSV With All Properties

Each of my tests implement one of two extension methods, ToDelimitedFile and ToDelimitedRow.  Collections focus on File whereas objects (singles) use the Row. 

Unfortunately, I couldn’t find a 100% accurate way to use the generic constraints—too bad we can’t put in “where T : !ICollection<T>”  Hence the separate methods.

For me, extension methods sit outside of my actual classes in their own happy static {whatever}Extensions class.  The CSV Conversions are no different.

For Test #1 to pass, we need to implement the extension method.

public static string ToDelimitedFile<T>(this ICollection<T> convertible)

{

       return DelimitedExporter.SerializeCollection(convertible);

}

This paves the way for creating our next class and method, DelimitedExporter and SerializeCollection.  The DelimitedExporter class will contain all of the methods and logic for converting our collections into CSV “lines”.  Let’s implement SerializeCollection real quick with some dummy data and rerun the test.

public static string SerializeCollection<T>(ICollection<T> convertible)

{

       return “Name,Level”;

}

Pass!  Test passes!

Now, of course, since the test passes, we’re ready to flush out the details of the SerializeCollection method.

Creating the Header Rows

Since we know we’ll be working with strings and doing a large number of appends, let’s start out by creating a StringBuilder to hold all of that text information.

public static string SerializeCollection<T>(IEnumerable<T> convertible)

{

       var stringBuilder = new StringBuilder();

 

       //grab properties of the method to create columns

       var columns = typeof(T).GetProperties();

 

GetProperties is a method on Type that returns all public properties as PropertyInfo objects.  These properties will be used to create the column header names for our CSV.

       // build header row

       stringBuilder.Append(BuildHeaderRowFrom(columns));

 

So let’s “build” our header row.  I’ve extracted this into a separate method from the start—you could have one mega method and refactor it down later.

 

private static string BuildHeaderRowFrom(IEnumerable<PropertyInfo> columns)

{

       var headerString = string.Empty;

       var counter = 0;

       foreach (PropertyInfo column in columns)

       {

              counter++;

             headerString += column.Name;

             if (counter != columns.Count)

                     headerString += “,”;

       }

       headerString += Environment.NewLine;

 

       return headerString;

}

The BuildHeaderRowFrom method takes the PropertyInfo enumeration from our GetProperties() call and iterates through it, capturing the Name of each property and appending it to a string.

Let’s close up the SerializeCollection() method …

       return stringBuilder.ToString();

}

… and run the test again and everything should pass up to this point.

Now we can focus on the data rows.

Creating the Data Rows

Our next task in SerializeCollection is to flush out how each enumerable object will be converted into a row in our CSV.

After our BuildHeaderRowsFrom() method, let’s now append the data rows with:

       // build item rows

       stringBuilder.Append(BuildDataRowsFrom(collection, columns));

BuildDataRowsFrom will take the original collection of objects (an IEnumerable<T>) and the columns we parsed for the header as parameters.

private static string BuildDataRowsFrom<T>(

       IEnumerable<T> collection,

       IEnumerable<PropertyInfo> columns)

{

       var rowString = string.Empty;

       foreach (T item in collection)

       {

              int counter = 0;

              var columnCount = columns.Count();

             foreach (PropertyInfo column in columns)

             {

                     counter++;

                     var value =

                           column.GetValue(item, null) ?? string.Empty;

 

                     // Append column value to the row.

                     rowString += “{0}”.AsFormatFor(value);

 

                     // Append delimiter if _not_ the last column.

                     if (counter != columnCount)

                           rowString += “,”;

              }

              rowString += Environment.NewLine;

       }

       return rowString;

}

Note: I could use a StringBuilder inside of this; however, the StringBuilder seemed to take a bit longer with the tests of 50,000ish records (max in the system I was designing this for).  A later revision may be to further examine ways to improve performance.

 

So, what’s all this do?

 

For the most part, it reads as a sentence:  For each item in the collection, loop through each known column and fetch the value from that item.  If the item is null, simply return an empty string. 

 

Since I’m using IEnumerable<T> rather than ICollection<T>, I don’t have access to a Count property (without calling the Linq extension method, so I’ve moved that outside of the foreach loop.  Perhaps there’s a better generic collection to be using, but that’s for later revisions.

 

Again, run our test again, and it should pass AND we should now have data.

 

can_convert_list_of_objects_to_csv : Passed

*** ConsoleOutput ***
Name,Level
SchoolA,Elementary
SchoolB,Elementary
SchoolC,Elementary
SchoolD,Elementary

 

Excellent.

 

That’s it for this post.  In the next part, I’ll start in on the second objective—being able to specify which parameters are picked up by the DelimitedExporter.

 

 

Part 1: Converting Generic Collections To CSVs

February 6, 2009 David Longnecker 1 comment

I recently had a request to allow “exports” of lists from one application to the user in CSV (comma separated value) format.  After a bit of dinking, here’s what I came up with; however, I’m sure a bit more work will find that it’s overkill. :)

Starting Off With The Tests

So what did I want to accomplish?  I had three objectives:

  1. Export a collection of objects (IList, ICollection, IEnumerable, etc) to CSV with all “properties”.
  2. Export a collection and be able to specify the properties to export.
  3. (optional) Export a single object to CSV with the same two requirements above (1, 2).

#1:

[Fact]

public void can_convert_list_of_objects_to_csv()

{

       var repository = new SchoolRepository();

       var schools = repository.GetBySchoolLevel(Level.Elementary);

 

       var csvOutput = schools.ToDelimitedFile();

 

       // check that the CSV has the headers

       // of the properties of the object

       csvOutput.ShouldContain(“Name,Level”);

}

#2:

[Fact]

public void can_convert_list_of_objects_to_csv_with_parameters()

{

       var repository = new SchoolRepository();

       var schools = repository.GetBySchoolLevel(Level.Elementary);

      

       var csvOutput = schools.ToDelimitedFile(“Name”);

       csvOutput.ShouldContain(“Name”);

 

       Console.Write(csvOutput);

}

#3:

[Fact]

public void can_convert_a_single_object_to_csv()

{

       var repository = new SchoolRepository();

       var school = repository.Get(120);

 

       var csvOutput = school.ToDelimitedRow();

       csvOutput.ShouldContain(“Great School,High”);

 

       Console.Write(csvOutput);

}

In the next post, we’ll begin flushing out our tests.

 

 

Refining the MSDN Search

December 4, 2008 David Longnecker Comments off

Earlier this year, I participated in a dig into the new features of the MSDN/TechNet “enhanced” search engine.  You can read my original review here or check out Chris’ summary of our reviews here.

I had time this morning to sit down and check out the renovations to the site, based on our (and the community’s) feedback, and am very impressed. 

1. Originally, I had a bit of issue that I couldn’t pre-refine my topics from the original search page; I still can’t.  That’s a downer.  However, the new “Related To” links are fantastic and add a nice layer of filtering to the results.  Previously, you clicked a refinement and had to have blind faith on which articles would get filtered—now you can actually filter “like” articles, which I like.

2. The site seems to work MUCH better in FireFox—autocomplete and all.  The browser-integrated search even works well in FireFox.  Awesome.

3. The original test of the MSDN search had quite a bit of traffic running back and forth and a heafty payload; however, it looks like they’ve cut both the number of requests and size down (30 requests to 6 and 187k to 25k payload). 

Request Count:  6
Bytes Sent:  5,547
Bytes Received: 25,106

ACTUAL PERFORMANCE
————–
Requests started at: 10:53:36:7301
Responses completed at: 10:53:38:9341
Total Sequence time: 00:00:02.2040000
DNS Lookup time: 125ms
TCP/IP Connect time: 234ms

RESPONSE BYTES (by Content-Type)
————–
image/gif: 1,135
 ~headers: 2,653
text/html: 21,318

There’s still a bit of traffic for the auto complete boxes and refinements seem to be total refreshes rather than on-the-fly filters, but it works quite nicely.  Results also come back pretty darn quick—almost Google quick!  I’ll, personally, live with a bit of the speed to keep the RSS resultset feeds. :)

4. They updated the TITLE tags on the results to list the search query FIRST.  That is stellar and greatly appreciated.

Updated MSDN Search Puts Query First!

5. I originally had an issue with how the search results parsed language and version of documentation.  It looks like they’ve gotten around that by removing the language refinements all together and focus on “.NET Framework {ver} Library”.  This also solves the issue of wondering what version the documentation is pointing to and allows additional refinement. Cool.

Versioning of Documentation Now Very Visible

The updates are definate winners—increases in performance and usability.  Thanks to Chris and his team for their continued work!