Scott Hanselman

Exploring Wyam - a .NET Static Site Content Generator

December 11, '16 Comments [20] Posted in ASP.NET | Open Source
Sponsored By

It's a bit of a renaissance out there when it comes to Static Site Generators. There's Jekyll and GitBook, Hugo and Hexo. Middleman and Pelican, Brunch and Octopress. There's dozens, if not hundreds of static site content generators, and "long tail is long."

Wyam is a great .NET based open source static site generator

Static Generators a nice for sites that DO get updated with dynamic content, but just not updated every few minutes. That means a Static Site Generator can be great for documentation, blogs, your brochure-ware home page, product catalogs, resumes, and lots more. Why install WordPress when you don't need to hit a database or generate HTML on every page view? Why not generate your site only when it changes?

I recently heard about a .NET Core-based open source generator called Wyam and wanted to check it out.

Wyam is a simple to use, highly modular, and extremely configurable static content generator that can be used to generate web sites, produce documentation, create ebooks, and much more.

Wyam is a module system with a pipeline that you can configure and chain processes together however you like. You can generate HTML from Markdown, from Razor, even XSLT2 - anything you like, really. Wyam also integrates nicely into your continuous build systems like Cake and others, so you can also get the Nuget Tools package for Wyam.

There's a few ways to get Wyam but I downloaded the setup.exe from GitHub Releases. You can also just get a ZIP and download it to any folder. When I ran the setup.exe it flashed (I didn't see a dialog, but it's beta so I'll chalk it up to that) and it installed to C:\Users\scott\AppData\Local\Wyam with what looked like the Squirrel installer from GitHub and Paul Betts.

Wyam has a number of nice features that .NET Folks will find useful.

Let's see what I can do with in just a few minutes!

Scaffolding a Blog

Wyam has a similar command line syntax as dotnet.exe and it uses "recipes" so I can say --recipe Blog and I'll get:

C:\Users\scott\Desktop\wyamtest>wyam new --recipe Blog
Wyam version 0.14.1-beta

,@@@@@ /@\ @@@@@
@@@@@@ @@@@@| $@@@@@h
$@@@@@ ,@@@@@@@ g@@@@@P
]@@@@@M g@@@@@@@ g@@@@@P
$@@@@@ @@@@@@@@@ g@@@@@P
j@@@@@ g@@@@@@@@@p ,@@@@@@@
`$@@@@@@@@@@@` ]@@@@@@@@@`
$@@@@@@@P` ?$@@@@@P
`^`` *P*`
Scaffold directory C:/Users/scott/Desktop/wyamtest/input does not exist and will be created
Installing NuGet packages
NuGet packages installed in 101813 ms
Recursively loading assemblies
Assemblies loaded in 2349 ms
Cataloging classes
Classes cataloged in 277 ms

One could imagine recipes for product catalogs, little league sites, etc. You can make your own custom recipes as well.

I'll make a config.wyam file with this inside:

Settings.Host = "";
GlobalMetadata["Title"] = "Scott Hanselman";
GlobalMetadata["Description"] = "The personal wyam-made blog of Scott Hanselman";
GlobalMetadata["Intro"] = "Hi, welcome to my blog!";

Then I'll run wyam with:

