The simplest ASP.NET Core app that'll serve static content

Ruuning a basic ASP.NET Core project from the console

NOTE: This post is targeting .NET Core / ASP.NET Core 2.0, not 1.x

I have a confession to make, I've not spent much time or energy looking into the ins and outs of .NET Core, ASP.NET Core, Entity Framework Core and all the new ways of doing things that come with it. I do have a good reason though, aside from laziness,.. I was kinda waiting for product maturity / v2 before I dug into it in any great detail. Unsurprisingly it turned out that it was worth waiting a little while as some changes have filtered through like project.json (which essentially replaced pacakges.config) being superseded by PackageReference's and the new super-slimline .csproj format. The latter really is a boon, especially to anyone who's seen the mess that was/is .csproj files for prior project types. There's also the evolution of .NETStandard which means that it kinda feels like all the pieces are coming together in the right place now.

Creating the project - via the Command Line

Note: If you don't have it installed already, you'll need the .NET Core 2.0 SDK installed to be able to follow along. I've already got it installed, likely thanks to Visual Studio 2017, so won't be stepping through the process of installing it here.

One of the big things with .NET Core is the command line tooling support, so I thought I'd show the process I went though to create this project using that tooling. Once that's done I'm going to swap to Visual Studio 2017 for the editing experience but there's no real reason why you couldn't carry on using Notepad(++), Visual Studio Code or your other editor of choice. The principle with .NET Core is that it's truly multi-platform so everything you can do, you can do without Visual Studio.

So, step one, in PowerShell although you could use the Windows Command Prompt if you want - it makes no difference:

Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

PS C:\Users\robertwray> d:
PS D:\> md BlogPostProject


    Directory: D:\


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       31/10/2017     12:59                BlogPostProject
PS D:\>

I've created a folder for the project to live in - I've done this on my "D" drive because that's where I do this stuff. The folder you create could be anywhere, though do stick to somewhere that's properly under your control, i.e. don't try this in C:\Windows\System32, it may well work, but it's probably not a good idea!

The next thing to do is to use the "dotnet new" command to create a truly empty web project. This is a web project that contains no WebForms (it doesn't exist in ASP.NET Core so that's a bad example!), no MVC, no WebAPI, no Routing, no *nothing*. This can be achieved by running dotnet new and specifying web as the type of project to create / the template to run through. You can get a full list of all the templates/projects by running dotnet new without any other arguments. So, running dotnet new web gives us the following output:

PS D:\> cd .\BlogPostProject\
PS D:\BlogPostProject> dotnet new web
The template "ASP.NET Core Empty" was created successfully.
This template contains technologies from parties other than Microsoft, see https://aka.ms/template-3pn for details.

Processing post-creation actions...
Running 'dotnet restore' on D:\BlogPostProject\BlogPostProject.csproj...
  Restoring packages for D:\BlogPostProject\BlogPostProject.csproj...
  Generating MSBuild file D:\BlogPostProject\obj\BlogPostProject.csproj.nuget.g.props.
  Generating MSBuild file D:\BlogPostProject\obj\BlogPostProject.csproj.nuget.g.targets.
  Restore completed in 1.26 sec for D:\BlogPostProject\BlogPostProject.csproj.


Restore succeeded.

Notice how I changed into the directory I created first, and then dotnet new has used that as the name for the project? Don't make the mistake of forgetting to do this and running dotnet new in another folder, like the root of drive D:, if you kinda happen to have one!

Before making any changes, it doesn't hurt to build and run the project, just to make sure it's all playing nicely, so call dotnet run and you should see something along the lines of this:

PS D:\BlogPostProject> dotnet run
Hosting environment: Production
Content root path: D:\BlogPostProject
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

If you then copy the address (http://localhost:5000) from the console and browse to it, two things should happen:

  • The browser should display the text "Hello World!"
  • The console will spit out a couple of information lines to let you know it's responded to a request

Assuming they do, you're good to carry on!

Serving some static content

What you might notice is, no matter the URL you specify, and no matter what files you place in the wwwroot folder (as this is where ASP.NET Core serves content from, which is a bit different to the ASP.NET on .NET Framework way of things), you'll always get "HelloWorld!" back. Go on, try browsing to http://localhost:5000/badger/badger/cat/cat, yup, "HelloWorld!".

Because of the way things work in the "Core" world, you don't get something for nothing anymore. In order for something to happen, you've got to tell the runtime that it needs to happen. At the moment, every request is responded to with "Hello World!" because of these lines in Startup.cs:

app.Run(async (context) =>
{
    await context.Response.WriteAsync("Hello World!");
});

In order to get static content served up, we need to do something other than just return static text for every request that comes in, like, return a file. I'm going to move to Visual Studio now, just because it makes the process a little bit easier, but as I said before: you could do all of this via the command line. If your PC has Visual Studio 2017 installed and is configured similarly to mine, running the following should open Visual Studio:

PS D:\BlogPostProject> .\BlogPostProject.csproj

Press F5 and you should see your browser open and proclaim "Hello World!", you can look in the Output pane of Visual Studio to see something that's similar to what you saw when running the web application using dotnet run:

The Output pane showing the request details that were shown in the console

There's some extra noise in there, but the two lines that start Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: are pretty similar to the output seen when running in the console. Now lets drop some static content in to serve up, prove that it doesn't work because of the code in Startup.cs handling all requests by returning "Hello World!" and fix that.

Step 1 - Add some content. This is nice and easy, right-click on the wwwroot folder in Solution Explorer, choose Add, New Item... and then choose the HTML Page" option, giving the file a name of your choice, say "mypage.html" before clicking the "Add" button to create the file. I'm going to put an h1 in my mypage.html that says "This is my page" giving me a file that looks like this:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <h1>This is my page</h1>
</body>
</html>

Step 2 - Prove that we'll still only get the "Hello World!" content returned. To do this, hit F5. Your browser will load and it'll probably go to the root of your app. Tack "mypage.html" on the end, the app is still returning "Hello World!". That leads us onto the next step - getting "mypage.html" to be returned.

Step 3 - Rendering static content. This is actually really rather easy. Open up Startup.cs and replace the whole app.Run block with app.UseStaticFiles();. This one-liner pulls in an extension method from the assembly Microsoft.AspNetCore.StaticFiles that configures everything you need so that static files are processed. What you'll now see is that instead of getting "Hello World!" for the root of the app, you get your browsers 404 behaviour of choice

404 for application root when static content is being served

Edit the address bar to tack on "mypage.html" to the end, and re-load, et voila:

There's plenty more documentation out there, along with guides and tutoirals that can show some of the other middleware that you can plug in here to do stuff other than simply return static content, indeed, this is how everything gets "bolted together" now. If you were to run dotnet new mvc to create a new MVC project on ASP.NET Core, you'd see that the genereated Startup.cs would contain code that looks like this:

app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});

There are a lot of "default" extension methods available that add functionality in, Intellisense in Visual Studio is a good way to discover some of them:

Some of the available extension methods on IApplicationBuilder

About Rob

I've been interested in computing since the day my Dad purchased his first business PC (an Amstrad PC 1640 for anyone interested) which introduced me to MS-DOS batch programming and BASIC.

My skillset has matured somewhat since then, which you'll probably see from the posts here. You can read a bit more about me on the about page of the site, or check out some of the other posts on my areas of interest.

No Comments

Add a Comment