Scott Hanselman

Is the Windows user ready for apt-get?

May 28, '13 Comments [87] Posted in NuGet | Open Source | Tools
Sponsored By
Chocolatey installs Git

What it does

Chocolatey lets you install Windows applications quickly from the command line via a central catalog of installation scripts. You could install Git, 7Zip or even Microsoft Office (given a key.) The idea is seamless and quiet installations using a well-known key.

For example, once installed you can do this from and command line:

  • cinst git
  • cinst 7zip
  • cinst ruby
  • cinst vlc

That's basically it.

The catalog has grown so complete, in fact, that I recently wanted to install DosBox so I could play Zork. I took and chance and just "cinst dosbox" and it worked. THAT is a the promise that Chocolatey makes.

Getting Started with Chocolatey

You can get started by first installing the Chocolatey package manager. Copy paste this line to your command line and run it. (More on the fearfulness of this first step in a moment).

@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin

Presumably you like to know what command line stuff is going to do to your computer before you do it, so parse this line out. It's going to launch PowerShell to do the hard work. Nearly every Windows machine has PowerShell these days, and it's PowerShell that makes Chocolatey work.

Some folks have custom profiles so the -NoProfile switch suppresses custom profiles to prevent conflicts during installation. It launches a chunk of PowerShell script that it downloads from https://chocolatey.org/install.ps1/ then executes. Note that it's setting execution policy to unrestricted to do this. To be clear, it's executing code downloaded over the web, so there is a non-zero risk there. It then adds Chocolatey to your path (for this one prompt) so you can use it immediately. It'll be added to future instances of prompts automatically.

Look at https://chocolatey.org/install.ps1 now. It's a very clean and easy to read script. It downloads the Chocolatey installation zip file (which is actually a NuGet package), unzips it and continues the installation by running a scripts in the tools section of the package.

How it works

Chocolatey is a bootstrapper that uses PowerShell scripts and the NuGet packaging format to install apps for you. NuGet is the package management system that Windows Developers use to bring libraries down at the project level. Chocolatey (get it? Chocolatey Nu-Get?) extends that concept to bring applications down at the system level.

Today if you want to get 7Zip, you usually google for it, find the site, figure out the latest version or right version for your system, download it, run it, next next next finish and maybe add it to your path. Chocolatey does that for you.

Again, NuGet is libraries installed locally for projects, Chocolatey is applications installed globally for your whole system.

Chocolatey uses PowerShell scripts (that you never have to think about) that package developers use to chain installations and build dependency trees. Take the internals of a Git installation script for example:

try {
Install-ChocolateyPackage 'git.install' 'exe' '/VERYSILENT' 'http://msysgit.googlecode.com/files/Git-1.8.1.2-preview20130201.exe'

#------- ADDITIONAL SETUP -------#
$is64bit = (Get-WmiObject Win32_Processor).AddressWidth -eq 64
$programFiles = $env:programfiles
if ($is64bit) {$programFiles = ${env:ProgramFiles(x86)}}
$gitPath = Join-Path $programFiles 'Git\cmd'

Install-ChocolateyPath $gitPath 'user'

@"

Making GIT core.autocrlf false
"@ | Write-Host

#make GIT core.autocrlf false
& "$env:comspec" '/c git config --global core.autocrlf false'

Write-ChocolateySuccess 'git.install'
} catch {
Write-ChocolateyFailure 'git.install' $($_.Exception.Message)
throw
}

The most important part for you to take away here is the first line. Note that this Chocolatey script is downloading Git from the mSysGit Site. Chocolatey is not changing installers, making installers or hosting installers. It's automating the boring parts of getting software, but it's still getting that software from the same location as always.

Advanced Stuff

Once you learn the basics - and they're pretty basic - there's more depth to Chocolatey to explore. Beyond the cinst and cuninst there's other commands to make installing stuff on Windows easier. Remember, they're all in your PATH so you can call these commands anytime.

Each of these major sources can be called with cinst using the -source parameter like "cinst IISExpress - source WebPI" or using their own aliases for simplicity as shown below.

  • cwindowsfeatures - If you've ever opened Add/Remove programs then click Install Windows Features in order to setup IIS or Hyper-V then this command is for you. Some examples:
    • cwindowsfeatures  IIS-WebServerRole
    • cwindowsfeatures Microsoft-Hyper-V-All
    • cwindowsfeatures TelnetClient
      • Plus, you can always clist -source windowsfeatures for the complete list.
  • cwebpi - The Web Platform Installer is a great GUI for downloading any development tools you might need for Web Development on Windows. It's a catalog, an installer, and a chainer. There's also a command-line version of WebPI that Chocolatey integrates with so you can:
    • cwebpi IISExpress
    • cwebpi VWDOrVs11AzurePack_2_0
      • And again, clist -source webpi gets you a list of what you can do.

