This is one of those "Did you know you could do THAT?" Many folks have figured out that C#/F#/.NET is cross-platform and open0source and runs on basically any operating system. People are using it to create micro services, web sites, and webAPI's all over. Not to mention iPhone/Android apps with Xamarin and video games with Unity and MonoGame.

But what about cross platform UIs?

While not officially supported by Microsoft - you can do some awesome stuff...as is how Open Source is supposed to work! Remember that there's a family of .NET Runtimes now, there's the .NET Framework on Windows, there's xplat .NET Core, and there's xplat Mono.

Eto.Forms has been in development since 2012 and is a cross-platform framework for creating GUI (Graphical User Interface, natch) applications with .NET that run across multiple platforms using their native toolkit. Not like Java in the 90s with custom painted buttons on canvas.

It's being used for real stuff! In fact, PabloDraw is an Ansi/Ascii text editor that you didn't know you needed in your life. But you do. It runs on Windows, Mac, and Linux and was written using Eto.Forms but has a native UI on each platform. Be sure to check out Curtis Wensley's Twitter account for some cool examples of what PabloDraw and Eto.Forms can do!

OS X: MonoMac or Xamarin.Mac (and also iOS via Xamarin)

Linux: GTK# 2 or 3

Windows: Windows Forms (using GDI or Direct2D) or WPF

Here's an example Hello World. Note that it's not just Code First, you can also use Xaml, or even Json (.jeto) to layout your forms!

This is one of those "Did you know you could do THAT?" Many folks have figured out that C#/F#/.NET is cross-platform and open0source and runs on basically any operating system. People are using it to create micro services, web sites, and webAPI's all over. Not to mention iPhone/Android apps with Xamarin and video games with Unity and MonoGame.

But what about cross platform UIs?

While not officially supported by Microsoft - you can do some awesome stuff...as is how Open Source is supposed to work! Remember that there's a family of .NET Runtimes now, there's the .NET Framework on Windows, there's xplat .NET Core, and there's xplat Mono.

Eto.Forms has been in development since 2012 and is a cross-platform framework for creating GUI (Graphical User Interface, natch) applications with .NET that run across multiple platforms using their native toolkit. Not like Java in the 90s with custom painted buttons on canvas.

It's being used for real stuff! In fact, PabloDraw is an Ansi/Ascii text editor that you didn't know you needed in your life. But you do. It runs on Windows, Mac, and Linux and was written using Eto.Forms but has a native UI on each platform. Be sure to check out Curtis Wensley's Twitter account for some cool examples of what PabloDraw and Eto.Forms can do!

OS X: MonoMac or Xamarin.Mac (and also iOS via Xamarin)

Linux: GTK# 2 or 3

Windows: Windows Forms (using GDI or Direct2D) or WPF

Here's an example Hello World. Note that it's not just Code First, you can also use Xaml, or even Json (.jeto) to layout your forms!

]]>
https://www.hanselman.com/blog/SettingUpApplicationInsightsTook10MinutesItCreatedTwoDaysOfWorkForMe.aspxhttps://www.hanselman.com/blog/Trackback.aspx?guid=5e70db26-4dd1-4c29-a49d-760934c42497https://www.hanselman.com/blog/pingback.aspxhttps://www.hanselman.com/blog/PermaLink.aspx?guid=5e70db26-4dd1-4c29-a49d-760934c42497Scott Hanselmanhttps://www.hanselman.com/blog/CommentView.aspx?guid=5e70db26-4dd1-4c29-a49d-760934c42497https://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=5e70db26-4dd1-4c29-a49d-760934c4249711Setting up Application Insights took 10 minutes. It created two days of work for me.https://www.hanselman.com/blog/PermaLink.aspx?guid=5e70db26-4dd1-4c29-a49d-760934c42497http://feeds.feedblitz.com/~/532136492/0/scotthanselman~Setting-up-Application-Insights-took-minutes-It-created-two-days-of-work-for-me.aspx
Tue, 13 Mar 2018 06:01:10 GMT

I added Application Insights to the site in about 10 min just a few days ago. It was super easy to setup and basically automatic in Visual Studio 2017 Community. I left the defaults, installed a bit of script on the client, and enabled the server-side profiler, and AppInsights already found a few interesting things.

It took 10 minutes to set up App Insights. It took two days (and work continues) to fix what it found. I love it. This tool has already given me a deeper insight into how my code runs and how it's behaving - and I'm just scratching the service. I'll need to do some videos and/or more blog posts to dig deeper. Truly, you need to try it.

Slow performance in other countries

I could fill this blog post with dozens of awesome screenshots of the useful charts, graphs, and filters that I got by just turning on AppInsights. But the most interesting part is that I turned it on really expecting nothing. I figured I'd get some "Google Analytics"-type behavior.

Then I got this email:

Huh. I had set up the Azure CDN at images.hanselminutes.com to handle all the faces for each episode. I then added lazy loading so that the webite only loads the images that enter the browser's viewport. I figured I was pretty much done.

However I didn't really think about the page itself as it loads for folks from around the world - given that it's hosted on Azure in the West US.

Ideally I'd want the site to load in less than a second, but this is my archives page with 600 shows so it's pretty heavy.

Yuck. I have a few options. I could pay and load up another copy of the site in South Asia and then do some global load balancing. However, I'm hosting this on a single small (along with a dozen other sites) so I don't want to really pay much to fix this.

I ended up signing up for a free account at CloudFlare and set up caching for my HTML. The images stay the same. served by the Azure CDN.

