NuGet Package Restore, Multiple Repositories, and CI Servers
I really like NuGet’s new Package Restore feature (and so does our git repositories).
We have several common libraries that we’ve moved into a private, local NuGet repository on our network. It’s really helped deal with the dependency and version nightmares between projects and developers.
I checked my first project using full package restore and our new local repositories into our CI server, TeamCity, the other day and noticed that the Package Restore feature couldn’t find the packages stored in our local repository.
At first, I thought there was a snag (permissions, network, general unhappiness) with our NuGet share, but all seemed well. To my surprise, repository locations are not stored in that swanky .nuget directory, but as part of the current user profile. %appdata%\NuGet\NuGet.Config to be precise.
Well, that’s nice on my workstation, but NETWORK SERVICE doesn’t have a profile and the All Users AppData directory didn’t seem to take effect.
The solution:
For TeamCity, at least, the solution was to set the TeamCity build agent services to run as a specific user (I chose a domain user in our network, you could use a local user as well). Once you have a profile, go into %drive%:\users\{your service name}\appdata\roaming\nuget and modify the nuget.config file.
Here’s an example of the file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="NuGet official package source" value="https://msft.long.url.here" />
<add key="Student Achievement [local]" value="\\server.domain.com\shared$\nuget" />
</packageSources>
<activePackageSource>
<add key="NuGet official package source" value="https://msft.long.url.here" />
</activePackageSource>
</configuration>
Package Restore will attempt to find the packages on the ‘activePackageSource’ first then proceed through the list.
Remember, if you have multiple build agent servers, this must be done on each server.
Wish List: The option to include non-standard repositories as part of the .nuget folder.
Workaround: Oracle, NHibernate, and CreateSQLQuery Not Working