There's a more complete list at the Chocolatey Commands Reference including how it integrates with Cygwin, Gems and Python.

Security Issues

nugetlogoThis is a prickly one. How do you make a system that lets you install anything directly from the Internet quickly, cleanly, and easily without, well, installing something evil directly from the Internet? You'll want the communication with the server to be secure and the packages trusted, but you'll also want to make sure the packages haven't been tampered with since they were uploaded. There's the inevitable threat of a man-in-the-middle attack. You'll want to watch for malicious packages and enable quick takedowns if one sneaks by.

Security concerns aren't unique to Chocolatey, of course. They are a part of package repositories since their inception. The node npm repository had a security breach in March of 2012, and the folks at andyet explored the issues surrounding it, but also pointed out that personal responsibility has to have a role as well.

Linux's apt-get solves much of this with appropriate uses of cryptography and best practices that can (and should) be emulated. Packages in apt repos are signed with SecureApp, there are warnings if you're using a 3rd party repo or installing an unsigned package.

The Chocolatey team has been very quick to jump on security issues and they are very approachable. They've added SSL where appropriate and are aware of the work to come. If Chocolatey gets big (bandwidth and costs is a question in my mind) perhaps a non-profit organization would step in to help with not only costs, but also security audits and best practices.

Here's some points (edited for length by me) from a post from Chocolatey's lead, Rob in a post on their mailing list, also in march of 2012:

Security has a big future aspect of chocolatey. At the present I am the curator and I every day I get an email showing me all of the new packages that went in the day before. I look at all packages from new authors and I typically look at the first version of most new packages from authors I have good contacts with.

I've talked at length with others about having a moderated feed in the aspect of every package, every new version would be approved prior to showing up on the main feed. I am paying attention to how debian does things with multiple feeds and there are thoughts to move in that direction as well.

Security? In the future we are looking at a small group of folks be an approving body for nupkgs. We also talked about showing the hash for the nupkg, and possibly letting folks specify a hash for the installers so chocolatey can verify the things it downloads prior to execution.

Chocolatey's LIB folderCould I make a Chocolatey package called "FormatMyHardDrive?" Sure I could, just like I could ask you to open an admin prompt and format c: /q, but you won't, right? ;)

What's next?

Chocolatey is clearly not meant to be used by your "Gender Non-Specific Non-Technical Parent" and it does have some "competition" in the form of the Ninite GUI installation utility. While still not for the average Joe/Jane and having only a limited catalog, Ninite does fill a gap for the super-user to quickly get the common apps and utilities they want.

Additionally, is Chocolatey really apt-get? It's not installing libraries system-wide, although there's no reason it couldn't. Other open source projects like CoApp would like to be the Windows app-get although CoApp is more of a "system-wide libraries, C++ support, and Unix-like utilities" and Chocolatey is more of a "developer and poweruser utilities and their dependencies."

Chocolatey does install dependencies and you can see that happen yourself by trying out "cinst gitextensions" which itself has a dependency on git. Chocolatey will walk the graph and install what it needs before finally installing gitextensions.

Where Chocolatey, and ultimately Windows itself, falls down is with odd PATHing and install locations. Because Windows doesn't have formal install locations for things and because Chocolatey puts itself first in the PATH, it's possible to get one's self into odd situations where apps that were installed outside of Chocolatey don't line up with apps installed inside. For example, I installed Git with Chocolatey some months ago, then forgot about that version and installed a newer version of Git on my own. However, I kept hitting an old git bug because the Chocolatey version of Git was "first." I believe issues like this have changed with recent builds of Chocolatey, but the point remains: it's hard on Windows today to who installed what low-level utility, when, and where it ended up.

Branding