C:\Users\scott\Desktop\wyamtest>wyam -r Blog
Wyam version 0.14.1-beta
Loading configuration from file:///C:/Users/scott/Desktop/wyamtest/config.wyam
Installing NuGet packages
NuGet packages installed in 30059 ms
Recursively loading assemblies
Assemblies loaded in 368 ms
Cataloging classes
Classes cataloged in 406 ms
Evaluating configuration script
Evaluated configuration script in 2594 ms
Root path:
Input path(s):
Output path:
Cleaning output path output
Cleaned output directory
Executing 7 pipelines
Executing pipeline "Pages" (1/7) with 8 child module(s)
Executed pipeline "Pages" (1/7) in 221 ms resulting in 13 output document(s)
Executing pipeline "RawPosts" (2/7) with 7 child module(s)
Executed pipeline "RawPosts" (2/7) in 18 ms resulting in 1 output document(s)
Executing pipeline "Tags" (3/7) with 10 child module(s)
Executed pipeline "Tags" (3/7) in 1578 ms resulting in 1 output document(s)
Executing pipeline "Posts" (4/7) with 6 child module(s)
Executed pipeline "Posts" (4/7) in 620 ms resulting in 1 output document(s)
Executing pipeline "Feed" (5/7) with 3 child module(s)
Executed pipeline "Feed" (5/7) in 134 ms resulting in 2 output document(s)
Executing pipeline "RenderPages" (6/7) with 3 child module(s)
Executed pipeline "RenderPages" (6/7) in 333 ms resulting in 4 output document(s)
Executing pipeline "Resources" (7/7) with 1 child module(s)
Executed pipeline "Resources" (7/7) in 19 ms resulting in 14 output document(s)
Executed 7/7 pipelines in 2936 ms

I can also run it with -t for different themes, like "wyam -r Blog -t Phantom":

Wyam supports themes

As with most Static Site Generators I can start with a markdown file like "" and included name value pairs of metadata at the top:

Title: First Post
Published: 2016-01-01
Tags: Introduction
This is my first post!

If I'm working on my site a lot, I could run Wyam with the -w (WATCH) switch and then edit my posts in Visual Studio Code and Wyam will WATCH the input folder and automatically run over and over, regenerating the site each time I change the inputs! A nice little touch, indeed.

There's a lot of cool examples at that show you how to generate RSS, do pagination, use Razor but still generate statically, as well as mixing Razor for layouts and Markdown for posts.

The AdventureTime sample is fairly sophisticated (be sure to read the comments in the config.wyam for gotcha) example that includes a custom Pipeline, use of Yaml for front matter, and mixes markdown and Razor.

There's also a ton of modules you can use to extend the build however you like. For example, you could have source images be large and then auto-generate thumbnails like this:

ReadFiles("*").Where(x => x.Contains("images\\") && new[] { ".jpg", ".jpeg", ".gif", ".png"}.Contains(Path.GetExtension(x))),

There's a TON of options. You could even use Excel as the source data for your site, generate CSVs from the Excel OOXML and then generate your site from those CSVs. Sounds crazy, but if you run a small business or non-profit you could quickly make a nice workflow for someone to take control of their own site!

GOTCHA: When generating a site locally your initial reaction may be to open the /output folder and open the index.html in your local browser. You MAY be disappointed with you use a static site generator. Often they generate absolute paths for CSS and Javascript so you'll see a lousy version of your website locally. Either change your templates to generate relative paths OR use a staging site and look at your sites live online. Even better, use the Wyam "preview web server" and run Wyam with a "-p" argument and then visit http://localhost:5080 to see your actual site as it will show up online.

Wyam looks like a really interesting start to a great open source project. It's got a lot of code, good docs, and it's easy to get started. It also has a bunch of advanced features that would enable me to easily embed static site generation in a dynamic app. From the comments, it seems that Dave Glick is doing most of the work himself. I'm sure he'd appreciate you reaching out and helping with some issues.

As always, don't just send a PR without talking and working with the maintainers of your favorite open source projects. Also, ask if they have issues that are friendly to

Sponsor: Big thanks to Redgate! Help your team write better, shareable SQL faster. Discover how your whole team can write better, shareable SQL faster with a free trial of SQL Prompt. Write, refactor and share SQL effortlessly, try it now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is 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 SherWeb

Docker on a Synology NAS - Also running ASP.NET and .NET Core!

November 29, '16 Comments [32] Posted in Open Source
Sponsored By

Docker on Synology is amazingI love my Synology NAS (Network Attached Storage) device. It has sat quietly in my server closet for almost 5 years now. It was a fantastic investment. I've filled it with 8TB of inexpensive Seagate Drives and it does its own flavor of RAID to give me roughly 5TB (which, for my house is effectively infinite) of storage. In my house it's just \\SERVER or http://server. It's a little GNU Linux machine that is easier to manage and maintain (and generally deal with) that just chills in the closet. It's a personal cloud.