It’s difficult to sum this post up with a title. I started the morning adding (what I thought to be) a trivial feature to one of our shared repository libraries.
By the time I saw light at the end of the rabbit hole, I wasn’t sure what happened. This is the tale of my journey. All of the code is is guaranteed to work on my machine… usually.
I’ve done this before–how hard could it be?
The full source code is available via a gist.
The initial need
A simple need really: take a complex query and trim it down to a model using NHibernate’s Session.CreateSQLQuery and Transformers.AliasToBean<T>.
The problems
So far, the only data provider I’ve had these problems with is Oracle’s ODP: Oracle.DataAccess. I’m not sure if the built-in System.Data.OracleClient.
Problem #1 – Why is EVERYTHING IN CAPS?
The first oddness I ran into seemed to be caused by the IPropertyAccessor returning the properties in ALL CAPS. When it tried to match the aliases in the array, [FIRSTNAME] != [FirstName]. Well, that’s annoying.
Workaround: Add an additional PropertyInfo[] and fetch the properties myself.
This method ignores the aliases parameter in TransformTuple and relies on a call in the constructor to populate the Transformer’s properties.
public OracleSQLAliasToBeanTransformer(Type resultClass)
{
// [snip!]
// this is also a PERSONAL preference to only return fields that have a valid setter.
_fields = this._resultClass.GetProperties(Flags)
.Where(x => x.GetSetMethod() != null).ToArray();
}
Inside TransformTuple, I then call on _fields rather than the aliases constructor parameter.
var fieldNames = _fields.Select(x => x.Name).ToList();
// [big snip!]
setters = new ISetter[fieldNames.Count];
for (var i = 0; i < fieldNames.Count; i++)
{
var fieldName = fieldNames[i];
_setters[i] = _propertyAccessor.GetSetter(_resultClass, fieldName);
}
Problem solved. Everything is proper case.
Bold assumption: I’m guessing this is coming back in as upper case because Oracle, by default, stores and retrieves everything as upper case unless it’s surrounded by quotes (which has it’s own disadvantages).
Problem #2 – Why are my ints coming in as decimals and strings as char[]?
This one I’m taking a wild guess. I found a similar issue for Hibernate (Java daddy of NHibernate), but didn’t see a matching NHibernate issue. It seems that the types coming in are correct, but the tuple data types are wrong.
For example, if an object as a integer 0 value, it returns as 0M and implicitly converts to decimal.
Workaround: Use System.Convert.ChangeType(obj, T)
If I used this on every piece of code, I’d feel more guilty than I do; however, on edge cases where the standard AliasToBeanTransformer won’t work, I chalk it up to part of doing business with Oracle.
Inside the TransformTuple method, I iterate over the fields and recast each tuple member accordingly. The only caveat is that I’m separating out enums and specifically casting them as int32. YMMV.
var fieldNames = _fields.Select(x => x.Name).ToList();
for (var i = 0; i < fieldNames.Count; i++)
{
var fieldType = _fields[i].PropertyType;
if (fieldType.IsEnum)
{
// It can't seem to handle enums, so convert them
// to Int (so the enum will work)
tuple[i] = Convert.ChangeType(tuple[i], TypeCode.Int32);
}
else
{
// set it to the actual field type on the property we're
// filling.
tuple[i] = Convert.ChangeType(tuple[i], fieldType);
}
}
At this point, everything is recast to match the Type of the incoming property. When all is said and done, adding a bit of exception handling around this is recommended (though, I’m not sure when a non-expected error might pop here).
Problem solved. Our _setters[i].Set() can now populate our transformation and return it to the client.
Summary
Lessons learned? Like Mr. Clarkson usually discovers, when it sounds easy, it means you’ll usually end up on fire. Keep fire extinguishers handy at all times.
Is there another way to do this? Probably. I could probably create a throwaway DTO with all capital letters then use AutoMapper or such to map it to the properly-cased objects. That, honestly, seems more mindnumbing than this (though perhaps less voodoo).
Posting to Campfire using PowerShell (and curl)
I have a few tasks that kick off nightly that I wanted to post status updates into our team’s Campfire room. Thankfully, 37signals Campfire has an amazing API. With that knowledge, time to create a quick PowerShell function!
NOTE: I use curl for this. The Linux/Unix folks likely know curl, however, I’m sure the Windows folks have funny looks on their faces. You can grab the latest curl here for Windows (the Win32 or Win64 generic versions are fine).
The full code for this function is available via gist.
I pass two parameters: the room number (though this could be tweaked to be optional if you only have one room) and the message to post.
param (
[string]$RoomNumber = (Read-Host "The room to post to (default: 123456) "),
[string]$Message = (Read-Host "The message to send ")
)
$defaultRoom = "123456"
if ($RoomNumber -eq "") {
$RoomNumber = $defaultRoom
}
There are two baked-in variables, the authentication token for your posting user (we created a ‘robot’ account that we use) and the YOURDOMAIN prefix for Campfire.
$authToken = "YOUR AUTH TOKEN"
$postUrl = "https://YOURDOMAIN.campfirenow.com/room/{0}/speak.json" -f $RoomNumber
The rest is simply using curl to HTTP POST a bit of JSON back up to the web service. If you’re not familiar with the JSON data format, give this a quick read. The best way I can sum up JSON is that it’s XML objects for the web with less wrist-cutting.
$data = "`"{'message':{'body':'$message'}}`""
$command = "curl -i --user {0}:X -H 'Content-Type: application/json' --data {1} {2}"
-f $authToken, $data, $postUrl
$result = Invoke-Expression ($command)
if ($result[0].EndsWith("Created") -ne $true) {
Write-Host "Error!" -foregroundcolor red
$result
}
else {
Write-Host "Success!" -foregroundcolor green
}
Indeed, there be success!
It’s important to remember that PowerShell IS extremely powerful, but can become even more powerful coupled with other available tools–even the web itself!
Changing Default Printers by Network Subnet
Windows 7 includes a pretty handy feature for mobile devices called location-aware printing. The feature itself is pretty cool and great if you’re moving between two distinct networks (home and work, for example). However, if you’re moving within the SAME network–and the SAME wireless SSID, it doesn’t register a difference. LAP doesn’t pay attention to your IP address, just the SSID you’re connected to.
In our organization, and most large corporations, wireless access points have the same name/credentials so that users can move seamlessly through the enterprise. How can we address location-based printing then?
One of my peers recently moved into a position where they are constantly between two buildings multiple times per day and frequently forgetting to reset their default printer.
Here’s how I helped her out using a bit of PowerShell.
For the full code, check out this gist.
To begin, we need to specify our IP subnets and the printers associated to them. As this gets bigger (say 4-5 sites), it’d be easier to toss this into a separate file as a key-value pair and import it.
$homeNet = "10.1.4.*", "OfficePrinter" $remoteNet = "10.1.6.*", "W382_HP_Printer"
Next, let’s grab all of the IP addresses currently active on our computer. Since we could have both wireless and wired plugged in, this returns an array.
$ipAddress = @()
$ipAddress = gwmi win32_NetworkAdapterConfiguration |
? { $_.IPEnabled -eq $true } |
% { $_.IPAddress } |
% { [IPAddress]$_ } |
? { $_.AddressFamily -eq 'internetwork' } |
% { $_.IPAddressToString }
Write-Host -fore cyan "Your current network is $ipAddress."
Our last step is to switch (using the awesome -wildcard flag since we’re using wildcards ‘*’ in our subnets) based on the returned IPs. The Set-DefaultPrinter function is a tweaked version of this code from The Scripting Guy.
function Set-DefaultPrinter([string]$printerPath) {
$printers = gwmi -class Win32_Printer -computer .
Write-Host -fore cyan "Default Printer: $printerPath"
$dp = $printers | ? { $_.deviceID -match $printerPath }
$dp.SetDefaultPrinter() | Out-Null
}
switch -wildcard ($ipAddress) {
$homeNet[0] { Set-DefaultPrinter $homeNet[1] }
$remoteNet[0] { Set-DefaultPrinter $remoteNet[1] }
default { Set-DefaultPrinter $homeNet[1] }
The full source code (and a constantly updated version available from gist).
$homeNet = "10.1.4.*", "OfficePrinter"
$remoteNet = "10.1.6.*", "W382_HP_Printer"
function Set-DefaultPrinter([string]$printerPath) {
$printers = gwmi -class Win32_Printer -computer .
Write-Host -fore cyan "Default Printer: $printerPath"
$dp = $printers | ? { $_.deviceID -match $printerPath }
$dp.SetDefaultPrinter() | Out-Null
}
$ipAddress = @()
$ipAddress = gwmi win32_NetworkAdapterConfiguration |
? { $_.IPEnabled -eq $true } |
% { $_.IPAddress } |
% { [IPAddress]$_ } |
? { $_.AddressFamily -eq 'internetwork' } |
% { $_.IPAddressToString }
Write-Host -fore cyan "Your current network is $ipAddress."
switch -wildcard ($ipAddress) {
$homeNet[0] { Set-DefaultPrinter $homeNet[1] }
$remoteNet[0] { Set-DefaultPrinter $remoteNet[1] }
default { Set-DefaultPrinter $homeNet[1] }
}
Tip: Using Spark Conditionals to Toggle CSS and JavaScript
The conditional attribute is a fantastic shortcut to toggle CSS, input boxes, and other elements on a page–and is something I don’t see used in very many examples. One of my favorites is applying classes to an element based on a output model property, such as a permission boolean.
Here’s an example.
In a recent project, a dashboard screen had several charts that toggled on and off based on the user’s preference. Rather than rebuild the screen each time, each class simply toggled an ‘enabled’ class based on a Model.{Property}.
<div class="charts">
<div id="enteredbycount" class="loading enabled?{Model.ShowEnteredBy}"
style="inlineChart">
</div>
<div id="schoolcount" class="loading enabled?{Model.ShowSchoolCount}"
style="inlineChart">
</div>
</div>
The Spark Conditional only renders the text preceding the conditional ?{} if the condition is true. In this example, if our Model.ShowSchoolCount returns false, enabled never renders and our chart (due to some styling), remains hidden and never posts back to the server to get the chart data (saving an unnecessary AJAX call).
By toggling a class, you can trigger a certain set of styles, events using JavaScript, or most anything else you can dream up.
Finding TODOs and Reporting in PowerShell
After @andyedinborough shared a blog post on how to report TODOs in CruiseControl.NET, I figured there HAD to be a snazzy way to do this with TeamCity.
I already have TeamCity configured to dump out the results from our Machine.Specifications tests and PartCover code coverage (simple HTML and XML transforms) so another HTML file shouldn’t be difficult. When we’re done, we’ll have an HTML file, so we just need to setup a custom report to look for the file name. For more information on setting up custom reports in TeamCity, checkout this post (step 3 in particular).
Let’s Dig In!
The code! The current working version of the code is available via this gist.
The code is designed to be placed in a file of it’s own. Mine’s named Get-TODO.ps1.
Note: If you want to include this in another file (such as your PowerShell profile), be sure to replace the param() into function Get-TODO( {all the params} ).
The the script parameters make a few assumptions based on my own coding standards; change as necessary:
- My projects are named {SolutionName}.Web/.Specifications/.Core and are inside a directory called {SolutionName},
- By default, it includes several file extensions: .spark, .cs, .coffee, .js, and .rb,
- By default, it excludes several directories: fubu-content, packages, build, and release.
It also includes a couple of flags for Html output–we’ll get to that in a bit.
param(
#this is appalling; there has to be a better way to get the raw name of "this" directory.
[string]$DirectoryMask =
(get-location),
[array]$Include =
@("*.spark","*.cs","*.js","*.coffee","*.rb"),
[array]$Exclude =
@("fubu-content","packages","build","release"),
[switch]$Html,
[string]$FileName = "todoList.html")
Fetching Our Files
We need to grab a collection of all of our solution files. This will include the file extensions from $Include and use the directories from $DirectoryMask (which the default is everything from the current location).
$originalFiles = gci -Recurse -Include $Include -Path $DirectoryMask;
Unfortunately, the -Exclude flag is…well, unhappy, in PowerShell as it doesn’t seem to work with -Recurse (or if it does, there’s voodoo involved).
How do we address voodoo issues? Regular expressions.
Aww, yeah.
$withoutExcludes = $originalFiles | ? {
if ($Exclude.count -gt 0) {
#need moar regex
[regex] $ex =
# 1: case insensitive and start of string
# 2: join our array, using RegEx to escape special characters
# the * allow wildcards so directory names filter out
# and not just exact paths.
# 3: end of string
# 1 2 3
'(?i)^(.*'+(($Exclude|%{[regex]::escape($_)}) -join ".*|.*")+'.*)$'
$_ -notmatch $ex
}
else {
$_
}
}
Breath, it’s okay. That is mostly code comments to explain what each line is doing. This snippet is dynamically creating a regular expression string based on our $Exclude parameter then comparing the current file in the iteration to the regular expression and returning the ones that do not match. If $Exclude is empty, it simply returns all files.
Finding our TODOs
Select-String provides us with a quick way to find patterns inside of text files and provides us with helpful output such as the line of text, line number, and file name (select-string is somewhat like PowerShell’s grep command).
$todos = $withoutExcludes |
% { select-string $_ -pattern "TODO:" } |
select-object LineNumber, FileName, Line;
Let’s take all of our remaining files, look at them as STRINGs and find the pattern "TODO:". This returns an array of MatchInfo objects. Since these have a few ancillary properties we don’t want, let’s simply grab the LineNumber, FileName, and the Line (of the match) for our reporting.
Now that we have our list, let’s pretty it up a bit. PowerShell’s select-object has the ability to reformat objects on the fly using expressions. I could have combined this in the last command; however, it’s a bit clearer to fetch our results THEN format them.
$formattedOutput = $todos | select-object `
@{Name='LineNumber'; Expression={$_.LineNumber}}, `
@{Name='FileName'; Expression={$_.FileName}}, `
@{Name='TODO'; Expression={$_.Line.Trim() -replace '// TODO: ',''}}
- LineNumber: We’re keeping this line the same.
- FileName: Again, input->output.
- TODO: Here’s the big change. "Line" isn’t real descriptive, so let’s set Name=’TODO’ for this column. Second, let’s trim the whitespace off the line AND replace the string "// TODO: " with an empty string (remove it). This cleans it up a bit.
Reporting It Out
At this point, we could simply return $formattedOutput | ft -a and have a handy table that looks like this:
Good for scripts, not so good for reporting and presenting to the boss/team (well, not my boss or team…). I added a -Html and -FileName flag to our parameters at the beginning just for this. I’ve pre-slugged the filename to todoList.html so I can set TeamCity to pickup the report automagically. But how do we build the report?
PowerShell contains a fantastic built-in cmdlet called ConvertTo-Html that you can pipe pretty much any tabular content into and it turns it into a table.
if ($Html) {
$head = @'
<style>
body{ font-family:Segoe UI; background-color:white;}
table{ border-width: 1px;border-style: solid;
border-color: black;border-collapse: collapse;width:100%;}
th{ font-family:Segoe Print;font-size:1.0em; border-width: 1px;
padding: 2px;border-style: solid;border-color:black;
background-color:lightblue;}
td{ border-width: 1px;padding: 2px;border-style: solid;
border-color: black;background-color:white;}
</style>
'@
$solutionName =
(Get-Location).ToString().Split("\")[(Get-Location).ToString().Split("\").Count-1];
$header = "<h1>"+$solutionName +" TODO List</h1><p>Generated on "+ [DateTime]::Now +".</p>"
$title = $solutionName +" TODO List"
$formattedOutput |
ConvertTo-HTML -head $head -body $header -title $title |
Out-File $FileName
}
else {
$formattedOutput
}
Our html <head> tag needs some style. Simple CSS to address that problem. I even added a few fonts in there for kicks and placed them in $head.
As I mentioned before, my solutions are usually the name of the project–which is what I want as the $title and $header. The $solutionName is ugly right now–if anyone out there has a BETTER way to get the STRING name of the current directory (not the Path), I’m all ears.
We take our $formattedOutput, $header, $title and pass them into ConvertTo-Html. It looks a bit strange that we’re setting our ‘body’ as the header; however, whatever is piped into the cmdlet appends to what is passed into -body. It then parses our content out to the $FileName specified.
Using Cassette with Spark View Engine
Knapsack… *cough*… I mean Cassette is a fantastic javascript/css/coffeescript resource manager from Andrew Davey. It did, however, take a bit to figure out why it wouldn’t work with Spark View Engine. Thankfully, blogs exist to remind me of this at a later date.
Namely—because I’ve never tried to use anything that returned void before. Helpers tend to always return either Html or a value.
I finally stumbled on a section in the Spark View Engine documentation for inline expressions.
Sometimes, when push comes to shove, you have a situation where you’re not writing output and there isn’t a markup construct for what you want to do. As a last resort you can produce code directly in-place in the generated class.
Well then, that sounds like what I want.
So our void methods, the Html.ReferenceScript and Html.ReferenceStylesheet should be written as:
#{Html.ReferenceScript("scripts/app/home.index.js");}
#{Html.ReferenceStylesheet("styles/app");}
Note the # (pound sign) and the semi-colon at the end of the statement block.
Our rendering scripts; however, use standard Spark output syntax:
${Html.RenderScripts()}
${Html.RenderStylesheetLinks()}
Now my Spark view contains the hashed Urls–in order–as it should.
<!DOCTYPE html> <html> <head> <link href="/styles/app/site.css?f8f8e3a3aec6d4e07008efb57d1233562d2c4b70" type="text/css" rel="stylesheet" /> </head> <body> <h2>Index</h2> <script src="/scripts/libs/jquery-1.6.2.js?eeee9d4604e71f2e01b818fc1439f7b5baf1be7a" type="text/javascript"></script> <script src="/scripts/app/application.js?91c81d13cf1762045ede31783560e6a46efc33d3" type="text/javascript"></script> <script src="/scripts/app/home.index.js?b0a66f7ba204e2dcf5261ab75934baba9cb94e51" type="text/javascript"></script> </body>
Excellent.
Review: Asus Transformer TF-101
tl;dr: Awesome!
I wanted to give my review after at least a week to settle in and integrate into my daily ‘flow’.
Why the Asus Transformer?
I’ve looked at more tablets than I can remember, teetering between the Motorola Xoom, Apple iPad2, Notion Ink Adam, and the Transformer. All of these seemed like great devices and had their own pros; however, the Transformer sold me on a few of its flashy innovations:
- Asus seems dedicated to constant updates. They’ve already pushed out Android Honeycomb 3.1 OTA and it updated like a champ.
- The docking station/keyboard is brilliant and really bridges the gap between netbook and tablet and adds incredible battery life.
- The mix of hardware performance for an incredible price point (499$US for the 32GB unit and 149$US for the keyboard/docking station at Amazon.com).
- Flash support. Yes, I’m looking at you iPad2.
How has the Transformer changed things?
I’ve noticed it’s changed things in the oddest of ways. I haven’t opened my personal laptop since I got the Transformer (it looks big and powerful, but it’s just old and … well, old).
Around the house, I’ve found myself using the Transformer in place of my EVO. I use it in the kitchen to look up recipes, check for coupons, make note of my groceries in Mighty Shopper, and listen to music. Other times, like for this post, for simple word processing, web browsing, and email. More functionality and less squinting.
At work, I’ve used Polaris Office for note taking, presentations (via the HDMI out), web browsing and research as I wander around the office with folks, and email. The remote desktop client (2X Client) allows me to remote into servers, my office desktop, and client machines for diagnostic work.
With Android 3.1, the web browser engine finally supports NTLM/Windows authentication so I can log into our corporate web sites (I hope this is coming to the Gingerbread builds soon).
I still have my phone with me through all this.. the Transformer hasn’t replaced the portability and features of my phone, but augmented what I can do without an actual desktop computer.
The Hardware
You can read the unit’s specifications, so I won’t drive into them too much. There are a few things to mention.
The bulk
Overall, the unit (and keyboard doc) are quite light compared to a normal 14" laptop. The tablet itself is very comfortable to carry around (long days here at work, so I’ve been pacing around while researching on the web).
The keyboard dock
I was a bit worried that the keyboard dock would be uncomfortable to use; however, that’s not the case. The keys are well spaced apart (once you get used to the ‘special’ keys at the top–I keep accidently locking the unit when I hit backspace) and the monitor can tilt back far enough for easy reading.
It’s important to note that the keyboard dock’s additional battery life is due to the dock charging the main unit while it’s docked. This is advantageous. Wander around and run the battery down a bit on the tablet, then dock and let the keyboard charge things up, detach, and you have a fully charged tablet again.
The POWER!
It is quite disappointing that the Transformer has a unique USB cable; however, even more so that it’s only about a meter long. This hassle is aggravated by the fact you cannot charge the unit via USB while it’s on, so if you need a charge AND need to use it, you’re trapped a meter from your electrical connection or extension cord.
Thankfully, with the 14-16 hours of battery life, charging isn’t a central focus of the day (unlike my EVO which is dead by the time I get to work).
The video output
Less of a big deal and more of a ‘oh’ moment when digging for cables. My EVO and a few other video devices all use micro HDMI so I had to pickup a 1.3a mini HDMI cable for the Transformer.
The screen
I love the screen. It’s a bit hard to see in high light (it’s not a Kindle for outdoor reading); however, the fingerprints are a bit out of control. I plan on getting a screen protector which, I hope, will help.
The camera
The camera is only a 5MP (compared to the 8MP in my EVO) and takes 4:3 photos rather than wide screen. That aside, it’s quite a good camera for general ‘here I am!’ sorts of photos–like lounging on the hammock in the back yard on a peaceful evening.
The lack of right click
I understand… I really do. The Android device doesn’t have a context for ‘right-click’; however, I dream of the day when it does so that the remote desktop clients have right-click.
Keeping it safe
I picked up a Belkin 10" Netbook Sleeve when ordering and highly recommend it as a carry case for the Transformer. The unit, whether you’re just carrying the tablet or the tablet and keyboard dock, fit very well into the sleeve and the zips/material feel and look good.
The Software
Out of the box, the Transformer walks you through a simple configuration–much like my EVO (or any Android phone). Setting up email, syncing contacts, and such worked just fine. I was impressed that the unit also synced my Google bookmarks. That’s an added bonus.
The basics are included:
- Email (Enterprise, Gmail, etc.) – The layout and flow of both mail applications is the same and works VERY well on landscape mode.
- Calendaring – nice, clean "Outlook-esque" layout.
- Contacts – standard Android contacts client.
- Polaris Office – bundled Office client for DOC, XLS, and PPT. Works quite well (and what I used for this post). It can also read/write to Google Docs, Dropbox, and a few other cloud services. At this time, I’m getting 400 errors trying to save BACK to Google Docs; however, from the forums, it appears that it is a Google API issue.
- MyReader – Simple eBook/pdf reader akin to Aikido.
- MyNet – network-based HD streaming client. Detects my PlayOn devices and streams perfectly.
- MyCloud – a subscription-based, unlimited storage system for music and files. Transformer includes a free 1 year subscription. I haven’t dug into this much as I have LiveSync and DropBox.
In addition to the boxed software, there are a few applications that I’d recommend (and seem to work quite well with the Transformer and Honeycomb):
- Dolphin Browser HD – Bit cleaner interface for web browsing and plugin modules (3.1 addresses some rendering issues though).
.
- Amazon Kindle Reader – Great for reading Kindle books on the run (and without your Kindle). The update for Android 3.1 works even better!
- Pandora – Great and solid music client.
- Grooveshark – Formatting is a bit off, but works fantastic to query and stream your favorite tunes.
- Google Reader – Great tablet support for full-screen reading.
- imo Chat beta – Best IM client I’ve found for any type of Android device.
- Plume – best Twitter client that takes advantage of the notifications and wide screen layout.
- DropBox – the Android DropBox client is pretty stellar.
- PrintBot - a free (and for cheap) application to print to network devices over WIFI. Works great and, hopefully, future versions will allow for multiple printers.
- NOTE: Similar to the Gingerbread break, Netflix is defunct on Honeycomb as well. I had hopes (dreams) that 3.1 would fix it, but alas it doesn’t seem so. Netflix is adamant that a new version is in the works. I hope so. It was great to have mobile movies on my cell phone and the Transformer seems ideal
Upgrading to Android Honeycomb 3.1
On 10 June 2011, Asus released Android Honeycomb 3.1 for the Transformer. The official version is v8.4.4.5 (the SKUs are separate by locale).
There are two options:
- manually download the update to an SD card and update.
- wait for the OTA update (Settings > About Tablet > System Update).
I’m impatient, so I opted for the manual method. The process was quite simple:
- Download the 8.4.4.5 zip file from the internet.
- On a microSD card create an \asus\update directory and copy the ZIP file into that directory.
- Insert the microSD card into the Transformer. You should see a notification that an update is available.
- The device will reboot a few times and then be good to go.
There are a few highlights to 3.1 (detailed by the release notes) that I really dig:
- The browser (and any browsers relying on it’s webkit) now supports NTLM/Windows Authentication. AWESOME for work!
- (Most) widgets are now resizable. I’ve come across a few that won’t resize.
- Speed! 3.1 generally feels faster. Multitasking across a dozen apps with notifications flying and music playing doesn’t seem to bother it.
Summary
With the tablet upgraded to 3.1, the applications that I like, and features that keep impressing me, I think the Transformer will continue to be a great fit. The keyboard matches my dire need to rapidly input information (take notes, respond to emails) and the portability matches my recent need to roam free of wires and surf the web.
The Transformer is a fantastic bridge between the smallest of laptops and the largest of cell phones and, unfortunately, is what I’d hoped the Google Chromebook would have been. Don’t get me wrong, I like my Chromebook–it was free and I like free–but the Android-based Transformer can actually DO the things I need to do in my day-to-day life.
Dynamically Adding Sub Reports to an ActiveReport
I’m currently working on a project where I needed to iterate through a group of users and plug in a little sub report that contains some demographic information and a Code38 barcode.
One sub report is easy–add the control to the page, set the .Report property and away we go; however, adding multiple sub reports dynamically and getting the spacing right proved to be a bit challenging.
Warning: It “works on my machine”.
To add controls to your report dynamically, you must use the _ReportStart event of your report.
To address the spacing issue, let’s start out by specifying our ‘base’ top and the height of our sub report.
const float height = 0.605f; var currentTop = 7.250f;
In my case, I want my sub reports to start at about 7.25″ and be ~0.605″ in height.
The actual creation of the sub report placeholder is fairly standard–new it up and assign a few properties. I’ll get into the looping a bit later.
var subReport = new SubReport
{
CloseBorder = false,
Height = height,
Left = 0F,
Width = 7.5F,
Top = currentTop,
Name = person.DisplayName + "_SubReport",
ReportName = person.DisplayName + "_SubReport",
};
Notice how I’ve set the Top property to be our currentTop variable. Keep that in mind.
The next step is to new up our actual sub report object. My sub report has two properties on it, each for a data item. I could pass it along as an object, but it seems a bit overkill for two string properties. After the report object is assigned to our new sub report container, add the container to our details section.
var spReport = new _PersonAssignment()
{
Name = person.DisplayName,
EmployeeId = person.EmployeeId
};
subReport.Report = spReport;
this.Sections["detail"].Controls.Add(subReport);
Because we’ve assigned it a left, width, and top, our sub report will be added where expected.
The final piece is incrementing the ‘top’ to accommodate for the height of the last sub report.
currentTop += height;
Easy. Now the next sub report will start at 7.250″ + 0.605″ or 7.855″. Keep in mind that the 0.605″ includes a bit of whitespace, if you need additional whitespace, pad the height number.
The full _ReportStart event looks like:
const float height = 0.605f;
var currentTop = 7.250f;
foreach (var person in Model.People)
{
var subReport = new SubReport
{
CloseBorder = false,
Height = height,
Left = 0F,
Width = 7.5F,
Top = currentTop,
Name = person.DisplayName + "_SubReport",
ReportName = person.DisplayName + "_SubReport",
};
var spReport = new _PersonAssignment()
{
Name = person.DisplayName,
EmployeeId = person.EmployeeId
};
subReport.Report = spReport;
this.Sections["detail"].Controls.Add(subReport);
currentTop += height;
}
Bingo.
Quick Solution Generation using PowerShell: New-Project
When I have an idea or want to prototype things, I tend to mock it up in Balsamiq, then dig right in and write some specs to see how it’d work. Unfortunately deleting the junk Class1.cs in Library projects, the plethora of excess in MVC3 webs, and such tends to be the most time intensive part of wiring up a quick project in .net.
All that deleting is too many steps–especially if you’re developing on the fly with a room of folks. I needed something ala command line to fit my normal workflow:
- o init-wrap MyProject -git
- cd MyProject
- git flow init
- {something to create projects, solutions, etc}
- o init-wrap -all
- {spend 5 minutes cleaning up junk files in my way}
Introducing New-Project
Yes, I know. I’m not a marketing guru. I don’t have a cool name for it. Just a standard PowerShell convention.
Usage:
-Library { } : Takes a string[] of names for c# class libraries to create.
-Web { } : Takes a string[] of names for MVC3 web projects to create.
-Solution "" : Takes a single string for your solution name.
Example:
New-Project -Library MyProj.Core, MyProj.Specs -Web MyProj.Web -Solution MyProject
What does this all do?
Well, honestly, I’m not sure how ‘reusable’ this is… the projects are pretty tailored.
Libraries
- Libraries don’t have the annoying Class1.cs file that you always delete.
- AssemblyInfo.cs is updated with the specified Name and Title.
MVC3 Webs
- The web.config is STRIPPED down to the minimal (27 lines).
- The folder structure is reorganized (removed unnecessary folders, like Controllers, which I put in libraries, not the web project).
Solution
- This is the only one I’m actually using the VisualStudio.DTE for–it makes it super easy to create and add projects into the solution.
But there are other scaffolding systems out there–why not use them?
Most of the time, I don’t need a full system. I don’t need my objects mapped, views automatically set up, or anything else.
Start with three empty projects, load up the Specifications project, and start driving out features. That’s how it’s supposed to work, right? So why would I want to have to pre-fill my projects ahead of time?
What’s next?
- Error catching and handling (it’s pretty lax right now)
- Handle setting up gitflow, openwrap, jQuery, etc. Less typing good!
- Something… who knows.
Where to get it?
I’ve tossed it up on github at https://github.com/drlongnecker/New-Project. Right now it has the WOMM warranty.