Now, by no means to I want to take away from the hard work done by Rob and the team, but (and I've said this to Rob before) I really have trouble getting past the name Chocolatey. Sure, there are two ways to spell "Chocolaty," which make it hard at least for me to type "Chocolatey" reliably. The -ey is a theoretically a valid variant spelling, but you can tell that that to the red squiggled underline in Word. But it's less the spelling and more the name itself. It lacks the nerdiness of an "npm," the gravitas of an "apt-get," or the poetic terseness of a "gem."  I realize that we are living in a world with companies called Hulu, Yahoo, Microsoft (seriously, MICRO SOFT, what is that?) and Google, but it's worth pointing out that a good name can really take a project to the next level. I'm not sure Chocolatey is the right name for this project, but that's 100% my opinion.

I encourage you, technical reader, to check out Chocolatey for yourself! It's a powerful tool, an engaged and growing community and an interesting piece of tech in its own right.

Is Chocolatey the apt-get Windows users have been waiting for? Sound off in the comments.


Sponsor: Big thanks to SoftFluent for sponsoring the feed this week! Check out their slick code generation tools: Less Plumbing, More Productivity! Generate rock-solid foundations for your .NET applications from Visual Studio and focus on what matters!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Project-less scripted C# with ScriptCS and Roslyn

April 24, '13 Comments [27] Posted in NuGet | NuGetPOW | Open Source | VS2012
Sponsored By
ScriptCS inside of SublimeText2 with the ScriptCS package giving SyntaxHighlighting

Glenn Block is working on something interesting that combines C#, NuGet, Roslyn (the new "compiler as a service") and his love of text editors and scripts. Now, with help from Justin Rusbatch (@jrusbatch) and Filip Wojcieszyn (@filip_woj) they are having all kinds of fun...using C# as a scripting language.

Every few years someone tries to turn C# into a competent scripting world, myself included. Often this has included batch files and MacGyver magic, file associations and hacks. Clearly the .NET community wants something like this, but we are collectively still trying to figure out what it should look like. PowerShell aficionados - and I count myself amongst them - might look at such efforts as a threat or a pale reinvention of PowerShell, but the fact remains that C# at the command line, be it as a script or a REPL, is an attractive concept.

Simply put by example, ScriptCS lets me do this:

C:\temp>copy con hello.csx
Console.WriteLine("Pants");
^Z
1 file(s) copied.

C:\temp>scriptcs hello.csx
Pants

That's Hello World. There's no namespace, no class, just some C# in a .csx file. Roslyn takes care of the compilation and the resulting code and .exe never hits the disk.

Self-hosting Web APIs

So that's interesting, but what about bootstrapping a web server using NancyFX to host a Web API?

Go and clone this repo:

git clone https://github.com/scriptcs/scriptcs-samples.git

Look in the Nancy folder. There's a packages.config. Just like a node.js application has a packages.json file with the dependencies in has, a .NET app usually has a packages.config with the name. In node, you type npm install to restore those packages from the main repository. Here I'll type scriptcs -install...

C:\temp\scriptcs-samples\nancy>scriptcs -install
Installing packages...
Installed: Nancy.Hosting.Self 0.16.1.0
Installed: Nancy.Bootstrappers.Autofac 0.16.1.0
Installed: Autofac 2.6.3.862
Installation successful.

Now, running start.csx fires up an instance of Nancy listening on localhost:1234. There's no IIS, no ASP.NET.

C:\temp\scriptcs-samples\nancy>scriptcs start.csx
Found assembly reference: Autofac.Configuration.dll
Found assembly reference: Autofac.dll
Found assembly reference: Nancy.Bootstrappers.Autofac.dll
Found assembly reference: Nancy.dll
Found assembly reference: Nancy.Hosting.Self.dll
Nancy is running at http://localhost:1234/
Press any key to end

There is also the notion of a "ScriptPack" such that you can Require<T> a library and hide a lot of the bootstrapping and complexity. For example, I could start up WebAPI after installing a Web API package that includes some starter code. Note this is all from the command line. I'm using "copy con file" to get started.

C:\temp\foo>scriptcs -install ScriptCs.WebApi
Installing packages...
Installed: ScriptCs.WebApi
Installation completed successfully.
...snip...
Added ScriptCs.WebApi, Version 0.1.0, .NET 4.5
Packages.config successfully created!

C:\temp\foo>copy con start.csx
public class TestController : ApiController {
public string Get() {
return "Hello world!";
}
}

var webApi = Require<WebApi>();
var server = webApi.CreateServer("http://localhost:8080");
server.OpenAsync().Wait();

Console.WriteLine("Listening...");
Console.ReadKey();
server.CloseAsync().Wait();
^Z
1 file(s) copied.

C:\temp\foo>scriptcs start.csx
Found assembly reference: Newtonsoft.Json.dll
...snip...
Listening...

Pretty slick. Add in a little Live Reload-style action and we could have a very node-ish experience, all from the command line and from within your text editor of choice, except using C#.

Note that this is all using the same CLR and .NET that you've already got, running at full speed. Only the compilation is handled differently to give this script-like feel.

Installing ScriptCS

The easiest way to install and use ScriptCS is to use Chocolatey (a system-wide NuGet-based application/component installer. "Chocolatey NuGet," get it?) And yes, it's Chocolatey spelled incorrectly with an "-ey."

You can use Chocolatey to do things like "cinst 7zip" or "cinst git" but we'll be using it just to get ScriptCS set up. It's also easily removed if it freaks you out and it installs no services and won't change anything major up save your PATH.

First paste this into a cmd.exe prompt:

@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin

This will PowerShell, run https://chocolatey.org/install.ps1 and add Chocolatey to your path.

Then, run

cinst ScriptCS

Which will put ScriptCS in a path like C:\Chocolatey\lib\ScriptCs.0.0.0 while Chocolatey makes it available in your PATH.

Sublime Text or Visual Studio

You can get syntax highlighting for your CSX files inside of Sublime Text 2 with the "ScriptCS" package you can install from package control. If you're using Visual Studio you can get the Roslyn CTP to turn on CSX syntax highlighting.

You can use PackageControl in SublimeText2 and install the ScriptCS package

You can even debug your running ScriptCS projects by opening the ScriptCS.exe as a project. (Did you know you can open an EXE as a project?) Add the .csx script to the command line via Project Properties, drag in the scripts you're working on and debug away.

Debugging requires the Roslyn SDK, although personally, I've been doing just fine with scripts at the command line which requires nothing more than the basic install and a text editor.

It's not clear where ScriptCS is going, but it'll be interesting to see! Go get involved at scriptcs.net. This kind of stuff gets me excited about the prospect of a compiler as a service, and also cements my appreciation of C# as my enabling language of choice. Between C# and JavaScript, you can really get a lot done, pretty much anywhere.

I'll have a video walkthrough on how this works as I explain it to Rob Conery up on TekPub soon! (Here's a referral coupon for 20% off of Tekpub!)