It also runs:

  • Plex - It's a media server with over 15 years of home movies and photos. It's even more magical when used with an Xbox One. It transcodes videos that then download to my Windows tablets or iPad...then I watch them offline on the plane.
  • VPN Server - I can remotely connect to my house. Even stream Netflix when I'm overseas.
  • Surveillance Station - It acts as a DVR and manages streams from a dozen cameras both inside and outside the house, scanning for motion and storing nearly a week of video.
  • Murmur/Mumble Server - Your own private VOIP chat service. Used for podcasts, gaming, private calls that aren't over Skype, etc.
  • Cloud Sync/Backup - I have files in Google Drive, Dropbox, and OneDrive...but I have them entirely backed up on my Synology with their Cloud Sync.

51FvMne3PyL._SL1280_Every year my Synology gets better with software upgrades. The biggest and most significant upgrade to Synology has been the addition of Docker and the Docker ecosystem. There is first class support for Docker on Synology. There are some Synology devices that are cheaper and use ARM processors. Make sure you get one with an Intel processor for best compatibility. Get the best one you can and you'll find new uses for it all the time! I have the 1511 (now 1515) and it's amazing.

ASP.NET Core on Docker on Synology

A month ago Glenn Condron and I did a Microsoft Virtual Academy on Containers and Cross-Platform .NET (coming soon!) and we made this little app and put it in Docker. It's "glennc/fancypants." That means I can easily run it anywhere with just:

docker run glennc/fancypants

Sometimes a DockerFile for ASP.NET Core can be as basic as this:

FROM microsoft/aspnetcore:1.0.1
ENTRYPOINT ["dotnet", "WebApplication4.dll"]
ARG source=.
COPY $source .

You could certainly use Docker Compose and have your Synology running Redis, MySql, ASP.NET Core, whatever.

Even better, since Synology has such a great UI, here is Glenn's app in the Synology web-based admin tool:

Docker on Synology - Node and ASP.NET Core Apps 

I can ssh into the Synology (you'll need to SSH in as root, or you'll want to set up Docker to allow another user to avoid this) and run docker commands directly, or I can use their excellent UI. It's really one of the nicest Docker UIs I've seen. I was able to get ASP.NET Core and the Node.js Ghost blog running in minutes with modest RAM requirements.


Once Containers exist in Docker on Synology you can "turn them on and off" like any service.

ASP.NET Core on Docker on Synology

This also means that your Synology can now run any Docker-based service like a private version of GitLab (good instructions here)! You could then (if you like) do cool domain mappings like and have your Synology do the work. The Synology could then run Jenkins or Travis as well which makes my home server fit nicely into my development workflow without use any compute resources on my main machine (or using any cloud resource at all!)

The next step for me will be to connect to Docker running on Synology remotely from my Windows machine, then setup "F5 Docker Debugging" in Visual Studio.


Anyone else using a Synology?

* My Amazon links pay for tacos. Please use them.

Sponsor: Big thanks to Octopus Deploy! Do you deploy the same application multiple times for each of your end customers? The team at Octopus have taken the pain out of multi-tenant deployments. Check out their latest 3.4 release!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is 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 SherWeb

WinAppDriver - Test any app with Appium's Selenium-like tests on Windows

November 16, '16 Comments [12] Posted in Open Source | Win10
Sponsored By
WinAppDriver - Appium testing Windows Apps

I've found blog posts on my site where I'm using the Selenium Web Testing Framework as far back as 2007! Today there's Selenium Drivers for every web browser including Microsoft Edge. You can write Selenium tests in nearly any language these days including Ruby, Python, Java, and C#.

I'm a big Selenium fan. I like using it with systems like BrowserStack to automate across many different browser on many operating systems.

"Appium" is a great Selenium-like testing framework that implements the "WebDriver" protocol - formerly JsonWireProtocol.

