Trying ASP.NET Core on the Google Cloud Platform “App Engine Flexible Environment”

Last week I used Zeit and “now” to deploy an ASP.NET Core app (via a container) to the Zeit cloud. Tonight the kids are asleep so I thought I’d deploy to the Google Cloud. They’ve got beta support for open source ASP.NET so it’s a perfect time. Google even has Google Cloud Tools for Visual Studio (2015).

I’ll install the Google Cloud SDK. I checked “beta” as well.

Installing the Google Cloud SDK

Install it, login to your Google account and setup/select a project. I make a new folder and put an “app.yaml” in there with this inside as a directive to the Google Cloud Platform.

runtime: aspnetcore
env: flex

Here’s a gratuitous screenshot:

App.yaml

I did a dotnet new, dotnet restore, and finally a:

dotnet publish -c Release

which makes a publish folder that will get sent up to the cloud.

IMPORTANT NOTE: I initially tried to push a .NET Core app using the .NET Core 1.1 runtime but Google Cloud’s beta support in the flexible environment is set up for the 1.0.3 runtime (using their own custom docker base image) as of the time of this blog post, so you’ll want to “dotnet new mvc –framework netcoreapp1.0” and set the “RuntimeFrameworkVersion” to get that specific shared LTS (Long Term Support) version. As soon as the Google Cloud flex runtime has the latest LTS (1.0.4, at the time of this writing) then apps would just roll forward.

<PropertyGroup>
  <TargetFramework>netcoreapp1.0</TargetFramework>
<RuntimeFrameworkVersion>1.0.3</RuntimeFrameworkVersion> </PropertyGroup>

Otherwise you’ll get errors. Fortunately those errors are very clear.

.NET Core Runtime 1.0.3 supported

The walkthrough on Google Cloud suggests you copy the app.yaml file using a standard CLI copy command. However, since you’re going to need that app.yaml EVERY publish, just add it to the csproj like this:

<ItemGroup>
<Content Include="app.yaml" CopyToOutputDirectory="Always" />
</ItemGroup>

This way it’ll end up in publish automatically. You can then publish to the “AppEngine flexible environment:

dotnet restore
dotnet publish -c Release
gcloud beta app deploy .\bin\Release\netcoreapp1.0\publish\app.yaml
gcloud app browse // THIS IS JUST TO VISIT IT AFTER IT'S PUBLISHED

NOTE: You may get an ERROR that billing isn’t enabled, or that the cloudbuild.googleapis.com aren’t enabled. You’ll need to ensure you have an active Free Trial, then go to the API Manager in the Google Cloud Platform dashboard and enable “Google Cloud Container Builder API.” I also had to manually enable the API for the “Flexible” Environment and confirm I had a valid billing account.

Needed to enable some Billing APIs in the Google Cloud

Once I enabled a few APIs, I just did a standard “gcloud beta app deploy” as above:

gcloud beta app deploy

Pretty cool stuff! Here is my ASP.NET Core app running on GCP’s Flex engine:

ASP.NET on Google Cloud

You can “tail” your app with “gcloud app logs tail -s default” and you’ll see the output from .NET Core and ASP.NET (and Kestrel) in the Google Cloud!

gcloud app logs tail -s default

Or online in the Google “Stackdriver” logging page:

Google Stackdriver Logging page showing ASP.NET Core Logging

Go read up more on the Google Cloud Platform Blog. They even support Kubernetes clusters with ASP.NE Core apps packaged as Docker containers.


Sponsor: Thanks to Redgate! Track every change to your database! See who made changes, what they did, & why, with SQL Source Control. Get a full version history in your source control system. See how.


© 2017 Scott Hanselman. All rights reserved.
     

Last week I used Zeit and "now" to deploy an ASP.NET Core app (via a container) to the Zeit cloud. Tonight the kids are asleep so I thought I'd deploy to the Google Cloud. They've got beta support for open source ASP.NET so it's a perfect time. Google even has Google Cloud Tools for Visual Studio (2015).

I'll install the Google Cloud SDK. I checked "beta" as well.

Installing the Google Cloud SDK

Install it, login to your Google account and setup/select a project. I make a new folder and put an "app.yaml" in there with this inside as a directive to the Google Cloud Platform.

runtime: aspnetcore

env: flex

Here's a gratuitous screenshot:

App.yaml

I did a dotnet new, dotnet restore, and finally a:

dotnet publish -c Release

which makes a publish folder that will get sent up to the cloud.

IMPORTANT NOTE: I initially tried to push a .NET Core app using the .NET Core 1.1 runtime but Google Cloud's beta support in the flexible environment is set up for the 1.0.3 runtime (using their own custom docker base image) as of the time of this blog post, so you'll want to "dotnet new mvc --framework netcoreapp1.0" and set the "RuntimeFrameworkVersion" to get that specific shared LTS (Long Term Support) version. As soon as the Google Cloud flex runtime has the latest LTS (1.0.4, at the time of this writing) then apps would just roll forward.

<PropertyGroup>
  <TargetFramework>netcoreapp1.0</TargetFramework>

<RuntimeFrameworkVersion>1.0.3</RuntimeFrameworkVersion> </PropertyGroup>

Otherwise you'll get errors. Fortunately those errors are very clear.

.NET Core Runtime 1.0.3 supported

The walkthrough on Google Cloud suggests you copy the app.yaml file using a standard CLI copy command. However, since you're going to need that app.yaml EVERY publish, just add it to the csproj like this:

<ItemGroup>

<Content Include="app.yaml" CopyToOutputDirectory="Always" />
</ItemGroup>

This way it'll end up in publish automatically. You can then publish to the "AppEngine flexible environment:

dotnet restore

dotnet publish -c Release
gcloud beta app deploy .\bin\Release\netcoreapp1.0\publish\app.yaml
gcloud app browse // THIS IS JUST TO VISIT IT AFTER IT'S PUBLISHED

NOTE: You may get an ERROR that billing isn't enabled, or that the cloudbuild.googleapis.com aren't enabled. You'll need to ensure you have an active Free Trial, then go to the API Manager in the Google Cloud Platform dashboard and enable "Google Cloud Container Builder API." I also had to manually enable the API for the "Flexible" Environment and confirm I had a valid billing account.

Needed to enable some Billing APIs in the Google Cloud

Once I enabled a few APIs, I just did a standard "gcloud beta app deploy" as above:

gcloud beta app deploy

Pretty cool stuff! Here is my ASP.NET Core app running on GCP's Flex engine:

ASP.NET on Google Cloud

You can "tail" your app with "gcloud app logs tail -s default" and you'll see the output from .NET Core and ASP.NET (and Kestrel) in the Google Cloud!

gcloud app logs tail -s default

Or online in the Google "Stackdriver" logging page:

Google Stackdriver Logging page showing ASP.NET Core Logging

Go read up more on the Google Cloud Platform Blog. They even support Kubernetes clusters with ASP.NE Core apps packaged as Docker containers.


Sponsor: Thanks to Redgate! Track every change to your database! See who made changes, what they did, & why, with SQL Source Control. Get a full version history in your source control system. See how.



© 2017 Scott Hanselman. All rights reserved.
     

Command Line: Using dotnet watch test for continuous testing with .NET Core 1.0 and XUnit.net