What do you think?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

NuGet Package of the Week #13 - Portable HttpClient makes portable libraries more useful

March 21, '13 Comments [16] Posted in NuGet | NuGetPOW | Win8 | Windows Client | WinPhone
Sponsored By

Reference Assemblies include .NET Portable AssembliesWhen you've got an idea for an app, it's likely that you've got the idea for that app in more than one place. By this I mean, you'll start with a phone app, then make a desktop app, then a web app. Or you'll make a game on one platform and then want it to work anywhere. In fact, with the rise of Xamarin, C# lets you put an app in every AppStore in the world with one language.

You likely already knew that you can target different versions of the .NET framework. You likely also know that there are small .NET Frameworks like Silverlight and the tiny .NET Micro Framework.

You can also target XBox and Windows Phone, OR better yet, target a profile called Portable Libraries that I've briefly mentioned before. Portable Libraries are a great idea that have some issues when you try to really use them. There's actually a great (if a little older) video with the inventors over at Channel 9. Note that Portable Libraries ship with Visual Studio 2012 and are a supported thing.

The idea is that you write a library that contains as much shared functionality as possible and then every application uses your now "portable" library. However, the subset of classes that are available are a subset. That means you can only use things that are available in the intersection of the targets you choose. Check this dialog:

Choose your target framework

And check out the Supported Features table at this MSDN article on Portable Libraries to find out what you can use where. Here's a graphical table I stole from Daniel.

PortableLIbraryChart

However, most folks that use Portable Libraries have ended up using them mostly for ViewModels - just simple classes without any real functionality. Almost as if we had a DLL full of structs. There are some great posts on how to make Portable Class Libraries work for you using architectural techniques like indirection and appropriate interfaces.

The number one complaint around code resuse and the number one voted item over at the Visual Studio UserVoice was "Add HttpClient support in Portable Class Libraries (including Windows Phone 8)." Why? Because the GETting of a remote resource via HTTP is such a fundamental thing that it'd be awesome to be able to bake that data access into a portable library and use it everywhere.

Now there is a Portable Http Client and you can get it via NuGet!

install-package Microsoft.net.http -pre

Here's an example of what the code looks like for a GET. Note that I'm using async and await also.

public static async Task<HttpResponseMessage> GetTheGoodStuff() 
{
var httpClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://hanselman.com/blog/");
var response = await httpClient.SendAsync(request);
return response;
}

.NET Portable Subset

If you were going to make a Twitter client (lame example, but bear with me) you could now put the JSON HTTP data access code in one library and share it across Windows Phone, Windows Store, WinForms, Console, whatever.

I'm hoping that the folks at MS and the folks at Mono will continue to work to make Portable Libraries a good option for Mono as well. I've been advocating (and pushing) to make something happen as well, as have the Portable Libraries folks. You'll find lots of working in the space around the web, so fear not, code reuse, either through Portable Libraries or via linked code files at compilation time is deeply possible. The game "Draw A Stickman Epic" achieved 95% code reuse by writing the game in C# with MonoGame!

.NET 4 or Windows Phone 7.5

If you want to use this HttpClient on .NET 4 or Windows Phone 7.5, note you might get a compile error if you use async and await.

Cannot await System.Threading.Task<HttpRequestMessage>