Fixing Random and regular Server 500 errors

I left the site up for a while and came back later to a warning. You can see my site availability is just 93%. Note that there's "2 Servers?" That's because one is my local machine! Very cool that AppInsights also (optionally) tracks your local development server as well.

When I dig in I see a VERY interesting sawtooth pattern.

Pro Tip - Recognizing that a Sawtooth Pattern is a Bad Thing (tm) is an important DevOps thing. Why is this happening regularly? Is it exactly regularly (like every 4 hours on a schedule?) or somewhat regularly (like a garbage collection issue?)

What do these operations have in common? Look closely.

It's not a GET it's a HEAD. Remember that HTTP Verbs are more than GET, POST, PUT, DELETE. There's also HEAD. It literally is a HEADer call. Like a GET, but no body.

HTTP HEAD - The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.

I installed HTTPie - which is like curl or wget for humans - and issue a HEAD command from my local machine while under the debugger.

Ok that is bad. See the 500? I check out AppInsights and see it has the full call stack. See it's getting a NullReferenceException as it tries to Render() the Razor page?

It turns out since I'm using Razor Pages, I have implemented "OnGet" where I do my data base work then pass a model to the pages to generate HTML. However, if someone issues a HEAD, then the pages still run but the local data work never happened (I have no OnHead() call). I have a few options here. I could handle HEAD myself. I could no-op it, but that'd be a lie.

THOUGHT: I think this behavior is sub-optimal. While GET and POST are distinct and it makes sense to require an OnGet() and OnPost(), I think that HEAD is special. It's basically a GET with a "don't return the body" flag set. So why not have Razor Pages automatically delegate OnHead to OnGet, unless there's an explicit OnHead() declared? I'll file an issue on GitHub because I don't like this behavior and I find it counter-intuitive. I could also register a global IPageFilter to make this work for all my site's pages.

The simplest thing to do is just to delegate the OnHead to to the OnGet handler.

Bonus - Application Map

Since I have AppInsights enabled on both the client and the server, I can see this cool live Application Map. I'll check again in a few days to see if I have fewer errors. You can see where my Podcast Site calls into the backend data service at Simplecast.

I saw a few failures in my call to SimpleCast's API as I was failing to consistently set my API key. Everything in this map can be drilled down into.

Bonus - Web Performance Testing

I figured while I was in the Azure Portal I would also take advantage of the free performance testing. I did a simulated aggressive 250 users beating on the site. Average response time is 1.22 seconds and I was doing over 600 req/second.

I am learning a ton of stuff. I have more things to fix, more improvements to make, and more insights to dig into. I LOVE that it's creating all this work for me because it's giving me a better application/website!

I added Application Insights to the site in about 10 min just a few days ago. It was super easy to setup and basically automatic in Visual Studio 2017 Community. I left the defaults, installed a bit of script on the client, and enabled the server-side profiler, and AppInsights already found a few interesting things.

It took 10 minutes to set up App Insights. It took two days (and work continues) to fix what it found. I love it. This tool has already given me a deeper insight into how my code runs and how it's behaving - and I'm just scratching the service. I'll need to do some videos and/or more blog posts to dig deeper. Truly, you need to try it.

Slow performance in other countries

I could fill this blog post with dozens of awesome screenshots of the useful charts, graphs, and filters that I got by just turning on AppInsights. But the most interesting part is that I turned it on really expecting nothing. I figured I'd get some "Google Analytics"-type behavior.

Then I got this email:

Huh. I had set up the Azure CDN at images.hanselminutes.com to handle all the faces for each episode. I then added lazy loading so that the webite only loads the images that enter the browser's viewport. I figured I was pretty much done.

However I didn't really think about the page itself as it loads for folks from around the world - given that it's hosted on Azure in the West US.

Ideally I'd want the site to load in less than a second, but this is my archives page with 600 shows so it's pretty heavy.

Yuck. I have a few options. I could pay and load up another copy of the site in South Asia and then do some global load balancing. However, I'm hosting this on a single small (along with a dozen other sites) so I don't want to really pay much to fix this.

I ended up signing up for a free account at CloudFlare and set up caching for my HTML. The images stay the same. served by the Azure CDN.

Fixing Random and regular Server 500 errors

I left the site up for a while and came back later to a warning. You can see my site availability is just 93%. Note that there's "2 Servers?" That's because one is my local machine! Very cool that AppInsights also (optionally) tracks your local development server as well.

When I dig in I see a VERY interesting sawtooth pattern.

Pro Tip - Recognizing that a Sawtooth Pattern is a Bad Thing (tm) is an important DevOps thing. Why is this happening regularly? Is it exactly regularly (like every 4 hours on a schedule?) or somewhat regularly (like a garbage collection issue?)

What do these operations have in common? Look closely.

It's not a GET it's a HEAD. Remember that HTTP Verbs are more than GET, POST, PUT, DELETE. There's also HEAD. It literally is a HEADer call. Like a GET, but no body.

HTTP HEAD - The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.

I installed HTTPie - which is like curl or wget for humans - and issue a HEAD command from my local machine while under the debugger.

Ok that is bad. See the 500? I check out AppInsights and see it has the full call stack. See it's getting a NullReferenceException as it tries to Render() the Razor page?

It turns out since I'm using Razor Pages, I have implemented "OnGet" where I do my data base work then pass a model to the pages to generate HTML. However, if someone issues a HEAD, then the pages still run but the local data work never happened (I have no OnHead() call). I have a few options here. I could handle HEAD myself. I could no-op it, but that'd be a lie.