I’ve installed .NET Core 1.0 on my machine. Let’s see if I can get a class library and tests running and compiling automatically using only the command line. (Yes, some of you are freaked out by my (and other folks’) appreciation of a nice, terse command line. Don’t worry. You can do all this with a mouse if you want. I’m just enjoying the CLI.

NOTE: This is considerably updated from the project.json version in 2016.

First, I installed from http://dot.net/core. This should all work on Windows, Mac, or Linux.

C:\> md testexample & cd testexample

C:\testexample> dotnet new sln
Content generation time: 33.0582 ms
The template "Solution File" created successfully.

C:\testexample> dotnet new classlib -n mylibrary -o mylibrary
Content generation time: 40.5442 ms
The template "Class library" created successfully.

C:\testexample> dotnet new xunit -n mytests -o mytests
Content generation time: 87.5115 ms
The template "xUnit Test Project" created successfully.

C:\testexample> dotnet sln add mylibrary\mylibrary.csproj
Project `mylibrary\mylibrary.csproj` added to the solution.

C:\testexample> dotnet sln add mytests\mytests.csproj
Project `mytests\mytests.csproj` added to the solution.

C:\testexample> cd mytests

C:\testexample\mytests> dotnet add reference ..\mylibrary\mylibrary.csproj
Reference `..\mylibrary\mylibrary.csproj` added to the project.

C:\testexample\mytests> cd ..

C:\testexample> dotnet restore
Restoring packages for C:\Users\scott\Desktop\testexample\mytests\mytests.csproj...
Restoring packages for C:\Users\scott\Desktop\testexample\mylibrary\mylibrary.csproj...
Restore completed in 586.73 ms for C:\Users\scott\Desktop\testexample\mylibrary\mylibrary.csproj.
Installing System.Diagnostics.TextWriterTraceListener 4.0.0.
...SNIP...
Installing Microsoft.NET.Test.Sdk 15.0.0.
Installing xunit.runner.visualstudio 2.2.0.
Installing xunit 2.2.0.
Generating MSBuild file C:\Users\scott\Desktop\testexample\mytests\obj\mytests.csproj.nuget.g.props.
Generating MSBuild file C:\Users\scott\Desktop\testexample\mytests\obj\mytests.csproj.nuget.g.targets.
Writing lock file to disk. Path: C:\Users\scott\Desktop\testexample\mytests\obj\project.assets.json
Installed:
16 package(s) to C:\Users\scott\Desktop\testexample\mytests\mytests.csproj

C:\testexample> cd mytests & dotnet test

Build started, please wait...
Build completed.

Test run for C:\testexample\mytests\bin\Debug\netcoreapp1.1\mytests.dll(.NETCoreApp,Version=v1.1)
Microsoft (R) Test Execution Command Line Tool Version 15.0.0.0
Copyright (c) Microsoft Corporation. All rights reserved.

Starting test execution, please wait...
[xUnit.net 00:00:00.5539676] Discovering: mytests
[xUnit.net 00:00:00.6867799] Discovered: mytests
[xUnit.net 00:00:00.7341661] Starting: mytests
[xUnit.net 00:00:00.8691063] Finished: mytests

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 1.8329 Seconds

Of course, I’m testing nothing yet but pretend there’s a test in the tests.cs and something it’s testing (that’s why I added a reference) in the library.cs, OK?

Now I want to have my project build and tests run automatically as I make changes to the code. I can’t “dotnet add tool” yet so I’ll add this line to my test’s project file:

<ItemGroup>
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />
</ItemGroup>

Like this:

Adding <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />

Then I just dotnet restore to bring in the tool.

NOTE: There’s a color bug using only cmd.exe so on “DOS” you’ll see some ANSI chars. That should be fixed in a minor release soon – the PR is in and waiting. On bash or PowerShell things look fin.

In this screenshot, you can see as I make changes to my test and hit save, the DotNetWatcher Tool sees the change and restarts my app, recompiles, and re-runs the tests.

Test Run Successful

All this was done from the command line. I made a solution file, made a library project and a test project, made the test project reference the library, then built and ran the tests. If I could add the tool from the command line I wouldn’t have had to manually touch the project file at all.

Again, to be sure, all this is stuff you can (and do) do in Visual Studio manually all the time. But I’ll race you anytime. 😉


Sponsor: Check out JetBrains Rider: a new cross-platform .NET IDE. Edit, refactor, test, build and debug ASP.NET, .NET Framework, .NET Core, or Unity applications. Learn more and get access to early builds!


© 2017 Scott Hanselman. All rights reserved.
     

I've installed .NET Core 1.0 on my machine. Let's see if I can get a class library and tests running and compiling automatically using only the command line. (Yes, some of you are freaked out by my (and other folks') appreciation of a nice, terse command line. Don't worry. You can do all this with a mouse if you want. I'm just enjoying the CLI.

NOTE: This is considerably updated from the project.json version in 2016.

First, I installed from http://dot.net/core. This should all work on Windows, Mac, or Linux.

C:\> md testexample & cd testexample


C:\testexample> dotnet new sln
Content generation time: 33.0582 ms
The template "Solution File" created successfully.

C:\testexample> dotnet new classlib -n mylibrary -o mylibrary
Content generation time: 40.5442 ms
The template "Class library" created successfully.

C:\testexample> dotnet new xunit -n mytests -o mytests
Content generation time: 87.5115 ms
The template "xUnit Test Project" created successfully.

C:\testexample> dotnet sln add mylibrary\mylibrary.csproj
Project `mylibrary\mylibrary.csproj` added to the solution.

C:\testexample> dotnet sln add mytests\mytests.csproj
Project `mytests\mytests.csproj` added to the solution.

C:\testexample> cd mytests

C:\testexample\mytests> dotnet add reference ..\mylibrary\mylibrary.csproj
Reference `..\mylibrary\mylibrary.csproj` added to the project.

C:\testexample\mytests> cd ..

C:\testexample> dotnet restore
Restoring packages for C:\Users\scott\Desktop\testexample\mytests\mytests.csproj...
Restoring packages for C:\Users\scott\Desktop\testexample\mylibrary\mylibrary.csproj...
Restore completed in 586.73 ms for C:\Users\scott\Desktop\testexample\mylibrary\mylibrary.csproj.
Installing System.Diagnostics.TextWriterTraceListener 4.0.0.
...SNIP...
Installing Microsoft.NET.Test.Sdk 15.0.0.
Installing xunit.runner.visualstudio 2.2.0.
Installing xunit 2.2.0.
Generating MSBuild file C:\Users\scott\Desktop\testexample\mytests\obj\mytests.csproj.nuget.g.props.
Generating MSBuild file C:\Users\scott\Desktop\testexample\mytests\obj\mytests.csproj.nuget.g.targets.
Writing lock file to disk. Path: C:\Users\scott\Desktop\testexample\mytests\obj\project.assets.json
Installed:
16 package(s) to C:\Users\scott\Desktop\testexample\mytests\mytests.csproj

C:\testexample> cd mytests & dotnet test

Build started, please wait...
Build completed.

Test run for C:\testexample\mytests\bin\Debug\netcoreapp1.1\mytests.dll(.NETCoreApp,Version=v1.1)
Microsoft (R) Test Execution Command Line Tool Version 15.0.0.0
Copyright (c) Microsoft Corporation. All rights reserved.

Starting test execution, please wait...
[xUnit.net 00:00:00.5539676] Discovering: mytests
[xUnit.net 00:00:00.6867799] Discovered: mytests
[xUnit.net 00:00:00.7341661] Starting: mytests
[xUnit.net 00:00:00.8691063] Finished: mytests

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 1.8329 Seconds

Of course, I'm testing nothing yet but pretend there's a test in the tests.cs and something it's testing (that's why I added a reference) in the library.cs, OK?

Now I want to have my project build and tests run automatically as I make changes to the code. I can't "dotnet add tool" yet so I'll add this line to my test's project file:

<ItemGroup>

<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />
</ItemGroup>

Like this:

Adding <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />

Then I just dotnet restore to bring in the tool.

NOTE: There's a color bug using only cmd.exe so on "DOS" you'll see some ANSI chars. That should be fixed in a minor release soon - the PR is in and waiting. On bash or PowerShell things look fin.

In this screenshot, you can see as I make changes to my test and hit save, the DotNetWatcher Tool sees the change and restarts my app, recompiles, and re-runs the tests.

Test Run Successful

All this was done from the command line. I made a solution file, made a library project and a test project, made the test project reference the library, then built and ran the tests. If I could add the tool from the command line I wouldn't have had to manually touch the project file at all.

Again, to be sure, all this is stuff you can (and do) do in Visual Studio manually all the time. But I'll race you anytime. ;)


Sponsor: Check out JetBrains Rider: a new cross-platform .NET IDE. Edit, refactor, test, build and debug ASP.NET, .NET Framework, .NET Core, or Unity applications. Learn more and get access to early builds!


© 2017 Scott Hanselman. All rights reserved.
     

Options for CSS and JS Bundling and Minification with ASP.NET Core

Maria and I were updating the NerdDinner sample app (not done yet, but soon) and were looking at various ways to do bundling and minification of the JSS and CS. There’s runtime bundling on ASP.NET 4.x but in recent years web developers have used tools like Grunt or Gulp to orchestrate a client-side build process to squish their assets. The key is to find a balance that gives you easy access to development versions of JS/CSS assets when at dev time, while making it “zero work” to put minified stuff into production. Additionally, some devs don’t need the Grunt/Gulp/npm overhead while others absolutely do. So how do you find balance? Here’s how it works.

I’m in Visual Studio 2017 and I go File | New Project | ASP.NET Core Web App. Bundling isn’t on by default but the configuration you need IS included by default. It’s just minutes to enable and it’s quite nice.

In my Solution Explorer is a “bundleconfig.json” like this:

// Configure bundling and minification for the project.
// More info at https://go.microsoft.com/fwlink/?LinkId=808241
[
{
"outputFileName": "wwwroot/css/site.min.css",
// An array of relative input file paths. Globbing patterns supported
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
// Optionally specify minification options
"minify": {
"enabled": true,
"renameLocals": true
},
// Optionally generate .map file
"sourceMap": false
}
]

Pretty simple. Ins and outs. At the top of the VS editor you’ll see this yellow prompt. VS knows you’re in a bundleconfig.json and in order to use it effectively in VS you grab a small extension. To be clear, it’s NOT required. It just makes it easier. The source is at https://github.com/madskristensen/BundlerMinifier. Slip this UI section if you just want Build-time bundling.

BundleConfig.json

If getting a prompt like this bugs you, you can turn all prompting off here:

Tools Options HTML Advanced Identify Helpful Extensions

Look at your Solution Explorer. See under site.css and site.js? There are associated minified versions of those files. They aren’t really “under” them. They are next to them on the disk, but this hierarchy is a nice way to see that they are associated, and that one generates the other.

Right click on your project and you’ll see this Bundler & Minifier menu:

Bundler and Minifier Menu

You can manually update your Bundles with this item as well as see settings and have bundling show up in the Task Runner Explorer.

Build Time Minification

The VSIX (VS extension) gives you the small menu and some UI hooks, but if you want to have your bundles updated at build time (useful if you don’t use VS!) then you’ll want to add a NuGet package called BuildBundlerMinifier.

You can add this NuGet package SEVERAL ways. Which is awesome.

  • Add it from the Manage NuGet Packages menu
  • Add it from the command line via “dotnet add package BuildBundlerMinifier”
    • Note that this adds it to your csproj without you having to edit it! It’s like “nuget install” but adds references to projects!  The dotnet CLI is lovely.
  • If you have the VSIX installed, just right-click the bundleconfig.json and click “Enable bundle on build…” and you’ll get the NuGet package.
    Enable bundle on build

Now bundling will run on build…

c:\WebApplication8\WebApplication8>dotnet build
Microsoft (R) Build Engine version 15
Copyright (C) Microsoft Corporation. All rights reserved.

Bundler: Begin processing bundleconfig.json
Bundler: Done processing bundleconfig.json
WebApplication8 -> c:\WebApplication8\bin\Debug\netcoreapp1.1\WebApplication8.dll

Build succeeded.
0 Warning(s)
0 Error(s)

…even from the command line with “dotnet build.” It’s all integrated.

This is nice for VS Code or users of other editors. Here’s how it would work entirely from the command prompt:

$ dotnet new mvc
$ dotnet add package BuildBundlerMinifier
$ dotnet restore
$ dotnet run

Advanced: Using Gulp to handle Bundling/Minifying

If you outgrow this bundler or just like Gulp, you can right click and Convert to Gulp!

Convert to Gulp

Now you’ll get a gulpfile.js that uses the bundleconfig.json and you’ve got full control:

gulpfile.js

And during the conversion you’ll get the npm packages you need to do the work automatically:

npm and bower

I’ve found this to be a good balance that can get quickly productive with a project that gets bundling without npm/node, but I can easily grow to a larger, more npm/bower/gulp-driven front-end developer-friendly app.


Sponsor: Did you know VSTS can integrate closely with Octopus Deploy? Join Damian Brady and Brian A. Randell as they show you how to automate deployments from VSTS to Octopus Deploy, and demo the new VSTS Octopus Deploy dashboard widget. Register now!


© 2017 Scott Hanselman. All rights reserved.
     

Maria and I were updating the NerdDinner sample app (not done yet, but soon) and were looking at various ways to do bundling and minification of the JSS and CS. There's runtime bundling on ASP.NET 4.x but in recent years web developers have used tools like Grunt or Gulp to orchestrate a client-side build process to squish their assets. The key is to find a balance that gives you easy access to development versions of JS/CSS assets when at dev time, while making it "zero work" to put minified stuff into production. Additionally, some devs don't need the Grunt/Gulp/npm overhead while others absolutely do. So how do you find balance? Here's how it works.

I'm in Visual Studio 2017 and I go File | New Project | ASP.NET Core Web App. Bundling isn't on by default but the configuration you need IS included by default. It's just minutes to enable and it's quite nice.

In my Solution Explorer is a "bundleconfig.json" like this:

// Configure bundling and minification for the project.

// More info at https://go.microsoft.com/fwlink/?LinkId=808241
[
{
"outputFileName": "wwwroot/css/site.min.css",
// An array of relative input file paths. Globbing patterns supported
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
// Optionally specify minification options
"minify": {
"enabled": true,
"renameLocals": true
},
// Optionally generate .map file
"sourceMap": false
}
]

Pretty simple. Ins and outs. At the top of the VS editor you'll see this yellow prompt. VS knows you're in a bundleconfig.json and in order to use it effectively in VS you grab a small extension. To be clear, it's NOT required. It just makes it easier. The source is at https://github.com/madskristensen/BundlerMinifier. Slip this UI section if you just want Build-time bundling.

BundleConfig.json

If getting a prompt like this bugs you, you can turn all prompting off here:

Tools Options HTML Advanced Identify Helpful Extensions

Look at your Solution Explorer. See under site.css and site.js? There are associated minified versions of those files. They aren't really "under" them. They are next to them on the disk, but this hierarchy is a nice way to see that they are associated, and that one generates the other.

Right click on your project and you'll see this Bundler & Minifier menu:

Bundler and Minifier Menu

You can manually update your Bundles with this item as well as see settings and have bundling show up in the Task Runner Explorer.

Build Time Minification

The VSIX (VS extension) gives you the small menu and some UI hooks, but if you want to have your bundles updated at build time (useful if you don't use VS!) then you'll want to add a NuGet package called BuildBundlerMinifier.

You can add this NuGet package SEVERAL ways. Which is awesome.

  • Add it from the Manage NuGet Packages menu
  • Add it from the command line via "dotnet add package BuildBundlerMinifier"
    • Note that this adds it to your csproj without you having to edit it! It's like "nuget install" but adds references to projects!  The dotnet CLI is lovely.
  • If you have the VSIX installed, just right-click the bundleconfig.json and click "Enable bundle on build..." and you'll get the NuGet package.
    Enable bundle on build

Now bundling will run on build...

c:\WebApplication8\WebApplication8>dotnet build

Microsoft (R) Build Engine version 15
Copyright (C) Microsoft Corporation. All rights reserved.

Bundler: Begin processing bundleconfig.json
Bundler: Done processing bundleconfig.json
WebApplication8 -> c:\WebApplication8\bin\Debug\netcoreapp1.1\WebApplication8.dll

Build succeeded.
0 Warning(s)
0 Error(s)

...even from the command line with "dotnet build." It's all integrated.

This is nice for VS Code or users of other editors. Here's how it would work entirely from the command prompt:

$ dotnet new mvc

$ dotnet add package BuildBundlerMinifier
$ dotnet restore
$ dotnet run

Advanced: Using Gulp to handle Bundling/Minifying

If you outgrow this bundler or just like Gulp, you can right click and Convert to Gulp!

Convert to Gulp

Now you'll get a gulpfile.js that uses the bundleconfig.json and you've got full control:

gulpfile.js

And during the conversion you'll get the npm packages you need to do the work automatically:

npm and bower

I've found this to be a good balance that can get quickly productive with a project that gets bundling without npm/node, but I can easily grow to a larger, more npm/bower/gulp-driven front-end developer-friendly app.


Sponsor: Did you know VSTS can integrate closely with Octopus Deploy? Join Damian Brady and Brian A. Randell as they show you how to automate deployments from VSTS to Octopus Deploy, and demo the new VSTS Octopus Deploy dashboard widget. Register now!


© 2017 Scott Hanselman. All rights reserved.
     

ZEIT now deployments of open source ASP.NET Core web apps with Docker

ZEIT is a new cloud service and “now” is the name of their deployment tool. ZEIT World is their DNS service. If you head over to https://zeit.co/ you’ll see a somewhat cryptic animated gif that shows how almost impossibly simple it is to deploy a web app with ZEIT now.

ZEIT works with .NET Core and ASP.NET

You can make a folder, put an index.html (for example) in it and just run “now.” You’ll automatically get a website with an autogenerated name and it’ll be live. It’s probably the fastest and easiest deploy I’ve ever seen. Remember when Heroku (then Azure, then literally everyone) started using git for deployment? Clearly being able to type “now” and just get a web site on the public internet was the next step. (Next someone will make “up” which will then get replaced with just pressing ENTER on an empty line! 😉 )

Jokes aside, now is clean and easy. I appreciate their organizational willpower to make an elegant and simple command line tool. I suspect it’s harder than it looks to keep things simple.

All of their examples use JavaScript and node.js, but they also support Docker, which means they support open source ASP.NET Core on .NET Core! But do they know they do? 😉 Let’s find out.

And more importantly, how easy is it? Can I take a site from concept to production in minutes? Darn tootin’ I can.

First, make a quick ASP.NET Core app. I’ll use the MVC template with Bootstrap.

C:\Users\scott\zeitdotnet>dotnet new mvc
Content generation time: 419.5337 ms
The template "ASP.NET Core Web App" created successfully.

I’ll do a quick dotnet restore to get the packages for my project.

C:\Users\scott\zeitdotnet>dotnet restore
Restoring packages for C:\Users\scott\zeitdotnet\zeitdotnet.csproj...
Generating MSBuild file C:\Users\scott\zeitdotnet\obj\zeitdotnet.csproj.nuget.g.props.
Generating MSBuild file C:\Users\scott\zeitdotnet\obj\zeitdotnet.csproj.nuget.g.targets.
Writing lock file to disk. Path: C:\Users\scott\zeitdotnet\obj\project.assets.json
Restore completed in 2.93 sec for C:\Users\scott\zeitdotnet\zeitdotnet.csproj.

NuGet Config files used:
C:\Users\scott\AppData\Roaming\NuGet\NuGet.Config
C:\Program Files (x86)\NuGet\Config\Microsoft.VisualStudio.Offline.config

Feeds used:
https://api.nuget.org/v3/index.json
C:\LocalNuGet
C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\

Now I need to add a Dockerfile. I’ll make one in the root that looks like this:

FROM microsoft/aspnetcore
LABEL name="zeitdotnet"
ENTRYPOINT ["dotnet", "zeitdotnet.dll"]
ARG source=.
WORKDIR /app
EXPOSE 80
COPY $source .

Note that I could have ZEIT build my app for me if I used the aspnetcore Dockerfile that includes the .NET Core SDK, but that would not only make my deployment longer, it would also make my docker images a LOT larger. I want to include JUST the .NET Core runtime in my image, so I’ll build and publish locally.

ZEIT now is going to need to see my Dockerfile, and since I want my app to include the binaries (I don’t want to ship my source in the Docker image up to ZEIT) I need to mark my Dockerfile as “Content” and make sure it’s copied to the publish folder when my app is built and published.

<ItemGroup>
  <None Remove="Dockerfile" />
</ItemGroup>
<ItemGroup>
  <Content Include="Dockerfile">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>
</ItemGroup>

I’ll add this my project’s csproj file. If I was using Visual Studio, this is the same as right clicking on the Properties of the Dockerfile, setting it to Content and then “Always Copy to Output Directory.”

Now I’ll just build and publish to a folder with one command:

C:\Users\scott\zeitdotnet>dotnet publish
Microsoft (R) Build Engine version 15.1.548.43366
Copyright (C) Microsoft Corporation. All rights reserved.

zeitdotnet -> C:\Users\scott\zeitdotnet\bin\Debug\netcoreapp1.1\zeitdotnet.dll

And finally, from the .\bin\Debug\netcoreapp1.1\ folder I run “now.” (Note that I’ve installed now and signed up for their service, of course.)

C:\Users\scott\zeitdotnet\bin\Debug\netcoreapp1.1\publish>now
> Deploying ~\zeitdotnet\bin\Debug\netcoreapp1.1\publish
> Ready! https://zeitdotnet-gmhcxevqkf.now.sh (copied to clipboard) [3s]
> Upload [====================] 100% 0.0s
> Sync complete (196.18kB) [2s]
> Initializing…
> Building
> ▲ docker build
> ---> 035a0a1401c3
> Removing intermediate container 289b9e4ce5d9
> Step 6 : EXPOSE 80
> ---> Running in efb817308333
> ---> fbac2aaa3039
> Removing intermediate container efb817308333
> Step 7 : COPY $source .
> ---> ff009cfc48ea
> Removing intermediate container 8d650c1867cd
> Successfully built ff009cfc48ea
> ▲ Storing image
> ▲ Deploying image
> Deployment complete!

Now has put the generated URL in my clipboard (during deployment you’ll get redirected to a lovely status page) and when it’s deployed I can visit my live site. But, that URL is not what I want. I want to use a custom URL.

I can take one of my domains and set it up with ZEIT World’s DNS but I like DNSimple (ref).

I can add my domain as an external one after adding a TXT record to my DNS to verify I own it. Then I setup a CNAME to point my subdomain to alias.zeit.co.

C:\Users\scott\Desktop\zeitdotnet>now alias https://zeitdotnet-gmhcxevqkf.now.sh http://zeitdotnet.hanselman.com
> zeitdotnet.hanselman.com is a custom domain.
> Verifying the DNS settings for zeitdotnet.hanselman.com (see https://zeit.world for help)
> Verification OK!
> Provisioning certificate for zeitdotnet.hanselman.com
> Success! Alias created:
https://zeitdotnet.hanselman.com now points to https://zeitdotnet-gmhcxevqkf.now.sh [copied to clipboard]

And that’s it. It even has a nice SSL certificate that they applied for me. It doesn’t terminate to SSL all the way into the docker container’s Kestral web server, but for most things that aren’t banking it’ll be just fine.

All in all, a lovely experience. Here’s my Hello World ASP.NE Core app running in ZEIT and deployed with now  at http://zeitdotnet.hanselman.com (if you are visiting this long after this was published, this sample MAY be gone.)

I am still learning about this (this whole exercise was about 30 total minutes and asking Glenn Condron a docker question) so I’m not clear how this would work in a large multi-container deployment, but as long as your site is immutable (don’t write to the container’s local disk!) ZEIT says it will scale your single containers. Perhaps docker-compose support is coming?


Sponsor: Did you know VSTS can integrate closely with Octopus Deploy? Join Damian Brady and Brian A. Randell as they show you how to automate deployments from VSTS to Octopus Deploy, and demo the new VSTS Octopus Deploy dashboard widget. Register now!


© 2017 Scott Hanselman. All rights reserved.
     

ZEIT is a new cloud service and "now" is the name of their deployment tool. ZEIT World is their DNS service. If you head over to https://zeit.co/ you'll see a somewhat cryptic animated gif that shows how almost impossibly simple it is to deploy a web app with ZEIT now.

ZEIT works with .NET Core and ASP.NET

You can make a folder, put an index.html (for example) in it and just run "now." You'll automatically get a website with an autogenerated name and it'll be live. It's probably the fastest and easiest deploy I've ever seen. Remember when Heroku (then Azure, then literally everyone) started using git for deployment? Clearly being able to type "now" and just get a web site on the public internet was the next step. (Next someone will make "up" which will then get replaced with just pressing ENTER on an empty line! ;) )

Jokes aside, now is clean and easy. I appreciate their organizational willpower to make an elegant and simple command line tool. I suspect it's harder than it looks to keep things simple.

All of their examples use JavaScript and node.js, but they also support Docker, which means they support open source ASP.NET Core on .NET Core! But do they know they do? ;) Let's find out.

And more importantly, how easy is it? Can I take a site from concept to production in minutes? Darn tootin' I can.

First, make a quick ASP.NET Core app. I'll use the MVC template with Bootstrap.

C:\Users\scott\zeitdotnet>dotnet new mvc

Content generation time: 419.5337 ms
The template "ASP.NET Core Web App" created successfully.

I'll do a quick dotnet restore to get the packages for my project.

C:\Users\scott\zeitdotnet>dotnet restore

Restoring packages for C:\Users\scott\zeitdotnet\zeitdotnet.csproj...
Generating MSBuild file C:\Users\scott\zeitdotnet\obj\zeitdotnet.csproj.nuget.g.props.
Generating MSBuild file C:\Users\scott\zeitdotnet\obj\zeitdotnet.csproj.nuget.g.targets.
Writing lock file to disk. Path: C:\Users\scott\zeitdotnet\obj\project.assets.json
Restore completed in 2.93 sec for C:\Users\scott\zeitdotnet\zeitdotnet.csproj.

NuGet Config files used:
C:\Users\scott\AppData\Roaming\NuGet\NuGet.Config
C:\Program Files (x86)\NuGet\Config\Microsoft.VisualStudio.Offline.config

Feeds used:
https://api.nuget.org/v3/index.json
C:\LocalNuGet
C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\

Now I need to add a Dockerfile. I'll make one in the root that looks like this:

FROM microsoft/aspnetcore

LABEL name="zeitdotnet"
ENTRYPOINT ["dotnet", "zeitdotnet.dll"]
ARG source=.
WORKDIR /app
EXPOSE 80
COPY $source .

Note that I could have ZEIT build my app for me if I used the aspnetcore Dockerfile that includes the .NET Core SDK, but that would not only make my deployment longer, it would also make my docker images a LOT larger. I want to include JUST the .NET Core runtime in my image, so I'll build and publish locally.

ZEIT now is going to need to see my Dockerfile, and since I want my app to include the binaries (I don't want to ship my source in the Docker image up to ZEIT) I need to mark my Dockerfile as "Content" and make sure it's copied to the publish folder when my app is built and published.

<ItemGroup>
  <None Remove="Dockerfile" />
</ItemGroup>
<ItemGroup>
  <Content Include="Dockerfile">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>
</ItemGroup>
I'll add this my project's csproj file. If I was using Visual Studio, this is the same as right clicking on the Properties of the Dockerfile, setting it to Content and then "Always Copy to Output Directory."

Now I'll just build and publish to a folder with one command:

C:\Users\scott\zeitdotnet>dotnet publish

Microsoft (R) Build Engine version 15.1.548.43366
Copyright (C) Microsoft Corporation. All rights reserved.

zeitdotnet -> C:\Users\scott\zeitdotnet\bin\Debug\netcoreapp1.1\zeitdotnet.dll

And finally, from the .\bin\Debug\netcoreapp1.1\ folder I run "now." (Note that I've installed now and signed up for their service, of course.)

C:\Users\scott\zeitdotnet\bin\Debug\netcoreapp1.1\publish>now

> Deploying ~\zeitdotnet\bin\Debug\netcoreapp1.1\publish
> Ready! https://zeitdotnet-gmhcxevqkf.now.sh (copied to clipboard) [3s]
> Upload [====================] 100% 0.0s
> Sync complete (196.18kB) [2s]
> Initializing…
> Building
> ▲ docker build
> ---> 035a0a1401c3
> Removing intermediate container 289b9e4ce5d9
> Step 6 : EXPOSE 80
> ---> Running in efb817308333
> ---> fbac2aaa3039
> Removing intermediate container efb817308333
> Step 7 : COPY $source .
> ---> ff009cfc48ea
> Removing intermediate container 8d650c1867cd
> Successfully built ff009cfc48ea
> ▲ Storing image
> ▲ Deploying image
> Deployment complete!

Now has put the generated URL in my clipboard (during deployment you'll get redirected to a lovely status page) and when it's deployed I can visit my live site. But, that URL is not what I want. I want to use a custom URL.

I can take one of my domains and set it up with ZEIT World's DNS but I like DNSimple (ref).

I can add my domain as an external one after adding a TXT record to my DNS to verify I own it. Then I setup a CNAME to point my subdomain to alias.zeit.co.

C:\Users\scott\Desktop\zeitdotnet>now alias https://zeitdotnet-gmhcxevqkf.now.sh http://zeitdotnet.hanselman.com

> zeitdotnet.hanselman.com is a custom domain.
> Verifying the DNS settings for zeitdotnet.hanselman.com (see https://zeit.world for help)
> Verification OK!
> Provisioning certificate for zeitdotnet.hanselman.com
> Success! Alias created:
https://zeitdotnet.hanselman.com now points to https://zeitdotnet-gmhcxevqkf.now.sh [copied to clipboard]

And that's it. It even has a nice SSL certificate that they applied for me. It doesn't terminate to SSL all the way into the docker container's Kestral web server, but for most things that aren't banking it'll be just fine.

All in all, a lovely experience. Here's my Hello World ASP.NE Core app running in ZEIT and deployed with now  at http://zeitdotnet.hanselman.com (if you are visiting this long after this was published, this sample MAY be gone.)

I am still learning about this (this whole exercise was about 30 total minutes and asking Glenn Condron a docker question) so I'm not clear how this would work in a large multi-container deployment, but as long as your site is immutable (don't write to the container's local disk!) ZEIT says it will scale your single containers. Perhaps docker-compose support is coming?


Sponsor: Did you know VSTS can integrate closely with Octopus Deploy? Join Damian Brady and Brian A. Randell as they show you how to automate deployments from VSTS to Octopus Deploy, and demo the new VSTS Octopus Deploy dashboard widget. Register now!



© 2017 Scott Hanselman. All rights reserved.
     

Xamarin .NET Workbooks – Interactive Computing is a stellar learning tool

I’ve been thinking a lot about how to best teach .NET and C#/F# to folks who are new to the space. We’ve added an in-browser no-install C# tutorial at http://dot.net. You can run through almost a few days lessons in C# without installing anything. Heck, it’s useful even if you just want to brush up on your skills.

When I spoke with Safia Abdalla a few months ago she re-introduced me to the ideas behind Interactive Computing and the whole ecosystem around Jupyter Notebooks, and the Nteract project Safia works on. It’s pretty amazing.

Pythonistas are familiar with Jupyter and the idea of a notebook that cleanly mixes prose and code. This ecosystem is very friendly to data scientists that are (perhaps) more scientist and less developer. People for whom an IDE is not as interesting as “electric paper.”

In fact, many people don’t realize that the Microsoft Azure Cloud supports hosting of Jupyter Notebooks using Python, R, and F#.

Azure Notebooks

Notebooks are a great learning resource that go beyond a REPL (an simple interactive console) in that they are effectively textbooks with islands of interactive code. It’s even more powerful when you consider graphics, charts, and other interactive models.

Xamarin has a thing called Xamarin Workbooks (I’m calling them .NET Workbooks in my head) that you should download and check out RIGHT NOW. Go get Xamarin Workbooks & Inspector for Windows (or download for Mac). Start playing around with workbooks or try out the samples.

I’m going to try teaching my C# and .NET courses for at least the first day or two using Xamarin .NET Workbooks. I think they have huge potential and I’m thrilled that Miguel and friends are investing so much in them. The potential for these as a learning tool that sits between a REPL and an IDE is huge.

The page at https://developer.xamarin.com/workbooks/ is FILLED with amazing example workbooks and lessons, and it’s growing. It has section not only on C# but Android, Games, Graphics as a concept, iOS, WPF, and so much more.

I run it and start here:

Xamarin Workbooks

Then I start typing…prose first! Just real sentences. Then I add some code. Notice that I’m not doing Console.WriteLine, I’m just assigning a variable. Xamarin Workbooks makes a nice visualization of my variable.

var scott = "Hanselman"

The prose is ignored (by the compiler) but the code cells and built upon each other and when you execute one you’re executing up to that point. Great for building up concepts.

You can print in other libraries and built upon them like in this chart example using the Urho library.

Charts in Xamarin Workbooks

Not to put to fine a point on it, but you can write really fully featured examples or games in Xamarin Workbooks. Here’s a fully 3D realized planet earth WITH SATELLITES. Again, with not just sample code but explanatory prose. It’s a textbook come to life.

THIS is how I wish I learned programming 25 years ago. I’d loved to have turned (or demo’ed) a .workbook file. I’m thrilled to see C# folks be able to do simple things that Jupyter users have enjoyed for so long.

3D Earth in Xamarin Workbooks

What do you think? Would this be a good way to deliver a course on learning .NET and C#?


Sponsor: Big thanks to Progress! 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!


© 2016 Scott Hanselman. All rights reserved.
     

I've been thinking a lot about how to best teach .NET and C#/F# to folks who are new to the space. We've added an in-browser no-install C# tutorial at http://dot.net. You can run through almost a few days lessons in C# without installing anything. Heck, it's useful even if you just want to brush up on your skills.

When I spoke with Safia Abdalla a few months ago she re-introduced me to the ideas behind Interactive Computing and the whole ecosystem around Jupyter Notebooks, and the Nteract project Safia works on. It's pretty amazing.

Pythonistas are familiar with Jupyter and the idea of a notebook that cleanly mixes prose and code. This ecosystem is very friendly to data scientists that are (perhaps) more scientist and less developer. People for whom an IDE is not as interesting as "electric paper."

In fact, many people don't realize that the Microsoft Azure Cloud supports hosting of Jupyter Notebooks using Python, R, and F#.

Azure Notebooks

Notebooks are a great learning resource that go beyond a REPL (an simple interactive console) in that they are effectively textbooks with islands of interactive code. It's even more powerful when you consider graphics, charts, and other interactive models.

Xamarin has a thing called Xamarin Workbooks (I'm calling them .NET Workbooks in my head) that you should download and check out RIGHT NOW. Go get Xamarin Workbooks & Inspector for Windows (or download for Mac). Start playing around with workbooks or try out the samples.

I'm going to try teaching my C# and .NET courses for at least the first day or two using Xamarin .NET Workbooks. I think they have huge potential and I'm thrilled that Miguel and friends are investing so much in them. The potential for these as a learning tool that sits between a REPL and an IDE is huge.

The page at https://developer.xamarin.com/workbooks/ is FILLED with amazing example workbooks and lessons, and it's growing. It has section not only on C# but Android, Games, Graphics as a concept, iOS, WPF, and so much more.

I run it and start here:

Xamarin Workbooks

Then I start typing...prose first! Just real sentences. Then I add some code. Notice that I'm not doing Console.WriteLine, I'm just assigning a variable. Xamarin Workbooks makes a nice visualization of my variable.

var scott = "Hanselman"

The prose is ignored (by the compiler) but the code cells and built upon each other and when you execute one you're executing up to that point. Great for building up concepts.

You can print in other libraries and built upon them like in this chart example using the Urho library.

Charts in Xamarin Workbooks

Not to put to fine a point on it, but you can write really fully featured examples or games in Xamarin Workbooks. Here's a fully 3D realized planet earth WITH SATELLITES. Again, with not just sample code but explanatory prose. It's a textbook come to life.

THIS is how I wish I learned programming 25 years ago. I'd loved to have turned (or demo'ed) a .workbook file. I'm thrilled to see C# folks be able to do simple things that Jupyter users have enjoyed for so long.

3D Earth in Xamarin Workbooks

What do you think? Would this be a good way to deliver a course on learning .NET and C#?


Sponsor: Big thanks to Progress! 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!



© 2016 Scott Hanselman. All rights reserved.
     

Stateless 3.0 – A State Machine library for .NET Core

.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 http://www.webgraphviz.com. 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);

_machine.Configure(State.Open)
.Permit(Trigger.Assign, State.Assigned);

_machine.Configure(State.Assigned)
.SubstateOf(State.Open)
.OnEntryFrom(_assignTrigger, assignee => OnAssigned(assignee))
.PermitReentry(Trigger.Assign)
.Permit(Trigger.Close, State.Closed)
.Permit(Trigger.Defer, State.Deferred)
.OnExit(() => OnDeassigned());

_machine.Configure(State.Deferred)
.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!


© 2016 Scott Hanselman. All rights reserved.
     

.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 http://www.webgraphviz.com. 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);

_machine.Configure(State.Open)
.Permit(Trigger.Assign, State.Assigned);

_machine.Configure(State.Assigned)
.SubstateOf(State.Open)
.OnEntryFrom(_assignTrigger, assignee => OnAssigned(assignee))
.PermitReentry(Trigger.Assign)
.Permit(Trigger.Close, State.Closed)
.Permit(Trigger.Defer, State.Deferred)
.OnExit(() => OnDeassigned());

_machine.Configure(State.Deferred)
.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!



© 2016 Scott Hanselman. All rights reserved.
     

The mystery of dotnet watch and ‘Microsoft.NETCore.App’, version ‘1.1.0-preview1-001100-00’ was not found

dotnet watch says "specified framework not found"

WARNING: This post is full of internal technical stuff. I think it’s interesting and useful. You may not.

I had an interesting Error/Warning happen when showing some folks .NET Core recently and I thought I’d deconstruct it here for you, Dear Reader, because it’s somewhat multi-layered and it’ll likely help you. It’s not just about Core, but also NuGet, Versioning, Package Management in general, version pinning, “Tools” in .NET Core, as well as how .NET Runtimes work and version. That’s a lot! All that from this little warning. Let’s see what’s up.

First, let’s say you have .NET Core installed. You likely got it from http://dot.net and you have either 1.0.0 or the 1.0.1 update.

Then say you have a website, or any app at all. I made one with “dotnet new -t web” in an empty folder.

I added “dotnet watch” as a tool in the project.json like this. NOTE the “1.0.0-*” there.

"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-*"
}

dotnet watch is nice because it watches the source code underneath it while running your app. If you change your code files, dotnet-watch will notice, and exit out, then launch “dotnet run” (or whatever, even test, etc) and your app will pick up the changes. It’s a nice developer convenience.

I tested this out on last weekend and it worked great. I went to show some folks on Monday that same week and got this error when I typed “dotnet watch.

C:\Users\scott\Desktop\foofoo>dotnet watch
The specified framework 'Microsoft.NETCore.App', version '1.1.0-preview1-001100-00' was not found.
- Check application dependencies and target a framework version installed at:
C:\Program Files\dotnet\shared\Microsoft.NETCore.App
- The following versions are installed:
1.0.0
1.0.1
- Alternatively, install the framework version '1.1.0-preview1-001100-00'.

Let’s really look at this. It says “the specified framework…1.1.0” was not found. That’s weird, I’m not using that one. I check my project.json and I see:

"Microsoft.NETCore.App": {
"version": "1.0.1",
"type": "platform"
},

So who wants 1.1.0? I typed “dotnet watch.” Can I “dotnet run?”

C:\Users\scott\Desktop\foofoo>dotnet run
Project foofoo (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing
Compiling foofoo for .NETCoreApp,Version=v1.0
Hosting environment: Production
Content root path: C:\Users\scott\Desktop\foofoo
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Hey, my app runs fine. But if I “dotnet watch” I get an error.

Remember that dotnet watch and other “tools” like it are not dependencies per se, but helpful sidecar apps. Tools can watch, squish css and js, precompile views, and do general administrivia that isn’t appropriate at runtime.

It seems it’s dotnet watch that wants something I don’t have.

Now, I could go install the framework 1.1.0 that it’s asking for, and the error would disappear, but would I know why? That would mean dotnet watch would use .NET Core 1.1.0 but my app (dotnet run) would use 1.0.1. That’s likely fine, but is it intentional? Is it deterministic and what I wanted?

I’ll open my generated project.lock.json. That’s the calculated tree of what we ended up with after dotnet restore. It’s a big calculated file but I can easily search it. I see two things. The internal details aren’t interesting but version strings are.

First, I search for “dotnet.watcher” and I see this:

"projectFileToolGroups": {
".NETCoreApp,Version=v1.0": [
"Microsoft.AspNetCore.Razor.Tools >= 1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools >= 1.0.0-preview2-final",
"Microsoft.DotNet.Watcher.Tools >= 1.0.0-*",
"Microsoft.EntityFrameworkCore.Tools >= 1.0.0-preview2-final",
"Microsoft.Extensions.SecretManager.Tools >= 1.0.0-preview2-final",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools >= 1.0.0-preview2-final"
]

Ah, that’s a reminder that I asked for 1.0.0-*. I asked for STAR for dotnet-watch but everything else was very clear. They were specific versions. I said “I don’t care about the stuff after 1.0.0 for watch, gimme whatever’s good.”

It seems that a new version of dotnet-watch and other tools came out between the weekend and my demo.

Search more in project.lock.json and I can see what all it asked for…I can see my dotnet-watch’s dependency tree.

"tools": {
".NETCoreApp,Version=v1.0": {
"Microsoft.DotNet.Watcher.Tools/1.0.0-preview3-final": {
"type": "package",
"dependencies": {
"Microsoft.DotNet.Cli.Utils": "1.0.0-preview2-003121",
"Microsoft.Extensions.CommandLineUtils": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging.Console": "1.1.0-preview1-final",
"Microsoft.NETCore.App": "1.1.0-preview1-001100-00"
},

Hey now. I said “1.0.0-*” and I ended up with “1.0.0-preview3-final”

Looks like dotnet-watch is trying to bring in a whole new .NET Core. It wants 1.1.0. This new dotnet-watch is part of the wave of new preview stuff from 1.1.0.

But I want to stay on the released and supported “LTS” (long term support) stuff, not the new fancy builds.

I shouldn’t have used 1.0.0-* as it was ambiguous. That might be great for my local versions or when I intend to chase the latest but not in this case.

I updated my version in my project.json to this and did a restore.

"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final",

Now I can reliably run dotnet restore and get what I want, and both dotnet watch and dotnet run use the same underlying runtime.


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.


© 2016 Scott Hanselman. All rights reserved.
     
dotnet watch says "specified framework not found"

WARNING: This post is full of internal technical stuff. I think it's interesting and useful. You may not.

I had an interesting Error/Warning happen when showing some folks .NET Core recently and I thought I'd deconstruct it here for you, Dear Reader, because it's somewhat multi-layered and it'll likely help you. It's not just about Core, but also NuGet, Versioning, Package Management in general, version pinning, "Tools" in .NET Core, as well as how .NET Runtimes work and version. That's a lot! All that from this little warning. Let's see what's up.

First, let's say you have .NET Core installed. You likely got it from http://dot.net and you have either 1.0.0 or the 1.0.1 update.

Then say you have a website, or any app at all. I made one with "dotnet new -t web" in an empty folder.

I added "dotnet watch" as a tool in the project.json like this. NOTE the "1.0.0-*" there.

"tools": {

"Microsoft.DotNet.Watcher.Tools": "1.0.0-*"
}

dotnet watch is nice because it watches the source code underneath it while running your app. If you change your code files, dotnet-watch will notice, and exit out, then launch "dotnet run" (or whatever, even test, etc) and your app will pick up the changes. It's a nice developer convenience.

I tested this out on last weekend and it worked great. I went to show some folks on Monday that same week and got this error when I typed "dotnet watch."

C:\Users\scott\Desktop\foofoo>dotnet watch

The specified framework 'Microsoft.NETCore.App', version '1.1.0-preview1-001100-00' was not found.
- Check application dependencies and target a framework version installed at:
C:\Program Files\dotnet\shared\Microsoft.NETCore.App
- The following versions are installed:
1.0.0
1.0.1
- Alternatively, install the framework version '1.1.0-preview1-001100-00'.

Let's really look at this. It says "the specified framework...1.1.0" was not found. That's weird, I'm not using that one. I check my project.json and I see:

"Microsoft.NETCore.App": {

"version": "1.0.1",
"type": "platform"
},

So who wants 1.1.0? I typed "dotnet watch." Can I "dotnet run?"

C:\Users\scott\Desktop\foofoo>dotnet run

Project foofoo (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing
Compiling foofoo for .NETCoreApp,Version=v1.0
Hosting environment: Production
Content root path: C:\Users\scott\Desktop\foofoo
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Hey, my app runs fine. But if I "dotnet watch" I get an error.

Remember that dotnet watch and other "tools" like it are not dependencies per se, but helpful sidecar apps. Tools can watch, squish css and js, precompile views, and do general administrivia that isn't appropriate at runtime.

It seems it's dotnet watch that wants something I don't have.

Now, I could go install the framework 1.1.0 that it's asking for, and the error would disappear, but would I know why? That would mean dotnet watch would use .NET Core 1.1.0 but my app (dotnet run) would use 1.0.1. That's likely fine, but is it intentional? Is it deterministic and what I wanted?

I'll open my generated project.lock.json. That's the calculated tree of what we ended up with after dotnet restore. It's a big calculated file but I can easily search it. I see two things. The internal details aren't interesting but version strings are.

First, I search for "dotnet.watcher" and I see this:

"projectFileToolGroups": {

".NETCoreApp,Version=v1.0": [
"Microsoft.AspNetCore.Razor.Tools >= 1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools >= 1.0.0-preview2-final",
"Microsoft.DotNet.Watcher.Tools >= 1.0.0-*",
"Microsoft.EntityFrameworkCore.Tools >= 1.0.0-preview2-final",
"Microsoft.Extensions.SecretManager.Tools >= 1.0.0-preview2-final",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools >= 1.0.0-preview2-final"
]

Ah, that's a reminder that I asked for 1.0.0-*. I asked for STAR for dotnet-watch but everything else was very clear. They were specific versions. I said "I don't care about the stuff after 1.0.0 for watch, gimme whatever's good."

It seems that a new version of dotnet-watch and other tools came out between the weekend and my demo.

Search more in project.lock.json and I can see what all it asked for...I can see my dotnet-watch's dependency tree.

"tools": {

".NETCoreApp,Version=v1.0": {
"Microsoft.DotNet.Watcher.Tools/1.0.0-preview3-final": {
"type": "package",
"dependencies": {
"Microsoft.DotNet.Cli.Utils": "1.0.0-preview2-003121",
"Microsoft.Extensions.CommandLineUtils": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging.Console": "1.1.0-preview1-final",
"Microsoft.NETCore.App": "1.1.0-preview1-001100-00"
},

Hey now. I said "1.0.0-*" and I ended up with "1.0.0-preview3-final"

Looks like dotnet-watch is trying to bring in a whole new .NET Core. It wants 1.1.0. This new dotnet-watch is part of the wave of new preview stuff from 1.1.0.

But I want to stay on the released and supported "LTS" (long term support) stuff, not the new fancy builds.

I shouldn't have used 1.0.0-* as it was ambiguous. That might be great for my local versions or when I intend to chase the latest but not in this case.

I updated my version in my project.json to this and did a restore.

"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final",

Now I can reliably run dotnet restore and get what I want, and both dotnet watch and dotnet run use the same underlying runtime.


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.


© 2016 Scott Hanselman. All rights reserved.
     

The mystery of dotnet watch and ‘Microsoft.NETCore.App’, version ‘1.1.0-preview1-001100-00’ was not found

dotnet watch says "specified framework not found"

WARNING: This post is full of internal technical stuff. I think it’s interesting and useful. You may not.

I had an interesting Error/Warning happen when showing some folks .NET Core recently and I thought I’d deconstruct it here for you, Dear Reader, because it’s somewhat multi-layered and it’ll likely help you. It’s not just about Core, but also NuGet, Versioning, Package Management in general, version pinning, “Tools” in .NET Core, as well as how .NET Runtimes work and version. That’s a lot! All that from this little warning. Let’s see what’s up.

First, let’s say you have .NET Core installed. You likely got it from http://dot.net and you have either 1.0.0 or the 1.0.1 update.

Then say you have a website, or any app at all. I made one with “dotnet new -t web” in an empty folder.

I added “dotnet watch” as a tool in the project.json like this. NOTE the “1.0.0-*” there.

"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-*"
}

dotnet watch is nice because it watches the source code underneath it while running your app. If you change your code files, dotnet-watch will notice, and exit out, then launch “dotnet run” (or whatever, even test, etc) and your app will pick up the changes. It’s a nice developer convenience.

I tested this out on last weekend and it worked great. I went to show some folks on Monday that same week and got this error when I typed “dotnet watch.

C:\Users\scott\Desktop\foofoo>dotnet watch
The specified framework 'Microsoft.NETCore.App', version '1.1.0-preview1-001100-00' was not found.
- Check application dependencies and target a framework version installed at:
C:\Program Files\dotnet\shared\Microsoft.NETCore.App
- The following versions are installed:
1.0.0
1.0.1
- Alternatively, install the framework version '1.1.0-preview1-001100-00'.

Let’s really look at this. It says “the specified framework…1.1.0” was not found. That’s weird, I’m not using that one. I check my project.json and I see:

"Microsoft.NETCore.App": {
"version": "1.0.1",
"type": "platform"
},

So who wants 1.1.0? I typed “dotnet watch.” Can I “dotnet run?”

C:\Users\scott\Desktop\foofoo>dotnet run
Project foofoo (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing
Compiling foofoo for .NETCoreApp,Version=v1.0
Hosting environment: Production
Content root path: C:\Users\scott\Desktop\foofoo
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Hey, my app runs fine. But if I “dotnet watch” I get an error.

Remember that dotnet watch and other “tools” like it are not dependencies per se, but helpful sidecar apps. Tools can watch, squish css and js, precompile views, and do general administrivia that isn’t appropriate at runtime.

It seems it’s dotnet watch that wants something I don’t have.

Now, I could go install the framework 1.1.0 that it’s asking for, and the error would disappear, but would I know why? That would mean dotnet watch would use .NET Core 1.1.0 but my app (dotnet run) would use 1.0.1. That’s likely fine, but is it intentional? Is it deterministic and what I wanted?

I’ll open my generated project.lock.json. That’s the calculated tree of what we ended up with after dotnet restore. It’s a big calculated file but I can easily search it. I see two things. The internal details aren’t interesting but version strings are.

First, I search for “dotnet.watcher” and I see this:

"projectFileToolGroups": {
".NETCoreApp,Version=v1.0": [
"Microsoft.AspNetCore.Razor.Tools >= 1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools >= 1.0.0-preview2-final",
"Microsoft.DotNet.Watcher.Tools >= 1.0.0-*",
"Microsoft.EntityFrameworkCore.Tools >= 1.0.0-preview2-final",
"Microsoft.Extensions.SecretManager.Tools >= 1.0.0-preview2-final",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools >= 1.0.0-preview2-final"
]

Ah, that’s a reminder that I asked for 1.0.0-*. I asked for STAR for dotnet-watch but everything else was very clear. They were specific versions. I said “I don’t care about the stuff after 1.0.0 for watch, gimme whatever’s good.”

It seems that a new version of dotnet-watch and other tools came out between the weekend and my demo.

Search more in project.lock.json and I can see what all it asked for…I can see my dotnet-watch’s dependency tree.

"tools": {
".NETCoreApp,Version=v1.0": {
"Microsoft.DotNet.Watcher.Tools/1.0.0-preview3-final": {
"type": "package",
"dependencies": {
"Microsoft.DotNet.Cli.Utils": "1.0.0-preview2-003121",
"Microsoft.Extensions.CommandLineUtils": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging.Console": "1.1.0-preview1-final",
"Microsoft.NETCore.App": "1.1.0-preview1-001100-00"
},

Hey now. I said “1.0.0-*” and I ended up with “1.0.0-preview3-final”

Looks like dotnet-watch is trying to bring in a whole new .NET Core. It wants 1.1.0. This new dotnet-watch is part of the wave of new preview stuff from 1.1.0.

But I want to stay on the released and supported “LTS” (long term support) stuff, not the new fancy builds.

I shouldn’t have used 1.0.0-* as it was ambiguous. That might be great for my local versions or when I intend to chase the latest but not in this case.

I updated my version in my project.json to this and did a restore.

"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final",

Now I can reliably run dotnet restore and get what I want, and both dotnet watch and dotnet run use the same underlying runtime.


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.


© 2016 Scott Hanselman. All rights reserved.
     
dotnet watch says "specified framework not found"

WARNING: This post is full of internal technical stuff. I think it's interesting and useful. You may not.

I had an interesting Error/Warning happen when showing some folks .NET Core recently and I thought I'd deconstruct it here for you, Dear Reader, because it's somewhat multi-layered and it'll likely help you. It's not just about Core, but also NuGet, Versioning, Package Management in general, version pinning, "Tools" in .NET Core, as well as how .NET Runtimes work and version. That's a lot! All that from this little warning. Let's see what's up.

First, let's say you have .NET Core installed. You likely got it from http://dot.net and you have either 1.0.0 or the 1.0.1 update.

Then say you have a website, or any app at all. I made one with "dotnet new -t web" in an empty folder.

I added "dotnet watch" as a tool in the project.json like this. NOTE the "1.0.0-*" there.

"tools": {

"Microsoft.DotNet.Watcher.Tools": "1.0.0-*"
}

dotnet watch is nice because it watches the source code underneath it while running your app. If you change your code files, dotnet-watch will notice, and exit out, then launch "dotnet run" (or whatever, even test, etc) and your app will pick up the changes. It's a nice developer convenience.

I tested this out on last weekend and it worked great. I went to show some folks on Monday that same week and got this error when I typed "dotnet watch."

C:\Users\scott\Desktop\foofoo>dotnet watch

The specified framework 'Microsoft.NETCore.App', version '1.1.0-preview1-001100-00' was not found.
- Check application dependencies and target a framework version installed at:
C:\Program Files\dotnet\shared\Microsoft.NETCore.App
- The following versions are installed:
1.0.0
1.0.1
- Alternatively, install the framework version '1.1.0-preview1-001100-00'.

Let's really look at this. It says "the specified framework...1.1.0" was not found. That's weird, I'm not using that one. I check my project.json and I see:

"Microsoft.NETCore.App": {

"version": "1.0.1",
"type": "platform"
},

So who wants 1.1.0? I typed "dotnet watch." Can I "dotnet run?"

C:\Users\scott\Desktop\foofoo>dotnet run

Project foofoo (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing
Compiling foofoo for .NETCoreApp,Version=v1.0
Hosting environment: Production
Content root path: C:\Users\scott\Desktop\foofoo
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Hey, my app runs fine. But if I "dotnet watch" I get an error.

Remember that dotnet watch and other "tools" like it are not dependencies per se, but helpful sidecar apps. Tools can watch, squish css and js, precompile views, and do general administrivia that isn't appropriate at runtime.

It seems it's dotnet watch that wants something I don't have.

Now, I could go install the framework 1.1.0 that it's asking for, and the error would disappear, but would I know why? That would mean dotnet watch would use .NET Core 1.1.0 but my app (dotnet run) would use 1.0.1. That's likely fine, but is it intentional? Is it deterministic and what I wanted?

I'll open my generated project.lock.json. That's the calculated tree of what we ended up with after dotnet restore. It's a big calculated file but I can easily search it. I see two things. The internal details aren't interesting but version strings are.

First, I search for "dotnet.watcher" and I see this:

"projectFileToolGroups": {

".NETCoreApp,Version=v1.0": [
"Microsoft.AspNetCore.Razor.Tools >= 1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools >= 1.0.0-preview2-final",
"Microsoft.DotNet.Watcher.Tools >= 1.0.0-*",
"Microsoft.EntityFrameworkCore.Tools >= 1.0.0-preview2-final",
"Microsoft.Extensions.SecretManager.Tools >= 1.0.0-preview2-final",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools >= 1.0.0-preview2-final"
]

Ah, that's a reminder that I asked for 1.0.0-*. I asked for STAR for dotnet-watch but everything else was very clear. They were specific versions. I said "I don't care about the stuff after 1.0.0 for watch, gimme whatever's good."

It seems that a new version of dotnet-watch and other tools came out between the weekend and my demo.

Search more in project.lock.json and I can see what all it asked for...I can see my dotnet-watch's dependency tree.

"tools": {

".NETCoreApp,Version=v1.0": {
"Microsoft.DotNet.Watcher.Tools/1.0.0-preview3-final": {
"type": "package",
"dependencies": {
"Microsoft.DotNet.Cli.Utils": "1.0.0-preview2-003121",
"Microsoft.Extensions.CommandLineUtils": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging": "1.1.0-preview1-final",
"Microsoft.Extensions.Logging.Console": "1.1.0-preview1-final",
"Microsoft.NETCore.App": "1.1.0-preview1-001100-00"
},

Hey now. I said "1.0.0-*" and I ended up with "1.0.0-preview3-final"

Looks like dotnet-watch is trying to bring in a whole new .NET Core. It wants 1.1.0. This new dotnet-watch is part of the wave of new preview stuff from 1.1.0.

But I want to stay on the released and supported "LTS" (long term support) stuff, not the new fancy builds.

I shouldn't have used 1.0.0-* as it was ambiguous. That might be great for my local versions or when I intend to chase the latest but not in this case.

I updated my version in my project.json to this and did a restore.

"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final",

Now I can reliably run dotnet restore and get what I want, and both dotnet watch and dotnet run use the same underlying runtime.


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.


© 2016 Scott Hanselman. All rights reserved.
     

Self-contained .NET Core Applications

Just in case you missed it, .NET is all open source now and .NET Core is a free, open source, cross-platform framework that you can download and start with in <10 minutes. You can get it on Mac, Windows, and a half-dozen Unixes at http://dot.net. Take that along with the free, cross-platform Visual Studio Code and you’ll be writing C# and F# all over the place.

Ok, that said, there’s two ways to deploy a .NET Core application. There’s FDD and SCD. Since TLAs (three letter acronyms) are stupid, that’s Framework-dependent and Self-contained. When .NET Core is installed it ends up in C:\program files\dotnet on Windows, for example. In the “Shared” folder there’s a bunch of .NET stuff that is, well, shared. There may be multiple folders, as you can see in my folder below. You can have many and multiple installs of .NET Core.

When you’re installing your app and its dependencies BUT NOT .NET Core itself, you’re dependent on .NET Core already being on the target machine. That’s fine for Web Apps or systems with lots of apps, but what if I want to write an app and give it to you as zip or on a USB key and and I just want it to work. I’ll include .NET Core as well so the whole thing is a Self Contained Deployment.

It will make my “Hello World” application larger than if I was using an existing system-wide install, but I know it’ll Just Work because it’ll be totally self-contained.

Where is .NET Core installed to?

If I deploy my app along with .NET Core it’s important to remember that I’ll be responsible for servicing .NET Core and keeping it up to date. I also need to decide on my target platforms ahead of time. If I want it to run on Windows, Mac, and Linux AND just work, I’ll need to include those target platforms and build deployment packages for them. This all makes mostly intuitive sense but it’s good to know.

I’ll take my little app (I’m just using a “dotnet new” app) and I’ll modify project.json in a text editor.

My app is a .NETCore.App, but it’s not going to use the .NET Core platform that’s installed. It’ll use a local version so I’ll remove “type=”platform”” from this dependency.

"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.1"
}
}
}
}

Next I’ll make a runtimes section to specify which ones I want to target. There’s a list of ALL the Runtime IDs here.

"runtimes": {
"win10-x64": {},
"osx.10.10-x64": {},
"ubuntu.14.04-x64": {}
}

After running “dotnet restore” you’ll want to build for each of these like this:

dotnet build -r win10-x64
dotnet build -r osx.10.10-x64
dotnet build -r ubuntu.14.04-x64

And then publish release versions after you’ve tested, etc.

dotnet publish -c release -r win10-x64
dotnet publish -c release -r osx.10.10-x64
dotnet publish -c release -r ubuntu.14.04-x64

Once this is done, I’ve got my app self-contained in n folders, ready to deploy to whatever systems I want.

Self-contained .NET app built for 3 OSs

You can see in the Win10 folder there’s my “MYAPPLICATION.exe” (mine is called scd.exe) that can be run, rather than running things like developers do with “dotnet run.”

I run foo.exe, not dotnet.exe now

There’s lots of good documentation about how you can tune and define exactly what gets deployed with your self contained application over at the .NET Core Docs. You can do considerable trimming to .NET Core, and there’s talk of that becoming more and more automated in the future, possibly down to the method level.


Sponsor: Big thanks to Redgate for sponsoring the feed this week. Discover the world’s most trusted SQL Server comparison tool. Enjoy a free trial of SQL Compare, the industry standard for comparing and deploying SQL Server schemas.


© 2016 Scott Hanselman. All rights reserved.
     

Just in case you missed it, .NET is all open source now and .NET Core is a free, open source, cross-platform framework that you can download and start with in <10 minutes. You can get it on Mac, Windows, and a half-dozen Unixes at http://dot.net. Take that along with the free, cross-platform Visual Studio Code and you'll be writing C# and F# all over the place.

Ok, that said, there's two ways to deploy a .NET Core application. There's FDD and SCD. Since TLAs (three letter acronyms) are stupid, that's Framework-dependent and Self-contained. When .NET Core is installed it ends up in C:\program files\dotnet on Windows, for example. In the "Shared" folder there's a bunch of .NET stuff that is, well, shared. There may be multiple folders, as you can see in my folder below. You can have many and multiple installs of .NET Core.

When you're installing your app and its dependencies BUT NOT .NET Core itself, you're dependent on .NET Core already being on the target machine. That's fine for Web Apps or systems with lots of apps, but what if I want to write an app and give it to you as zip or on a USB key and and I just want it to work. I'll include .NET Core as well so the whole thing is a Self Contained Deployment.

It will make my "Hello World" application larger than if I was using an existing system-wide install, but I know it'll Just Work because it'll be totally self-contained.

Where is .NET Core installed to?

If I deploy my app along with .NET Core it's important to remember that I'll be responsible for servicing .NET Core and keeping it up to date. I also need to decide on my target platforms ahead of time. If I want it to run on Windows, Mac, and Linux AND just work, I'll need to include those target platforms and build deployment packages for them. This all makes mostly intuitive sense but it's good to know.

I'll take my little app (I'm just using a "dotnet new" app) and I'll modify project.json in a text editor.

My app is a .NETCore.App, but it's not going to use the .NET Core platform that's installed. It'll use a local version so I'll remove "type="platform"" from this dependency.

"frameworks": {

"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.1"
}
}
}
}

Next I'll make a runtimes section to specify which ones I want to target. There's a list of ALL the Runtime IDs here.

"runtimes": {

"win10-x64": {},
"osx.10.10-x64": {},
"ubuntu.14.04-x64": {}
}

After running "dotnet restore" you'll want to build for each of these like this:

dotnet build -r win10-x64

dotnet build -r osx.10.10-x64
dotnet build -r ubuntu.14.04-x64

And then publish release versions after you've tested, etc.

dotnet publish -c release -r win10-x64

dotnet publish -c release -r osx.10.10-x64
dotnet publish -c release -r ubuntu.14.04-x64

Once this is done, I've got my app self-contained in n folders, ready to deploy to whatever systems I want.

Self-contained .NET app built for 3 OSs

You can see in the Win10 folder there's my "MYAPPLICATION.exe" (mine is called scd.exe) that can be run, rather than running things like developers do with "dotnet run."

I run foo.exe, not dotnet.exe now

There's lots of good documentation about how you can tune and define exactly what gets deployed with your self contained application over at the .NET Core Docs. You can do considerable trimming to .NET Core, and there's talk of that becoming more and more automated in the future, possibly down to the method level.


Sponsor: Big thanks to Redgate for sponsoring the feed this week. Discover the world’s most trusted SQL Server comparison tool. Enjoy a free trial of SQL Compare, the industry standard for comparing and deploying SQL Server schemas.



© 2016 Scott Hanselman. All rights reserved.
     

Publishing an ASP.NET Core website to a cheap Linux VM host

A little Linux VM on Azure is like $13 a month. You can get little Linux machines all over for between $10-15 a month. On Linode they are about $10 a month so I figured it would be interesting to setup an ASP.NET Core website running on .NET Core. As you may know, .NET Core is free, open source, cross platform and runs basically everywhere.

Step 0 – Get a cheap host

I went to Linode (or anywhere) and got the cheapest Linux machine they offered. In this case it’s an Ubuntu 14.04 LTS Profile, 640bit, 4.6.5 Kernel.

I signed up for a tiny VM at Linode

Since I’m on Windows but I want to SSH into this Linux machine I’ll need a SSH client. There’s a bunch of options.

Step 0.5 – Setup a user that isn’t root

It’s always a good idea to avoid being root. After logging into the system as root, I made a new user and give them sudo (super user do):

adduser scott
usermod -aG sudo scott

Then I’ll logout and go back in as scott.

Step 1 – Get .NET Core on your Linux Machine

Head over to http://dot.net to get .NET Core and follow the instructions. There’s at least 8 Linuxes supported in 6 flavors so you should have no trouble. I followed the Ubuntu instructions.

To make sure it works after you’ve set it up, make a quick console app like this and run it.

mkdir testapp
cd testapp
dotnet new
dotnet restore
dotnet run

If it runs, then you’ve got .NET Core installed and you can move on to making a web app and exposing it to the internet.

NOTE: If “dotnet restore” fails with a segmentation fault, you may be running into this issue with some 64-bit Linux Kernels. Here’s commands to fix it that worked for me on Ubuntu 14.04 when I hit this. The fix has been released as a NuGet now but it will be included with the next minor release of .NET Core, but if you ever need to manually update the CoreCLR you can.

Step 2 – Make an ASP.NET Core website

You can make an ASP.NET Core website that is very basic and very empty and that’s OK. You can also get Yeoman and use the ASP.NET yeoman-based generators to get more choices. There is also the great ASP.NET MVC Boilerplate project for Visual Studio.

Or you can just start with:

dotnet new -t web

Today, this default site uses npm, gulp, and bower to manage JavaScript and CSS dependencies. In the future there will be options that don’t require as much extra stuff but for now, in order to dotnet restore this site I’ll need npm and what not so I’ll do this to get node, npm, etc.

sudo install npm
sudo npm install gulp
sudo npm install bower

Now I can dotnet restore easily and run my web app to test. It will startup on localhost:5000 usually.

$ dotnet restore
$ dotnet run
[email protected]:~/dotnettest$ dotnet run
Project dotnettest (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]
User profile is available. Using '/home/scott/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.
Hosting environment: Production
Content root path: /home/scott/dotnettest
Now listening on: http://localhost:5000

Of course, having something startup on localhost:5000 doesn’t help me as I’m over here at home so I can’t test a local website like this. I want to expose this site (via a port) to the outside world. I want something like http://mysupermachine -> inside my machine -> localhost:5000.

Step 3 – Expose your web app to the outside.

I could tell Kestrel – that’s the .NET Web Server – to expose itself to Port 80, although you usually want to have another process between you and the outside world.

You can do this a few ways. You can open open Program.cs with a editor like “pico” and add a .UseUrls() call to the WebHostBuilder like this.

var host = new WebHostBuilder()
.UseKestrel()
.UseUrls("http://*:80")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();

Here the * binds to all the network adapters and it listens on Port 80. Putting http://0.0.0.0:80 also works.

You might have permission issues doing this and need to elevate the dotnet process and webserver which is also a problem so let’s just keep it at a high internal port and reverse proxy the traffic with something like Nginx or Apache. We’ll pull out the hard-coded port from the code and change the Program.cs to use a .json config file.

public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.Build();

var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();

host.Run();
}

The hosting.json file is just this:

{
"server.urls": "http://localhost:5123"
}

We can also use “AddCommandLine(args) instead of “AddJsonFile()” and pass in –server.urls=http://*:5123 on the command line. It’s up to you. You can also use the ASPNETCORE_URLS environment variable.

NOTE: I’m doing this work a folder under my home folder ~ or now. I’ll later compile and “publish” this website to something like /var/dotnettest when I want it seen.

Step 4 – Setup a Reverse Proxy like Nginx

I’m following the detailed instructions at the ASP.NET Core Docs site called “Publish to a Linux Production Environment.” (All the docs are on GitHub as well)

I’m going to bring in Nginx and start it.

sudo apt-get install nginx
sudo service nginx start

I’m going to change the default Nginx site to point to my (future) running ASP.NET Core web app. I’ll open and change /etc/nginx/sites-available/default and make it look like this. Note the port number. Nginx is a LOT more complex than this and has a lot of nuance, so when you are ready to go into Super Official Production, be sure to explore what the perfect Nginx Config File looks like and change it to your needs.

server {
listen 80;
location / {
proxy_pass http://localhost:5123;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

Then we’ll check it and reload the config.

sudo nginx -t 
sudo nginx -s reload

Step 5 – Keep your website running

The website isn’t up and running on localhost:5123 yet (unless you’ve run it yourself and kept it running!) so we’ll need an app or a monitor to run it and keep it running. There’s an app called Supervisor that is good at that so I’ll add it.

sudo apt-get install supervisor

Here is where you/we/I/errbody needs to get the paths and names right, so be aware. I’m over in ~/testapp or something. I need to publish my site into a final location so I’m going to run dotnet publish, then copy the reuslts into /var/dotnettest where it will live.

dotnet publish
publish: Published to /home/scott/dotnettest/bin/Debug/netcoreapp1.0/publish
sudo cp -a /home/scott/dotnettest/bin/Debug/netcoreapp1.0/publish /var/dotnettest

Now I’m going to make a file (again, I use pico because I’m not as awesome as emacs or vim) called /src/supervisor/conf.d/dotnettest.conf to start my app and keep it running:

[program:dotnettest]
command=/usr/bin/dotnet /var/dotnettest/dotnettest.dll --server.urls:http://*:5123
directory=/var/dotnettest/
autostart=true
autorestart=true
stderr_logfile=/var/log/dotnettest.err.log
stdout_logfile=/var/log/dotnettest.out.log
environment=ASPNETCORE_ENVIRONMENT=Production
user=www-data
stopsignal=INT

Now we start and stop Supervisor and watch/tail its logs to see our app startup!

sudo service supervisor stop
sudo service supervisor start
sudo tail -f /var/log/supervisor/supervisord.log
#and the application logs if you like
sudo tail -f /var/log/dotnettest.out.log

If all worked out (if it didn’t, it’ll be a name or a path so keep trying!) you’ll see the supervisor log with dotnet starting up, running your app.

Hey it's dotnet on linux

Remember the relationships.

  • Dotnet – runs your website
  • Nginx or Apache – Listens on Port 80 and forwards HTTP calls to your website
  • Supervisor – Keeps your app running

Next, I might want to setup a continuous integration build, or SCP/SFTP to handle deployment of my app. That way I can develop locally and push up to my Linux machine.

Hey it's my ASP.NET Core app on Linux

Of course, there are a dozen other ways to publish an ASP.NET Core site, not to mention Docker. I’ll post about Docker another time, but for now, I was able to get my ASP.NET Core website published to a cheap $10 host in less than an hour. You can use the same tools to manage a .NET Core site that you use to manage any site be it PHP, nodejs, Ruby, or whatever makes you happy.


Sponsor: Aspose makes programming APIs for working with files, like: DOC, XLS, PPT, PDF and countless more.  Developers can use their products to create, convert, modify, or manage files in almost any way.  Aspose is a good company and they offer solid products.  Check them out, and download a free evaluation.


© 2016 Scott Hanselman. All rights reserved.
     

A little Linux VM on Azure is like $13 a month. You can get little Linux machines all over for between $10-15 a month. On Linode they are about $10 a month so I figured it would be interesting to setup an ASP.NET Core website running on .NET Core. As you may know, .NET Core is free, open source, cross platform and runs basically everywhere.

Step 0 - Get a cheap host

I went to Linode (or anywhere) and got the cheapest Linux machine they offered. In this case it's an Ubuntu 14.04 LTS Profile, 640bit, 4.6.5 Kernel.

I signed up for a tiny VM at Linode

Since I'm on Windows but I want to SSH into this Linux machine I'll need a SSH client. There's a bunch of options.

Step 0.5 - Setup a user that isn't root

It's always a good idea to avoid being root. After logging into the system as root, I made a new user and give them sudo (super user do):

adduser scott

usermod -aG sudo scott

Then I'll logout and go back in as scott.

Step 1 - Get .NET Core on your Linux Machine

Head over to http://dot.net to get .NET Core and follow the instructions. There's at least 8 Linuxes supported in 6 flavors so you should have no trouble. I followed the Ubuntu instructions.

To make sure it works after you've set it up, make a quick console app like this and run it.

mkdir testapp

cd testapp
dotnet new
dotnet restore
dotnet run

If it runs, then you've got .NET Core installed and you can move on to making a web app and exposing it to the internet.

NOTE: If "dotnet restore" fails with a segmentation fault, you may be running into this issue with some 64-bit Linux Kernels. Here's commands to fix it that worked for me on Ubuntu 14.04 when I hit this. The fix has been released as a NuGet now but it will be included with the next minor release of .NET Core, but if you ever need to manually update the CoreCLR you can.

Step 2 - Make an ASP.NET Core website

You can make an ASP.NET Core website that is very basic and very empty and that's OK. You can also get Yeoman and use the ASP.NET yeoman-based generators to get more choices. There is also the great ASP.NET MVC Boilerplate project for Visual Studio.

Or you can just start with:

dotnet new -t web

Today, this default site uses npm, gulp, and bower to manage JavaScript and CSS dependencies. In the future there will be options that don't require as much extra stuff but for now, in order to dotnet restore this site I'll need npm and what not so I'll do this to get node, npm, etc.

sudo install npm

sudo npm install gulp
sudo npm install bower

Now I can dotnet restore easily and run my web app to test. It will startup on localhost:5000 usually.

$ dotnet restore

$ dotnet run
[email protected]:~/dotnettest$ dotnet run
Project dotnettest (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]
User profile is available. Using '/home/scott/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.
Hosting environment: Production
Content root path: /home/scott/dotnettest
Now listening on: http://localhost:5000

Of course, having something startup on localhost:5000 doesn't help me as I'm over here at home so I can't test a local website like this. I want to expose this site (via a port) to the outside world. I want something like http://mysupermachine -> inside my machine -> localhost:5000.

Step 3 - Expose your web app to the outside.

I could tell Kestrel - that's the .NET Web Server - to expose itself to Port 80, although you usually want to have another process between you and the outside world.

You can do this a few ways. You can open open Program.cs with a editor like "pico" and add a .UseUrls() call to the WebHostBuilder like this.

var host = new WebHostBuilder()

.UseKestrel()
.UseUrls("http://*:80")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();

Here the * binds to all the network adapters and it listens on Port 80. Putting http://0.0.0.0:80 also works.

You might have permission issues doing this and need to elevate the dotnet process and webserver which is also a problem so let's just keep it at a high internal port and reverse proxy the traffic with something like Nginx or Apache. We'll pull out the hard-coded port from the code and change the Program.cs to use a .json config file.

public static void Main(string[] args)

{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.Build();

var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();

host.Run();
}

The hosting.json file is just this:

{

"server.urls": "http://localhost:5123"
}

We can also use "AddCommandLine(args) instead of "AddJsonFile()" and pass in --server.urls=http://*:5123 on the command line. It's up to you. You can also use the ASPNETCORE_URLS environment variable.

NOTE: I'm doing this work a folder under my home folder ~ or now. I'll later compile and "publish" this website to something like /var/dotnettest when I want it seen.

Step 4 - Setup a Reverse Proxy like Nginx

I'm following the detailed instructions at the ASP.NET Core Docs site called "Publish to a Linux Production Environment." (All the docs are on GitHub as well)

I'm going to bring in Nginx and start it.

sudo apt-get install nginx

sudo service nginx start

I'm going to change the default Nginx site to point to my (future) running ASP.NET Core web app. I'll open and change /etc/nginx/sites-available/default and make it look like this. Note the port number. Nginx is a LOT more complex than this and has a lot of nuance, so when you are ready to go into Super Official Production, be sure to explore what the perfect Nginx Config File looks like and change it to your needs.

server {

listen 80;
location / {
proxy_pass http://localhost:5123;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

Then we'll check it and reload the config.

sudo nginx -t 

sudo nginx -s reload

Step 5 - Keep your website running

The website isn't up and running on localhost:5123 yet (unless you've run it yourself and kept it running!) so we'll need an app or a monitor to run it and keep it running. There's an app called Supervisor that is good at that so I'll add it.

sudo apt-get install supervisor

Here is where you/we/I/errbody needs to get the paths and names right, so be aware. I'm over in ~/testapp or something. I need to publish my site into a final location so I'm going to run dotnet publish, then copy the reuslts into /var/dotnettest where it will live.

dotnet publish

publish: Published to /home/scott/dotnettest/bin/Debug/netcoreapp1.0/publish
sudo cp -a /home/scott/dotnettest/bin/Debug/netcoreapp1.0/publish /var/dotnettest

Now I'm going to make a file (again, I use pico because I'm not as awesome as emacs or vim) called /src/supervisor/conf.d/dotnettest.conf to start my app and keep it running:

[program:dotnettest]

command=/usr/bin/dotnet /var/dotnettest/dotnettest.dll --server.urls:http://*:5123
directory=/var/dotnettest/
autostart=true
autorestart=true
stderr_logfile=/var/log/dotnettest.err.log
stdout_logfile=/var/log/dotnettest.out.log
environment=ASPNETCORE_ENVIRONMENT=Production
user=www-data
stopsignal=INT

Now we start and stop Supervisor and watch/tail its logs to see our app startup!

sudo service supervisor stop

sudo service supervisor start
sudo tail -f /var/log/supervisor/supervisord.log
#and the application logs if you like
sudo tail -f /var/log/dotnettest.out.log

If all worked out (if it didn't, it'll be a name or a path so keep trying!) you'll see the supervisor log with dotnet starting up, running your app.

Hey it's dotnet on linux

Remember the relationships.

  • Dotnet - runs your website
  • Nginx or Apache - Listens on Port 80 and forwards HTTP calls to your website
  • Supervisor - Keeps your app running

Next, I might want to setup a continuous integration build, or SCP/SFTP to handle deployment of my app. That way I can develop locally and push up to my Linux machine.

Hey it's my ASP.NET Core app on Linux

Of course, there are a dozen other ways to publish an ASP.NET Core site, not to mention Docker. I'll post about Docker another time, but for now, I was able to get my ASP.NET Core website published to a cheap $10 host in less than an hour. You can use the same tools to manage a .NET Core site that you use to manage any site be it PHP, nodejs, Ruby, or whatever makes you happy.


Sponsor: Aspose makes programming APIs for working with files, like: DOC, XLS, PPT, PDF and countless more.  Developers can use their products to create, convert, modify, or manage files in almost any way.  Aspose is a good company and they offer solid products.  Check them out, and download a free evaluation.



© 2016 Scott Hanselman. All rights reserved.