This is because .Net 4.0 and Windows Phone 7.5 did not support the async/await keywords. In order to fix this add a reference to the Microsoft.Bcl.Async nuget package, which adds the support for async and await in .NET 4 and WP7.5. Here's a post with more details on how this backport works.

Related Links

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

NuGet Package(s) of the Week #12 - Accessing Google Spreadsheets with GData from C# *and* hosting Razor Templates to generate HTML from a Console App

January 10, '13 Comments [21] Posted in ASP.NET MVC | Back to Basics | NuGet | NuGetPOW | Open Source
Sponsored By

The Red Pump Project

Sometimes I write apps for charities on the side. Recently I've been doing some charity coding on the side for The Red Pump Project. They are a non-profit focused on raising awareness about the impact of HIV/AIDS on women and girls. I encourage you to check them out, donate some money, or join their mailing list.

Side Note: Folks often ask me how they can get more experience and wonder if Open Source is a good way. It is! But, charities often need code too! You may be able to have the best of both worlds. Donate your time and your code...and work with them to open source the result. Everyone wins. You get knowledge, the charity get results, the world gets code.

Anyway, this charity has a Google Spreadsheet that holds the results of a survey of users they take. You can create a Form from a Google Spreadsheet; it's a very common thing.

In the past, they've manually gone into the spreadsheet and copied the data out then painstakingly - manually - wrapped the data with HTML tags and posted donors names (who have opted in) to their site.

It got the point where this tedium was the #1 most hated job at The Red Pump Project. They wanted to recognize donors but they aren't large enough yet to have a whole donation platform CRM, instead opting to use Google Apps and free tools.

I figured I could fix this and quickly. Over a one hour Skype last night with Luvvie, one of The Red Pump Founders, we 'paired' (in that I wrote code and she validated the results as I typed) and made a little app that would loop through a Google Spreadsheet and make some HTML that was then uploaded to a webserver and used as a resource within their larger blogging platform.

Yes there are lots of simpler and better ways to do this but keep in mind that this is the result of a single hour, paired directly with the "on site customer" and they are thrilled. It also gives me something to build on. It could later to moved into the cloud, automated, moved to the server side, etc. One has to prioritize and this solution will save them dozens of hours of tedious work this fund raising season.

Here's our hour.

Step 1 - Access Google Spreadsheet via GDATA and C#

I was not familiar with the Google GData API but I knew there was one.  I made a console app and downloaded the Google Data API installer. You can also get them via NuGet:

image

I added references to Google.GData.Client, .Extensions, and .Spreadsheets. Per their documentation, you have to walk and object model, traversing first to find the Spreadsheet with in your Google Drive, then the Worksheet within a single Spreadsheet, and then the Rows and Columns as Cells within the Worksheet. Sounds like moving around a DOM. Get a reference, save it, dig down, continue.

So, that's Drive -> Spreadsheet -> Worksheet -> Cells (Rows, Cols)

The supporters of the Red Pump Project call themselves "Red Pump Rockers" so I have a class to hold them. I want their site, url and twitter. I have a "strippedSite" property which will be the name of their site with only valid alphanumerics so I can make an alphabet navigator later and put some simple navigation in a sorted list.

public class Rocker
{
public string site { get; set; }
public string strippedSite { get; set; }
public string url { get; set; }
public string twitter { get; set; }
}

Again, this is not my finest code but it works well given constraints.

var rockers = new List<Rocker>();

SpreadsheetsService myService = new SpreadsheetsService("auniquename");
myService.setUserCredentials(gmaillogin@email.com, "password");

// GET THE SPREADSHEET from all the docs
SpreadsheetQuery query = new SpreadsheetQuery();
SpreadsheetFeed feed = myService.Query(query);

var campaign = (from x in feed.Entries where x.Title.Text.Contains("thetitleofthesheetineed") select x).First();

// GET THE first WORKSHEET from that sheet
AtomLink link = campaign.Links.FindService(GDataSpreadsheetsNameTable.WorksheetRel, null);
WorksheetQuery query2 = new WorksheetQuery(link.HRef.ToString());
WorksheetFeed feed2 = myService.Query(query2);

var campaignSheet = feed2.Entries.First();

// GET THE CELLS

AtomLink cellFeedLink = campaignSheet.Links.FindService(GDataSpreadsheetsNameTable.CellRel, null);
CellQuery query3 = new CellQuery(cellFeedLink.HRef.ToString());
CellFeed feed3 = myService.Query(query3);

uint lastRow = 1;
Rocker rocker = new Rocker();