THOUGHT: I think this behavior is sub-optimal. While GET and POST are distinct and it makes sense to require an OnGet() and OnPost(), I think that HEAD is special. It's basically a GET with a "don't return the body" flag set. So why not have Razor Pages automatically delegate OnHead to OnGet, unless there's an explicit OnHead() declared? I'll file an issue on GitHub because I don't like this behavior and I find it counter-intuitive. I could also register a global IPageFilter to make this work for all my site's pages.

The simplest thing to do is just to delegate the OnHead to to the OnGet handler.

Bonus - Application Map

Since I have AppInsights enabled on both the client and the server, I can see this cool live Application Map. I'll check again in a few days to see if I have fewer errors. You can see where my Podcast Site calls into the backend data service at Simplecast.

I saw a few failures in my call to SimpleCast's API as I was failing to consistently set my API key. Everything in this map can be drilled down into.

Bonus - Web Performance Testing

I figured while I was in the Azure Portal I would also take advantage of the free performance testing. I did a simulated aggressive 250 users beating on the site. Average response time is 1.22 seconds and I was doing over 600 req/second.

I am learning a ton of stuff. I have more things to fix, more improvements to make, and more insights to dig into. I LOVE that it's creating all this work for me because it's giving me a better application/website!

Pro Tip: Be aware, you can still get up to 10x faster local builds but still keep your site's runtime as 2.0 to lower risk. So there's little reason to not download the .NET Core 2.1 Preview and test your build speeds.

At this point the podcast site is live in Azure at https://hanselminutes.com. Now that I've moved off of the (very old) site I've quickly set up some best practices in just a few hours. I should have taken the time to upgrade this site - and its "devops" a long time ago.

Here's a few things I was able to get done just this evening while the boys' did homework. Each of these tasks were between 5 and 15 min. So not a big investment, but they represented real value I'd been wanting to add to the site.

Git Deploy for Production

The podcast site's code now lives in GitHub and deployment to production is a git push to master.

A "deployment slot" for staging