WebDriver is a remote control interface that enables introspection and control of user agents. It provides a platform- and language-neutral wire protocol as a way for out-of-process programs to remotely instruct the behavior of web browsers.

From the Appium website, "Appium is 'cross-platform': it allows you to write tests against multiple platforms (iOS, Android, Windows), using the same API. This enables code reuse between iOS, Android, and Windows testsuites"

Appium is a webserver that exposes a REST API. The WinAppDriver enables Appium by using new APIs that were added in Windows 10 Anniversary Edition that allow you to test any Windows app. That means ANY Windows App. Win32, VB6, WPF, UWP, anything. Not only can you put any app in the Windows Store, you can do full and complete UI testing of those apps with a tool that is already familiar to Web Developers like myself.

Your preferred language, your preferred test runner, the Appium Server, and your app

You can write tests in C# and run them from Visual Studio's Test Runner. You can press any button and basically totally control your apps.

// Launch the calculator app
DesiredCapabilities appCapabilities = new DesiredCapabilities();
appCapabilities.SetCapability("app", "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App");
CalculatorSession = new RemoteWebDriver(new Uri(WindowsApplicationDriverUrl), appCapabilities);
// Make sure we're in standard mode
CalculatorSession.FindElementByXPath("//Button[starts-with(@Name, \"Menu\")]").Click();
OriginalCalculatorMode = CalculatorSession.FindElementByXPath("//List[@AutomationId=\"FlyoutNav\"]//ListItem[@IsSelected=\"True\"]").Text;
CalculatorSession.FindElementByXPath("//ListItem[@Name=\"Standard Calculator\"]").Click();

It's surprisingly easy once you get started.

public void Addition()
Assert.AreEqual("Display is 8 ", CalculatorResult.Text);

You can automate any part of Windows, even the Start Menu or Cortana.

var searchBox = CortanaSession.FindElementByAccessibilityId("SearchTextBox");
searchBox.SendKeys("What is eight times eleven");

var bingPane = CortanaSession.FindElementByName("Bing");

var bingResult = bingPane.FindElementByName("88");

If you use "AccessibiltyIds" and refer to native controls in a non-locale specific way you can even reuse test code across platforms. For example, you could write sign in code for Windows, iOS, your web app, and even a VB6 Win32 app. ;)

Testing a VB6 app with WinAppDriver

Appium and WebAppDriver a nice alternative to "CodedUI Tests." CodedUI tests are great but just for Windows apps. If you're a web developer or you are writing cross platform or mobile apps you should check it out.

Sponsor: Help your team write better, shareable SQL faster! Discover how your whole team can write better, shareable SQL faster with a free trial of SQL Prompt. Write, refactor and share SQL effortlessly, try it now.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is 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 SherWeb

Stateless 3.0 - A State Machine library for .NET Core

November 11, '16 Comments [38] Posted in DotNetCore | Open Source
Sponsored By

.NET StandardState Machines and business processes that describe a series of states seem like they'll be easy to code but you'll eventually regret trying to do it yourself. Sure, you'll start with a boolean, then two, then you'll need to manage three states and there will be an invalid state to avoid then you'll just consider quitting all together. ;)

"Stateless" is a simple library for creating state machines in C# code. It's recently been updated to support .NET Core 1.0. They achieved this not by targeting .NET Core but by writing to the .NET Standard. Just like API levels in Android abstract away the many underlying versions of Android, .NET Standard is a set of APIs that all .NET platforms have to implement. Even better, the folks who wrote Stateless 3.0 targeted .NET Standard 1.0, which is the broadest and most compatible standard - it basically works everywhere and is portable across the .NET Framework on Windows, .NET Core on Windows, Mac, and LInux, as well as Windows Store apps and all phones.

Sure, there's Windows Workflow, but it may be overkill for some projects. In Nicholas Blumhardt's words:

...over time, the logic that decided which actions were allowed in each state, and what the state resulting from an action should be, grew into a tangle of if and switch. Inspired by Simple State Machine, I eventually refactored this out into a little state machine class that was configured declaratively: in this state, allow this trigger, transition to this other state, and so-on.