foreach (CellEntry curCell in feed3.Entries) {

if (curCell.Cell.Row > lastRow && lastRow != 1) { //When we've moved to a new row, save our Rocker
rockers.Add(rocker);
rocker = new Rocker();
}

//Console.WriteLine("Row {0} Column {1}: {2}", curCell.Cell.Row, curCell.Cell.Column, curCell.Cell.Value);

switch (curCell.Cell.Column) {
case 4: //site
rocker.site = curCell.Cell.Value;
Regex rgx = new Regex("[^a-zA-Z0-9]"); //Save a alphanumeric only version
rocker.strippedSite = rgx.Replace(rocker.site, "");
break;
case 5: //url
rocker.url = curCell.Cell.Value;
break;
case 6: //twitter
rocker.twitter = curCell.Cell.Value;
break;
}
lastRow = curCell.Cell.Row;
}

var sortedRockers = rockers.OrderBy(x => x.strippedSite).ToList();

At this point I have thousands of folks who "Rock The Red Pump" in a list called sortedRockers, sorted by site A-Z. I'm ready to do something with them.

Step 2 - Generate HTML (first wrong, then later right with Razor Templates)

They wanted a list of website names linked to their sites with an optional twitter name like:

Scott's Blog - @shanselman

I started (poorly) with a StringBuilder. *Gasp*

This is a learning moment, because it was hard and it was silly and I wasted 20 minutes of Luvvie's time. Still, it gets better, keep reading.

Here's what I wrote, quickly, and first. Don't judge, I'm being honest here.

foreach (Rocker r in sortedRockers){
string strippedName = r.strippedSite;

if (char.ToUpperInvariant(lastCharacter) != char.ToUpperInvariant(strippedName[0])) {
sb.AppendFormat("<h2><a name=\"{0}\">{0}</a></h2>", char.ToUpperInvariant(strippedName[0]));
}

sb.AppendFormat("<a href=\"{1}\" target=\"_blank\">{0}</a>", r.site, r.url);

if (!string.IsNullOrWhiteSpace(r.twitter)){
r.twitter = r.twitter.Replace("@", "");
sb.AppendFormat(" &mdash; <a href=\"http://twitter.com/{0}\">@{0}</a>", r.twitter);
}
sb.AppendFormat("<br>");

lastCharacter = strippedName[0];
}
sb.AppendFormat("</body></html>");

This works fine. It's also nuts and hard to read. Impossible to debug and generally confusing. Luvvie was patient but I clearly lost her here.

I realized that I should probably have used Razor Templating from within my Console App for this. I asked on StackOverflow as well.

UPDATE: There's a great answer by Demis from ServiceStack on StackOverflow showing how to use ServiceStack and Razor to generate HTML from Razor templates.

I ended up using RazorEngine, largely because of the promise of their first two lines of code on their original home page.  There is also RazorMachine, Nancy, and a post by Andrew Nurse (author of much of Razor itself) as other options.

RazorEngine in NuGet

But, these two lines right at their top of their site were too enticing to ignore.

string template = "Hello @Name.Name! Welcome to Razor!";
string result = Razor.Parse(template, new { Name = "World" });