Some people like to have the master branch be Production, then they make a branch called Staging for a secondary staging site. Since Azure App Services (WebSites) has "deployment slots" I choose to do it differently. I deploy to Production from GitHub, sure, but I prefer to push manually to staging rather than litter my commits (and clean them up or squash commits later - it's just my preference) with little stuff.

I hooked up Git Deployment but the git repro is in Azure and just for deploy. Then "git remote add azure ..." so when I want to deploy to staging it's:

git push staging

I use it for testing, so ya, it could have been test/dev, etc, but you get the idea. Plus the Deployment Slot/Staging Site is free as it's on the same Azure App Service Plan.

A more sophisticated - but just as easy - plan would be to push to staging, get it perfect then do a "hot swap" with a single button click.

Deployment Slots can have their own independent settings if you click "Slot Setting." Here I've set that this ASPNETCORE_ENVIRONMENT is "Staging" while the main one is "Production."

The ASP.NET Core runtime picks up that environment variable and I can conditionally run code based on Environment. I run as "Development" on my local machine. For example:

Don't let Google Index the Staging Site - No Robots

You should be careful to not let Google/Bing/DuckDuckGo index your staging site if it's public. Since I have an environment set on my slot, I can just add this Meta Robots element to the site's main layout. Note also that I use minified CSS when I'm not in Development.

Pro Tip: Be aware, you can still get up to 10x faster local builds but still keep your site's runtime as 2.0 to lower risk. So there's little reason to not download the .NET Core 2.1 Preview and test your build speeds.

At this point the podcast site is live in Azure at https://hanselminutes.com. Now that I've moved off of the (very old) site I've quickly set up some best practices in just a few hours. I should have taken the time to upgrade this site - and its "devops" a long time ago.

Here's a few things I was able to get done just this evening while the boys' did homework. Each of these tasks were between 5 and 15 min. So not a big investment, but they represented real value I'd been wanting to add to the site.

Git Deploy for Production

The podcast site's code now lives in GitHub and deployment to production is a git push to master.

A "deployment slot" for staging

Some people like to have the master branch be Production, then they make a branch called Staging for a secondary staging site. Since Azure App Services (WebSites) has "deployment slots" I choose to do it differently. I deploy to Production from GitHub, sure, but I prefer to push manually to staging rather than litter my commits (and clean them up or squash commits later - it's just my preference) with little stuff.

I hooked up Git Deployment but the git repro is in Azure and just for deploy. Then "git remote add azure ..." so when I want to deploy to staging it's:

git push staging

I use it for testing, so ya, it could have been test/dev, etc, but you get the idea. Plus the Deployment Slot/Staging Site is free as it's on the same Azure App Service Plan.

A more sophisticated - but just as easy - plan would be to push to staging, get it perfect then do a "hot swap" with a single button click.

Deployment Slots can have their own independent settings if you click "Slot Setting." Here I've set that this ASPNETCORE_ENVIRONMENT is "Staging" while the main one is "Production."

The ASP.NET Core runtime picks up that environment variable and I can conditionally run code based on Environment. I run as "Development" on my local machine. For example:

Don't let Google Index the Staging Site - No Robots

You should be careful to not let Google/Bing/DuckDuckGo index your staging site if it's public. Since I have an environment set on my slot, I can just add this Meta Robots element to the site's main layout. Note also that I use minified CSS when I'm not in Development.

There's a few interesting things happening here. Youc an see before I had the runtime for .NET Core 2.0.5, and now I also have the 2.1.0 Preview.

It can also be a little confusing that the SDK and Runtime sometimes have different versions, similar to JREs and JDKs. Simply stated - the thing that builds sometimes updates while then thing that runs doesn't. So the .NET Core SDK and compilers might get fixes but the runtime doesn't. I'm told they're going to line things up better. You can read deeply on versioning if you like.

You'll also notice AspNetCore.App, which is a metapackage (package of packages) that's got less than All and helps you make smaller apps.

If you install a beta or preview you might be worried it'll mess stuff up. It won't.

You can type "dotnet new globaljson" and make a file that looks like this! Then "pin" the SDK version you want to use:

Let's make the SDK version the new .NET Core 2.1 Preview 1 - it has a bunch of build speed improvements.

All I have to do is change the global.json file. Update the sdk version in the global.json and type "dotnet --version" to see that it took.

I can have as many .NET Core SDKs as I like on my machine and I can control what SDK versions are being used on a tree by tree basis. That means you CAN download .NET Core 2.1 and not mess things up if you're paying attention.

There's a few interesting things happening here. Youc an see before I had the runtime for .NET Core 2.0.5, and now I also have the 2.1.0 Preview.

It can also be a little confusing that the SDK and Runtime sometimes have different versions, similar to JREs and JDKs. Simply stated - the thing that builds sometimes updates while then thing that runs doesn't. So the .NET Core SDK and compilers might get fixes but the runtime doesn't. I'm told they're going to line things up better. You can read deeply on versioning if you like.

You'll also notice AspNetCore.App, which is a metapackage (package of packages) that's got less than All and helps you make smaller apps.

If you install a beta or preview you might be worried it'll mess stuff up. It won't.

You can type "dotnet new globaljson" and make a file that looks like this! Then "pin" the SDK version you want to use:

Let's make the SDK version the new .NET Core 2.1 Preview 1 - it has a bunch of build speed improvements.

All I have to do is change the global.json file. Update the sdk version in the global.json and type "dotnet --version" to see that it took.

I can have as many .NET Core SDKs as I like on my machine and I can control what SDK versions are being used on a tree by tree basis. That means you CAN download .NET Core 2.1 and not mess things up if you're paying attention.

One of the great joys of sharing and discovering code online is when you stumble upon something so truly epic, so amazing, that you have to dig in. Head over to https://github.com/axle-h/Retro.Net and ask yourself why this GitHub project has only 20 stars?

Alex Haslehurst has created some retro hardware libraries in open source .NET Core with an Angular Front End!

Please check out my GameBoy emulator written in .NET Core; Retro.Net. Yes, a GameBoy emulator written in .NET Core. Why? Why not. I plan to do a few write-ups about my experience with this project. Firstly: why it was a bad idea.

Luckily the GameBoy CPU, a Sharp LR35902, is derived from the popular and very well documented Zilog Z80 - A microprocessor that is unbelievably still in production today, over 40 years after it’s introduction.

The Z80 is an 8-bit microprocessor, meaning that each operation is natively performed on a single byte. The instruction set does have some 16-bit operations but these are just executed as multiple cycles of 8-bit logic. The Z80 has a 16-bit wide address bus, which logically represents a 64K memory map. Data is transferred to the CPU over an 8-bit wide data bus but this is irrelevant to simulating the system at state machine level. The Z80 and the Intel 8080 that it derives from have 256 I/O ports for accessing external peripherals but the GameBoy CPU has none - favouring memory mapped I/O instead

He didn't just create an emulator - there's lots of those - but uniquely he runs it on the server-side while allowing shared controls in a browser. "In between each unique frame, all connected clients can vote on what the next control input should be. The server will choose the one with the most votes… most of the time." Massively multi-player online GameBoy! Then he streams out the next frame! "GPU rendering is completed on the server once per unique frame, compressed with LZ4 and streamed out to all connected clients over websockets."

This is a great learning repository because:

it has complex business logic on the server-side but the front end uses Angular and web-sockets and open web technologies.

It's also nice that he has a complete multi-stage Dockerfile that is itself a great example of how to build both .NET Core and Angular apps in Docker.

I would encourage you to go STAR and CLONE https://github.com/axle-h/Retro.Net and give it a run with Docker! You can then use Visual Studio Code and .NET Core to compile and run it locally. He's looking for help with GameBoy sound and a Debugger.

One of the great joys of sharing and discovering code online is when you stumble upon something so truly epic, so amazing, that you have to dig in. Head over to https://github.com/axle-h/Retro.Net and ask yourself why this GitHub project has only 20 stars?

Alex Haslehurst has created some retro hardware libraries in open source .NET Core with an Angular Front End!

Please check out my GameBoy emulator written in .NET Core; Retro.Net. Yes, a GameBoy emulator written in .NET Core. Why? Why not. I plan to do a few write-ups about my experience with this project. Firstly: why it was a bad idea.

Luckily the GameBoy CPU, a Sharp LR35902, is derived from the popular and very well documented Zilog Z80 - A microprocessor that is unbelievably still in production today, over 40 years after it’s introduction.

The Z80 is an 8-bit microprocessor, meaning that each operation is natively performed on a single byte. The instruction set does have some 16-bit operations but these are just executed as multiple cycles of 8-bit logic. The Z80 has a 16-bit wide address bus, which logically represents a 64K memory map. Data is transferred to the CPU over an 8-bit wide data bus but this is irrelevant to simulating the system at state machine level. The Z80 and the Intel 8080 that it derives from have 256 I/O ports for accessing external peripherals but the GameBoy CPU has none - favouring memory mapped I/O instead

He didn't just create an emulator - there's lots of those - but uniquely he runs it on the server-side while allowing shared controls in a browser. "In between each unique frame, all connected clients can vote on what the next control input should be. The server will choose the one with the most votes… most of the time." Massively multi-player online GameBoy! Then he streams out the next frame! "GPU rendering is completed on the server once per unique frame, compressed with LZ4 and streamed out to all connected clients over websockets."

This is a great learning repository because:

it has complex business logic on the server-side but the front end uses Angular and web-sockets and open web technologies.

It's also nice that he has a complete multi-stage Dockerfile that is itself a great example of how to build both .NET Core and Angular apps in Docker.

I would encourage you to go STAR and CLONE https://github.com/axle-h/Retro.Net and give it a run with Docker! You can then use Visual Studio Code and .NET Core to compile and run it locally. He's looking for help with GameBoy sound and a Debugger.

First, a disclaimer. Don't do this. I did this to test a theory and to prove a point. ASP.NET Core and the .NET Core that it runs on are open source and run pretty much anywhere. I wanted to see if I could run an ASP.NET Core site on GoDaddy's cheapest hosting ($3, although it scales to $8) that basically supports only PHP. It's not a full Linux VM. It's locked-down and limited. You don't have root. You are missing most tools you'd expect you'd have.

BUT.

I wanted to see if I could get ASP.NET Core running on it anyway. Maybe if I do, they (and other inexpensive hosts) will talk to the .NET team, learn that ASP.NET Core is open source and could easily run on their existing infrastructure.

First, I went to GoDaddy and signed up for their cheap hosting. Again, not a VM, but their shared one. I also registered supercheapaspnetsite.com as well. They use a cPanel-based web management system that doesn't really let you do anything. You can turn on SSH, do some PHP stuff, and generally poke around, but it's not exactly low-level.

First I ssh (shoosh!) in and see what I'm working with. I'm shooshing with Ubuntu on Windows 10 feature, that every developer should turn on. It's makes it really easy to work with Linux hosts if you're starting from Linux on Windows 10.

I'm going to use .NET Core 2.1 (which is in preview now!) and get the SDK at https://www.microsoft.com/net/download/all and install it on my Windows machine where I will develop and build the app. I don't NEED to use Windows to do this, but it's the laptop I have and it's also nice to know I can build on Windows but target CentOS/RHEL6.

Next I'll make a new ASP.NET site with

dotnet new razor

and then I'll publish a self-contained version like this:

dotnet publish -r rhel.6-x64

And those files will end up in a folder like \supercheapaspnetsite\bin\Debug\netcoreapp2.1\rhel.6-x64\publish\

NOTE: You may need to add the NuGet feed for the dailies for this .NET Core preview in order to get the RHEL6 runtime downloaded during this local publish.

Then I used WinSCP (or whatever FTP/SCP client you like, rsync, etc) to get the files over to the ~/www folder on your GoDaddy shared site. Then I

chmod +x ./supercheapasnetsite

to make it executable. Now, from my ssh session at GoDaddy, let's try to run my app!

secretname@theirvmname [~/www]$ ./supercheapaspnetsite
Failed to load hb, error: libunwind.so.8: cannot open shared object file: No such file or directory
Failed to bind to CoreCLR at '/home/secretname/public_html/libcoreclr.so'

Of course it couldn't be that easy, right? .NET Core wants the unwind library (shared object) and it doesn't exist on this locked down system.

I need to crack open that rpm file and get the library. RPM packages are just headers on top of a CPIO archive, so I can apt-get install rpm2cpio from my local Ubuntu instances (on Windows 10). Then from /mnt/c/users/scott/Downloads (where I downloaded the file) I will extract it.

rpm2cpio ./libunwind-1.1-3.el6.x86_64.rpm | cpio -idmv

There they are.

This part is cool. Even though I have these files, I don't have root or any way to "install" them. However I could either export/use the LD_LIBRARY_PATH environment variable to control how libraries get loaded OR I could put these files in $ORIGIN/netcoredeps. You can read more about Self Contained Linux Applications on .NET Core here.

The main executable of published .NET Core applications (which is the .NET Core host) has an RPATH property set to $ORIGIN/netcoredeps. That means that when Linux shared library loader is looking for shared libraries, it looks to this location before looking to default shared library locations. It is worth noting that the paths specified by the LD_LIBRARY_PATHenvironment variable or libraries specified by the LD_PRELOAD environment variable are still used before the RPATH property. So, in order to use local copies of the third-party libraries, developers need to create a directory named netcoredeps next to the main application executable and copy all the necessary dependencies into it.

At this point I've added a "netcoredeps" folder to my public folder, and then copied it (scp) over to GoDaddy. Let's run it again.

secretname@theirvmname [~/www]$ ./supercheapaspnetsite
FailFast: Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.
at System.Environment.FailFast(System.String)
at System.Globalization.GlobalizationMode.GetGlobalizationInvariantMode()
at System.Globalization.GlobalizationMode..cctor()
at System.Globalization.CultureData.CreateCultureWithInvariantData()
at System.Globalization.CultureData.get_Invariant()
at System.Globalization.CultureInfo..cctor()
at System.StringComparer..cctor()
at System.AppDomain.InitializeCompatibilityFlags()
at System.AppDomain.Setup(System.Object)
Aborted

If your app doesn't explicitly opt out of using globalization, you also need to add libicuuc.so.{version}, libicui18n.so.{version}, and libicudata.so.{version}

I like "opt-out" so I don't have to go dig these ups (although I could) so I can either set the CORECLR_GLOBAL_INVARIANT env var to 1, or I can add System.Globalization.Invariant = true to supercheapaspnetsite.runtimeconfig.json, which I'll do with just to be obnoxious. ;)

When I run it again I get another complained about libuv. Yet another shared library that isn't installed on this instance. I could go get it and put it in netcoredeps OR since I'm using the .NET Core 2.1, I could try something new. There were some improvements made in .NET Core 2.1 around sockets and http performance. On the client side, these new managed libraries are written from the ground up in managed code using the new high-performance Span<T> and on the server-side I could use Kestrel's (Kestrel is the .NET Core webserver) experimental UseSockets() as they are starting to move that over.

In other words, I can bypass libuv usage entirely by changing my Program.cs to use the use UseSockets() like this.

Cheesy, yes. Works for GET? Also, yes. This really is Apache's job, not ours, but kudos to Tomas for this evil idea.

Boom. How about another page at /about? Yes.

Lovely. But I had to run the app myself. I have no supervisor or process manager (again this is already handled by GoDaddy for PHP but I'm in unprivileged world.) Shooshing in and running it is a bad idea and not sustainable. (Well, this whole thing is not sustainable, but still.)

We could copy "screen" over and start it up and detach like use screen ./supercheapaspnet app, but again, if it crashes, no one will start it. We do have crontab, so for now, we'll launch the app on a schedule occasionally to do a health check and if needed, keep it running. Also added a few debugging tools in ~/bin:

All in all, not that hard. ASP.NET Core and .NET Core underneath it can run pretty much anywhere, just like PHP, Python, whatever.

If you're a host and you want to talk to someone at Microsoft about setting up ASP.NET Core shared hosting, email Sourabh.Shirhatti@microsoft.com and talk to them! If you are GoDaddy, I apologize, and you should also email. ;)

First, a disclaimer. Don't do this. I did this to test a theory and to prove a point. ASP.NET Core and the .NET Core that it runs on are open source and run pretty much anywhere. I wanted to see if I could run an ASP.NET Core site on GoDaddy's cheapest hosting ($3, although it scales to $8) that basically supports only PHP. It's not a full Linux VM. It's locked-down and limited. You don't have root. You are missing most tools you'd expect you'd have.

BUT.

I wanted to see if I could get ASP.NET Core running on it anyway. Maybe if I do, they (and other inexpensive hosts) will talk to the .NET team, learn that ASP.NET Core is open source and could easily run on their existing infrastructure.

First, I went to GoDaddy and signed up for their cheap hosting. Again, not a VM, but their shared one. I also registered supercheapaspnetsite.com as well. They use a cPanel-based web management system that doesn't really let you do anything. You can turn on SSH, do some PHP stuff, and generally poke around, but it's not exactly low-level.

First I ssh (shoosh!) in and see what I'm working with. I'm shooshing with Ubuntu on Windows 10 feature, that every developer should turn on. It's makes it really easy to work with Linux hosts if you're starting from Linux on Windows 10.

I'm going to use .NET Core 2.1 (which is in preview now!) and get the SDK at https://www.microsoft.com/net/download/all and install it on my Windows machine where I will develop and build the app. I don't NEED to use Windows to do this, but it's the laptop I have and it's also nice to know I can build on Windows but target CentOS/RHEL6.

Next I'll make a new ASP.NET site with

dotnet new razor

and then I'll publish a self-contained version like this:

dotnet publish -r rhel.6-x64

And those files will end up in a folder like \supercheapaspnetsite\bin\Debug\netcoreapp2.1\rhel.6-x64\publish\

NOTE: You may need to add the NuGet feed for the dailies for this .NET Core preview in order to get the RHEL6 runtime downloaded during this local publish.

Then I used WinSCP (or whatever FTP/SCP client you like, rsync, etc) to get the files over to the ~/www folder on your GoDaddy shared site. Then I

chmod +x ./supercheapasnetsite

to make it executable. Now, from my ssh session at GoDaddy, let's try to run my app!

secretname@theirvmname [~/www]$ ./supercheapaspnetsite
Failed to load hb, error: libunwind.so.8: cannot open shared object file: No such file or directory
Failed to bind to CoreCLR at '/home/secretname/public_html/libcoreclr.so'

Of course it couldn't be that easy, right? .NET Core wants the unwind library (shared object) and it doesn't exist on this locked down system.

I need to crack open that rpm file and get the library. RPM packages are just headers on top of a CPIO archive, so I can apt-get install rpm2cpio from my local Ubuntu instances (on Windows 10). Then from /mnt/c/users/scott/Downloads (where I downloaded the file) I will extract it.

rpm2cpio ./libunwind-1.1-3.el6.x86_64.rpm | cpio -idmv

There they are.

This part is cool. Even though I have these files, I don't have root or any way to "install" them. However I could either export/use the LD_LIBRARY_PATH environment variable to control how libraries get loaded OR I could put these files in $ORIGIN/netcoredeps. You can read more about Self Contained Linux Applications on .NET Core here.

The main executable of published .NET Core applications (which is the .NET Core host) has an RPATH property set to $ORIGIN/netcoredeps. That means that when Linux shared library loader is looking for shared libraries, it looks to this location before looking to default shared library locations. It is worth noting that the paths specified by the LD_LIBRARY_PATHenvironment variable or libraries specified by the LD_PRELOAD environment variable are still used before the RPATH property. So, in order to use local copies of the third-party libraries, developers need to create a directory named netcoredeps next to the main application executable and copy all the necessary dependencies into it.

At this point I've added a "netcoredeps" folder to my public folder, and then copied it (scp) over to GoDaddy. Let's run it again.

secretname@theirvmname [~/www]$ ./supercheapaspnetsite
FailFast: Couldn't find a valid ICU package installed on the system. Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support.
at System.Environment.FailFast(System.String)
at System.Globalization.GlobalizationMode.GetGlobalizationInvariantMode()
at System.Globalization.GlobalizationMode..cctor()
at System.Globalization.CultureData.CreateCultureWithInvariantData()
at System.Globalization.CultureData.get_Invariant()
at System.Globalization.CultureInfo..cctor()
at System.StringComparer..cctor()
at System.AppDomain.InitializeCompatibilityFlags()
at System.AppDomain.Setup(System.Object)
Aborted

If your app doesn't explicitly opt out of using globalization, you also need to add libicuuc.so.{version}, libicui18n.so.{version}, and libicudata.so.{version}

I like "opt-out" so I don't have to go dig these ups (although I could) so I can either set the CORECLR_GLOBAL_INVARIANT env var to 1, or I can add System.Globalization.Invariant = true to supercheapaspnetsite.runtimeconfig.json, which I'll do with just to be obnoxious. ;)

When I run it again I get another complained about libuv. Yet another shared library that isn't installed on this instance. I could go get it and put it in netcoredeps OR since I'm using the .NET Core 2.1, I could try something new. There were some improvements made in .NET Core 2.1 around sockets and http performance. On the client side, these new managed libraries are written from the ground up in managed code using the new high-performance Span<T> and on the server-side I could use Kestrel's (Kestrel is the .NET Core webserver) experimental UseSockets() as they are starting to move that over.

In other words, I can bypass libuv usage entirely by changing my Program.cs to use the use UseSockets() like this.

Cheesy, yes. Works for GET? Also, yes. This really is Apache's job, not ours, but kudos to Tomas for this evil idea.

Boom. How about another page at /about? Yes.

Lovely. But I had to run the app myself. I have no supervisor or process manager (again this is already handled by GoDaddy for PHP but I'm in unprivileged world.) Shooshing in and running it is a bad idea and not sustainable. (Well, this whole thing is not sustainable, but still.)

We could copy "screen" over and start it up and detach like use screen ./supercheapaspnet app, but again, if it crashes, no one will start it. We do have crontab, so for now, we'll launch the app on a schedule occasionally to do a health check and if needed, keep it running. Also added a few debugging tools in ~/bin:

All in all, not that hard. ASP.NET Core and .NET Core underneath it can run pretty much anywhere, just like PHP, Python, whatever.

If you're a host and you want to talk to someone at Microsoft about setting up ASP.NET Core shared hosting, email Sourabh.Shirhatti@microsoft.com and talk to them! If you are GoDaddy, I apologize, and you should also email. ;)

My podcast has over 600 episodes (Every week for many years, you do the math! And subscribe!) website was written in ASP.NET Web Pages many years ago. "Web Pages" (horrible name) was it's own thing. It wasn't ASP.NET Web Forms, nor was it ASP.NET MVC. However, while open-source and cross-platform ASP.NET Core uses the "MVC" pattern, it includes an integrated architecture that supports pages created with the model-view-controller style, Web APIs that return JSON/whatever from controllers, and routing system that works across all of these. It also includes "Razor Pages."

On first blush, you'd think Razor Pages is "Web Pages" part two. I thought that, but it's not. It's an alternative model to MVC but it's built on MVC. Let me explain.

My podcast site has a home page, a single episode page, and and archives page. It's pretty basic. Back in the day I felt an MVC-style site would just be overkill, so I did it in a page model. However, the code ended up (no disrespect intended) very 90s style PHPy. Basically one super-page with too much state management to all the URL cracking happening at the top of the page.

What I wanted was a Page-focused model without the ceremony of MVC while still being able to dip down into the flexibility and power of MVC when appropriate. That's Razor Pages. Best of all worlds and simply another tool in my toolbox. And the Pages (.cshtml) are Razor so I could port 90% of my very old existing code. In fact, I just made a new site with .NET Core with "dotnet new razor," opened up Visual Studio Code, and started copying over from (gasp) my WebMatrix project. I updated the code to be cleaner (a lot has happened to C# since then) and had 80% of my site going in a few hours. I'll switch Hanselminutes.com over in the next few weeks. This will mean I'll have a proper git checkin/deploy process rather than my "publish from WebMatrix" system I use today. I can containerize the site, run it on Linux, and finally add Unit Testing as I've been able to use pervasive Dependency Injection that's built into ASP.NET.

Merging the old and the new with the ASP.NET Core's URL Rewriting Middleware

Here's the thing though, there's parts of my existing site that are 10 years old, sure, but they also WORK. For example, I have existing URL Rewrite Rules from IIS that have been around that long. I'm pretty obsessive about making old URLs work. Never break a URL. No excuses.

Remember I have URLs like default.aspx?ShowID=18570 but I don't use default.aspx any more (literally doesn't exist on disk) and I don't use those IDs (they are just stored as metadata in a new system.

NOTE: Just want to point out that last line above there, where it shows the rewritten URL. Putting that in the logs or bypassing everything and outputting it as text is a nice way to debug and developer with this middleware, then comment it out as you get things refined and working.

I have an IIS Rewrite URL that looks like this. It lives in an XML file along with dozens of other rules. Reminder - there's no IIS in this scenario. We are talking about the format and reusing that format. I load my rewrite rules in my Configure() method in Startup:

I capture that show ID and I rewrite (not redirect...we rewrite and continue on to the next segment of the pipeline) it to /18570?handler=oldshowid. That handler is a magic internal part of Razor Pages. Usually if you have a page called foo.cshtml it will have a method called OnGet or OnPost or OnHTTPVERB. But if you want multiple handlers per page you'll have OnGetHANDLERNAME so I have OnGet() for regular stuff, and I have OnGetOldShowId for this rare but important URL type. But notice that my implementation isn't URL-style specific. Razor Pages doesn't even know about that URL format. It just knows that these weird IDs have their own handler.

My podcast has over 600 episodes (Every week for many years, you do the math! And subscribe!) website was written in ASP.NET Web Pages many years ago. "Web Pages" (horrible name) was it's own thing. It wasn't ASP.NET Web Forms, nor was it ASP.NET MVC. However, while open-source and cross-platform ASP.NET Core uses the "MVC" pattern, it includes an integrated architecture that supports pages created with the model-view-controller style, Web APIs that return JSON/whatever from controllers, and routing system that works across all of these. It also includes "Razor Pages."

On first blush, you'd think Razor Pages is "Web Pages" part two. I thought that, but it's not. It's an alternative model to MVC but it's built on MVC. Let me explain.

My podcast site has a home page, a single episode page, and and archives page. It's pretty basic. Back in the day I felt an MVC-style site would just be overkill, so I did it in a page model. However, the code ended up (no disrespect intended) very 90s style PHPy. Basically one super-page with too much state management to all the URL cracking happening at the top of the page.

What I wanted was a Page-focused model without the ceremony of MVC while still being able to dip down into the flexibility and power of MVC when appropriate. That's Razor Pages. Best of all worlds and simply another tool in my toolbox. And the Pages (.cshtml) are Razor so I could port 90% of my very old existing code. In fact, I just made a new site with .NET Core with "dotnet new razor," opened up Visual Studio Code, and started copying over from (gasp) my WebMatrix project. I updated the code to be cleaner (a lot has happened to C# since then) and had 80% of my site going in a few hours. I'll switch Hanselminutes.com over in the next few weeks. This will mean I'll have a proper git checkin/deploy process rather than my "publish from WebMatrix" system I use today. I can containerize the site, run it on Linux, and finally add Unit Testing as I've been able to use pervasive Dependency Injection that's built into ASP.NET.

Merging the old and the new with the ASP.NET Core's URL Rewriting Middleware

Here's the thing though, there's parts of my existing site that are 10 years old, sure, but they also WORK. For example, I have existing URL Rewrite Rules from IIS that have been around that long. I'm pretty obsessive about making old URLs work. Never break a URL. No excuses.

Remember I have URLs like default.aspx?ShowID=18570 but I don't use default.aspx any more (literally doesn't exist on disk) and I don't use those IDs (they are just stored as metadata in a new system.