A state machine diagram describing the states a Bug can go throughYou can use state machines for anything. You can certainly describe high-level business state machines, but you can also easily model IoT device state, user interfaces, and more.

Even better, Stateless also serialize your state machine to a standard text-based "DOT Graph" format that can then be generated into an SVG or PNG like this with It's super nice to be able to visualize state machines at runtime.

Modeling a Simple State Machine with Stateless

Let's look at a few code examples. You start by describing some finite states as an enum, and some finite "triggers" that cause a state to change. Like a switch could have On and Off as states and Toggle as a trigger.

A more useful example is the Bug Tracker included in the Stateless source on GitHub. To start with here are the states of a Bug and the Triggers that cause state to change:

enum State { Open, Assigned, Deferred, Resolved, Closed }
enum Trigger { Assign, Defer, Resolve, Close }

You then have your initial state, define your StateMachine, and if you like, you can pass Parameters when a state is trigger. For example, if a Bug is triggered with Assign you can pass in "Scott" so the bug goes into the Assigned state - assigned to Scott.

State _state = State.Open;
StateMachine<State, Trigger> _machine;
StateMachine<State, Trigger>.TriggerWithParameters<string> _assignTrigger;

string _title;
string _assignee;

Then, in this example, the Bug constructor describes the state machine using a fluent interface that reads rather nicely.

public Bug(string title)
_title = title;

_machine = new StateMachine<State, Trigger>(() => _state, s => _state = s);

_assignTrigger = _machine.SetTriggerParameters<string>(Trigger.Assign);

.Permit(Trigger.Assign, State.Assigned);

.OnEntryFrom(_assignTrigger, assignee => OnAssigned(assignee))
.Permit(Trigger.Close, State.Closed)
.Permit(Trigger.Defer, State.Deferred)
.OnExit(() => OnDeassigned());

.OnEntry(() => _assignee = null)
.Permit(Trigger.Assign, State.Assigned);

For example, when the State is Open, it can be Assigned. But as this is written (you can change it) you can't close a Bug that is Open but not Assigned. Make sense?

When the Bug is Assigned, you can Close it, Defer it, or Assign it again. That's PermitReentry(). Also, notice that Assigned is a Substate of Open.

You can have events that are fired as states change. Those events can take actions as you like.

void OnAssigned(string assignee)
if (_assignee != null && assignee != _assignee)
SendEmailToAssignee("Don't forget to help the new employee.");

_assignee = assignee;
SendEmailToAssignee("You own it.");

void OnDeassigned()
SendEmailToAssignee("You're off the hook.");

void SendEmailToAssignee(string message)
Console.WriteLine("{0}, RE {1}: {2}", _assignee, _title, message);

With a nice State Machine library like Stateless you can quickly model states that you'd ordinarily do with a "big ol' switch statement."

What have you used for state machines like this in your projects?

Sponsor: Big thanks to Telerik! They recently published a comprehensive whitepaper on The State of C#, discussing the history of C#, what’s new in C# 7 and whether C# is still a viable language. Check it out!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is 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 SherWeb

ASP.NET Core RESTful Web API versioning made easy

November 2, '16 Comments [30] Posted in ASP.NET Web API | Open Source
Sponsored By

Pic by WoCTechChat used under Creative Commons There's a LOT of interesting and intense arguments that have been made around how you should version your Web API. As soon as you say RESTful it turns into a religious argument where folks may just well quote from the original text. ;)

Regardless of how you personally version your Web APIs, and side-stepping any arguments one way or the other, there's great new repository by Chris Martinez that Jon Galloway turned me on to at There's ASP.NET 4.x Web API, ODATA with ASP.NET Web APIs, and now ASP.NET Core 1.x. Fortunately Chris has assembled a nicely factored set of libraries called "ASP.NET API Versioning" that add service API versioning in a very convenient way.

As Chris points out:

The default API versioning configuration is compliant with the versioning semantics outlined by the Microsoft REST Guidelines. There are also a number of customization and extension points available to support transitioning services that may not have supported API versioning in the past or supported API versioning with semantics that are different from the Microsoft REST versioning guidelines.