(Open Source Developers Take Heed: Where's the easy quickstart code sample on your home page?)

This allowed me to change all that StringBuilder goo above into a nice clear Razor template in a string. I also added the alphabet navigation and the letter headers easily.

<html><head><link rel="stylesheet"" href="style.css" type="text/css" media="screen"/></head><body>

//Navigation - A B C D, etc.
@foreach(char x in ""ABCDEFGHIJKLMNOPQRSTUVWXYZ"".ToList()) {
<a href=""#@x"">@x</a>
}

@functions {
//need @functions because I need this variable in a wider scope
char lastCharacter = '0';
}

@foreach(var r in Model) {
var theUpperChar = char.ToUpperInvariant(r.strippedSite[0]);

//Make a capital letter "heading" when letters change
if (lastCharacter != theUpperChar) {
<h2><a name="@theUpperChar">@theUpperChar</a></h2>
}

<a href="@r.url" target="_blank">@r.site</a>

if (!string.IsNullOrWhiteSpace(r.twitter)) {
var twitter = r.twitter.Replace("@", String.Empty);
<text>&mdash;</text> <a href="http://twitter.com/@twitter">@twitter</a>
}
<br/>
lastCharacter = theUpperChar;
}
</body></html>

And the "do it" code ended up being:

string result = Razor.Parse(template, sortedRockers);
File.WriteAllText("2013list.html", result);

StringBuilders are fine, to a point. When it gets hairy, consider a templating engine of some kind.

Step 3 - Upload a File with FTP with C#

Now what? They want the little app to upload the result. Mads Kristensen to the rescue 7 years ago!

private static void Upload(string ftpServer, string userName, string password, string filename)
{
using (System.Net.WebClient client = new System.Net.WebClient())
{
client.Credentials = new System.Net.NetworkCredential(userName, password);
client.UploadFile(ftpServer + "/" + new FileInfo(filename).Name, "STOR", filename);
}
}

Then it's just

Upload("ftp://192.168.1.1", "UserName", "Password", @"2013list.html");

Conclusion

You can see that this is largely a spike, but it's a spike that solves a problem, today. Later we can build on it, move it to a server process, build a front end on it, and come up with more ways for them to keep  using tools like Google Spreadsheet while better integrating with their existing websites.

Consider donating your coding time to your favorite local charity today!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

NuGet 2.0 (.NET Package Manager) released - GO UPGRADE NOW and here's why

June 27, '12 Comments [30] Posted in NuGet
Sponsored By

Before we get started, take a second and head over to http://nuget.org and click Install NuGet. Actually, just do it from here. I'll wait.

Install NuGet

It's a 2.5 meg VSIX file and will take just a minute to install. It'll work on Visual Studio 2010 SP1 as well as Visual Studio 2012 RC. If you have them all installed at the same time, NuGet will prompt you to install in all of them if you like.

Weird Issues you might hit

If you are an early adopter and are testing Visual Studio 2012 RC, first, thanks. If you see a dialog box on VS2012RC that says "Configuring Extensions" and seems to sit forever, we have a bug that was fixed for RTM that is starting to surface more frequently with the recent NuGet update. The bug is a race condition that occurs intermittently when a user updates his extensions in the RC release.

Workaround for hung at "Configuring Extensions" on Visual Studio 2012 RC

  1. Close all instances of VS
  2. Examine the contents of HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\ExtensionManager\PendingDeletions
  3. Delete the folders listed for each entry
  4. Delete HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\ExtensionManager\PendingDeletions

99.9% of upgrades or installs will work just fine. If you see any other issues, run Visual Studio once as Administrator, go to Tools | Extensions Manager and uninstall NuGet, then install again.

The most common installation issue is a certificate mismatch with Visual Studio 2010 SP1. Unfortunately this one isn't NuGet's bug but you can get a Visual Studio hotfix here to fix it once and for all - http://bit.ly/vsixcertfix This should be in Windows Update one day, I hope. Either installing that hotfix or uninstalling/reinstalling as admin will fix the issue for NuGet.

Fixed Issues and New Features

Here's a query to the complete list of the 80 issues that were fixed in Version 2.0 of NuGet. NuGet has seen over 14 MILLION package downloads and there are over 6,000 unique packages in the gallery. You can see the updated stats anytime at http://stats.nuget.org.

The best fix, and the one I have personally been pushing the most on was this Issue: NuGet PowerShell Tab Completion is SLOW over a slow connection. If you are on a slow collection (I'm talking to you, New Zealand) or just appreciate speed, this is reason enough to upgrade NuGet.

Before, typing Install-Package jQuery.[TAB] would cause an HTTP call to go to OData that would return more data than was required. I'm always pushing for folks who are not in the US on 35 megabit connections. Often because I'm over there to, sucking data through 3G.

With NuGet 2.0 typing Install-Package JQuery.[TAB] will make a quick JSON call like this:

GET /api/v2/package-ids?partialId=jQuery. HTTP/1.0

Which will return, in this case, 603 bytes of JSON, as it should. It's fast.

["jQuery.Ajax.Unobtrusive", 
"jQuery.ba-throttle-debounce",
...,
"jQuery.LiveQuery",
"jQuery.MaskedInput",
"jQuery.Meow"]

And you'll get nice Intellisense for packages.

Intellisense in NuGet 2.0

New Features

Not only is NuGet 2.0 faster, but there's some new features like dependency grouping by target framework. You can vary your dependences such that one package can service .NET 2 and .NET 4 but each target framework requires a different bunch of packages. Here's a example:

<dependencies> 
<group>
<dependency id="RouteMagic" version="1.1.0" />
</group>

<group targetFramework="net40">
<dependency id="jQuery" />
<dependency id="WebActivator" />
</group>

<group targetFramework="sl30">
</group>
</dependencies>

From the docs:

Note that a group can contain zero dependencies. In the example above, if the package is installed into a project that targets Silverlight 3.0 or later, no dependencies will be installed. If the package is installed into a project that targets .NET 4.0 or later, two dependencies, jQuery and WebActivator, will be installed. If the package is installed into a project that targets an early version of these 2 frameworks, or any other framework, RouteMagic 1.1.0 will be installed. There is no inheritance between groups. If a project's target framework matches the targetFramework attribute of a group, only the dependencies within that group will be installed.

Even better, you can now group your PowerShell scripts as well as your content files by target framework. Specific scripts can run depending on your versions and specific content files can be included. This uses the same directory hierarchy you are already using for dependencies only now it works for /content and /tools as well.

Turn on "Allow NuGet to download missing packages during build" to make your life easier

Finally, do be aware that you have to explicitly give the OK to "restore packages" at least once, in order to enable NuGet to fetch a bunch of dependencies for you. Often you'll get a large project that you want to compile and perhaps that project includes a packages.config but not the packages itself (you don't want check your binary packages into source control, for example) so NuGet will restore missing packages when it's time to build. You only need to do this once to satisfy the lawyers.

Turn on Package Consent in Package Manager | General

Sneak Peak of Feature UI Features (thanks Mads!)

You know the new Ctrl-Q "search all commands" feature in Visual Studio 2012? I've seen a daily build of a possible improvement to NuGet on Mads' computer that not only searched Visual Studio local commands, but also the Visual Studio Gallery AND NuGet Packages. Leave a comment if you like this feature and I'll put pressure on Mads. Or, you will. ;)

jQuery searched for in the main Visual Studio CTRL-Q Quick search box

The Great Package Rename

We've changed the names of a BUNCH of packages (and forwarded the old names) so there's a little more logic to the Microsoft ones, at least. For example, here's the autocomplete for Microsoft.AspNet...

Microsoft.AspNet. intellisense

With this RC release, all of the NuGet packages involved in the ASP.NET products were renamed. Internally we called it the "Big Package Rename of 2012." Here is a mapping of old package names to new package names. In this list, the old names refer to prior versions of the products, including the Beta releases that shipped with VS 11 Beta.

OLD PACKAGE NEW PACKAGE
AspNetMvc Microsoft.AspNet.Mvc
AspNetRazor.Core Microsoft.AspNet.Razor
AspNetWebApi Microsoft.AspNet.WebApi
AspNetWebApi.Core Microsoft.AspNet.WebApi.Core
AspNetWebApi.SelfHost Microsoft.AspNet.WebApi.SelfHost
AspNetWebPages.Core Microsoft.AspNet.WebPages
AspNetWebPages Microsoft.AspNet.WebPages.Administration
jQuery.Ajax.Unobtrusive Microsoft.jQuery.Unobtrusive.Ajax
jQuery.Validation.Unobtrusive Microsoft.jQuery.Unobtrusive.Validation
Microsoft.Web.Optimization Microsoft.AspNet.Web.Optimization
SqlServerCompact Microsoft.SqlServer.Compact
System.Net.Http Microsoft.Net.Http
System.Net.Http.Formatting Microsoft.AspNet.WebApi.Client
System.Web.Providers Microsoft.AspNet.Providers
System.Web.Providers.Core Microsoft.AspNet.Providers.Core
System.Web.Providers.LocalDb Microsoft.AspNet.Providers.LocalDb
System.Web.Providers.SqlCE Microsoft.AspNet.Providers.SqlCE

We are hoping the other companies (and others inside of Microsoft) will follow the same standard naming structure

Hosting your own Feeds (and other NuGet sightings in the community)

If you haven't noticed there's a bunch of cool NuGet-specific sites and applications showing up in the wild.

  • MyGet - Create and host your own NuGet feed in the cloud. Host for your company, add security, privileges and more. Great for companies as well as automated build systems.
  • SymbolSource - "SymbolSource is an integrated solution for hosting and browsing code releases - specifically, but not only, NuGet and OpenWrap packages. It's true power, however, comes from implementing the srcsrv protocol, which allows Visual Studio and other compatible software to download on-demand symbol (PDB) and source files from SymbolSource."
  • TeamCity - TeamCity 7 supports packing and publishing of Nuget packages via a NuGet plugin (thanks Eugene Petrenko!) that is now installed by default!
  • Sonatype Nexus - Supports the Java Maven repository and now NuGet.
    • Allows the customer to have a local copy of the entire NuGet repository
    • Allow the customer to select which license types of software they support and only show them matching NuGet’s
    • Allow the customer to see that the NuGet’s they are consuming do not contain code copied from other projects
  • NuGet Server written in Java - Eugene created a small NuGet server that you can run under Linux and Java 1.6. It's all part of the larger TeamCity NuGet support and on GitHub as well as NuGet itself (inception!)
  • WebMatrix 2 - WebMatrix not only supports NuGet but it includes the gallery as a toolbar button and uses NuGet to install additional functionality like iPhone and iPad simulators!
  • NuGetFeed - Create a personalized feed of packages you care about and never miss another update!
  • ProGet is an NuGet repository for the enterprise, includes LDAP-based permissions and scoped feeds for multiple teams. Host private NuGet packages, as well as cache and filter other repositories. Free edition available.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Page 1 of 6 in the NuGet category Next Page

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