NOTE: Just want to point out that last line above there, where it shows the rewritten URL. Putting that in the logs or bypassing everything and outputting it as text is a nice way to debug and developer with this middleware, then comment it out as you get things refined and working.

I have an IIS Rewrite URL that looks like this. It lives in an XML file along with dozens of other rules. Reminder - there's no IIS in this scenario. We are talking about the format and reusing that format. I load my rewrite rules in my Configure() method in Startup:

I capture that show ID and I rewrite (not redirect...we rewrite and continue on to the next segment of the pipeline) it to /18570?handler=oldshowid. That handler is a magic internal part of Razor Pages. Usually if you have a page called foo.cshtml it will have a method called OnGet or OnPost or OnHTTPVERB. But if you want multiple handlers per page you'll have OnGetHANDLERNAME so I have OnGet() for regular stuff, and I have OnGetOldShowId for this rare but important URL type. But notice that my implementation isn't URL-style specific. Razor Pages doesn't even know about that URL format. It just knows that these weird IDs have their own handler.

Now, from a directory, I can make a little node/express app or a little .NET Core app (with "dotnet new razor" and "dotnet build") then it'll make a resource group, web app, and zip up the current folder and just deploy it. The idea being to "JUST DO IT."

I'd even like it to make up a name so I could maybe "az webapp up" or even just "az up." For now it'll make a Free site by default, so you can try it without worrying about paying. If you want to upgrade or change it, upgrade either with the az command or in the Azure portal. Also the site ends at up <name>.azurewebsites.net!

DO NOTE that these extensions are living things, so you can update after installing with

Now, from a directory, I can make a little node/express app or a little .NET Core app (with "dotnet new razor" and "dotnet build") then it'll make a resource group, web app, and zip up the current folder and just deploy it. The idea being to "JUST DO IT."

I'd even like it to make up a name so I could maybe "az webapp up" or even just "az up." For now it'll make a Free site by default, so you can try it without worrying about paying. If you want to upgrade or change it, upgrade either with the az command or in the Azure portal. Also the site ends at up <name>.azurewebsites.net!

DO NOTE that these extensions are living things, so you can update after installing with