It's also worth pointing out how great the documentation is given it's mostly a one-contributor project. I'm sure Chris would appreciate your help though, even if you're a first timer.

Chris has NuGet packages for three flavors of Web APIs on ASP.NET:

But you should really clone the repo and check out his excellent samples.

When versioning services there's a few schools of thought and with ASP.NET Core it's super easy to get started:

public void ConfigureServices( IServiceCollection services )

// remaining other stuff omitted for brevity

Oh, but you already have an API that's not versioned yet?

o =>
o.AssumeDefaultVersionWhenUnspecified = true );
o.DefaultApiVersion = new ApiVersion( new DateTime( 2016, 7, 1 ) );
} );

Your versions can look however'd you like them to:

  • /api/foo?api-version=1.0
  • /api/foo?api-version=2.0-Alpha
  • /api/foo?api-version=2015-05-01.3.0
  • /api/v1/foo
  • /api/v2.0-Alpha/foo
  • /api/v2015-05-01.3.0/foo

QueryString Parameter Versioning

I'm not a fan of this one, but here's the general idea:

[ApiVersion( "2.0" )]
[Route( "api/helloworld" )]
public class HelloWorld2Controller : Controller {
public string Get() => "Hello world!";

So this means to get 2.0 over 1.0 in another Controller with the same route, you'd go here:


Also, don't worry, you can use namespaces to have multiple HelloWorldControllers without having to have any numbers in the class names. ;)

URL Path Segment Versioning

This happens to be my first choice (yes I know Headers are "better," more on that later). You put the version in the route like this.

Here we're throwing in a little curveball. There's three versions but just two controllers.

[ApiVersion( "1.0" )]
[Route( "api/v{version:apiVersion}/[controller]" )]
public class HelloWorldController : Controller {
public string Get() => "Hello world!";

[ApiVersion( "2.0" )]
[ApiVersion( "3.0" )]
[Route( "api/v{version:apiVersion}/helloworld" )]
public class HelloWorld2Controller : Controller {
public string Get() => "Hello world v2!";

[HttpGet, MapToApiVersion( "3.0" )]
public string GetV3() => "Hello world v3!";

To be clear, you have total control, but the result from the outside is quite clean with /api/v[1|2|3]/helloworld. In fact, you can see with this example where this is more sophisticated than what you can do with routing out of the box. (I know some of you are thinking "meh I'll just make a route table." I think the semantics are much clearer and cleaner this way.

Header Versioning

Or, the hardest way (and the one that a lot of people this is best, but I disagree) is HTTP Headers. Set this up in ConfigureServices for ASP.NET Core:

public void ConfigureServices( IServiceCollection services )
services.AddApiVersioning(o => o.ApiVersionReader = new HeaderApiVersionReader("api-version"));

When you do HeaderApiVersioning you won't be able to just do a GET in your browser, so I'll use Postman to add the header (or I could use Curl, or WGet, or PowerShell, or a Unit Test):



Speaking of semantics, here's a nice one. Let's say an API is going away in the next 6 months.

[ApiVersion( "2.0" )]
[ApiVersion( "1.0", Deprecated = true )]

This advertises that 1.0 is going away soon and that folks should consider 2.0. Where does it advertise this fact? The response headers!

api-supported-versions: 2.0, api-deprecated-versions: 1.0

All in all, this is very useful stuff and I'm happy to add it to my personal toolbox. Should this be built in? I don't know but I sure appreciate that it exists.

SIDE NOTE: There is/was the start of a VersionRoute over in the AspNet.Mvc repo. Maybe these folks need to join forces?

How do YOU version your Web APIs and Services?

Sponsor: Big thanks to Telerik! They recently launched their UI toolset for ASP.NET Core so feel free to check it out or learn more about ASP.NET Core development in their recent whitepaper.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is 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 SherWeb
Previous Page Page 2 of 42 in the Open Source category Next Page

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