In an earlier article I built an ASP.NET Core MVC Web Application from scratch on macOS using the dotnet CLI and Visual Studio Code. If you're wondering how to get started with ASP.NET Core, that is a good article that teaches the basics.

In this article I want to get a little more minimal and use ASP.NET Core without MVC. Since I am learning a lot about algorithms this summer, I will create a simple ASP.NET Core Web Application that returns Fibonacci numbers. It will demonstrate the fundamentals of ASP.NET Core and ASP.NET Core Routing.

Create the ASP.NET Core Web Application

I develop both on macOS and Windows, but all my getting started with ASP.NET Core Tutorials are using macOS on my MacBook Pro. This keeps me away from the wizards in Visual Studio, and allows me to learn just pure ASP.NET Core. To get started, I open up a bash terminal on my MacBook Pro and create a directory for the application as well as create a new .NET Core Application and restore its Nuget Packages. This is the start of all my .NET Core Application on macOS.

mkdir FibApp && CD $_
dotnet new
dotnet restore

I use Visual Studio Code on macOS for my development and debugging of ASP.NET Core applications. Once the .NET Core application is created using the dotnet CLI, I open the new application in Visual Studio Code.

code .

Visual Studio Code will open up and within about 10 seconds asks me if I want to install the necessary assets to debug the application. I choose "Yes."

Add Important Dependencies to Project.json

There are two dependencies I need for this ASP.NET Core Application. The first dependency is a web server, Microsoft.AspNetCore.Server.Kestrel, and the other is ASP.NET Core Routing: Microsoft.AspNetCore.Routing.

I add these to project.json.

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0"
        },
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
        "Microsoft.AspNetCore.Routing": "1.0.0"
      },
      "imports": "dnxcore50"
    }
  }
}

I need to install these dependencies so I type the following command in the bash terminal. Note that one could execute this command from the Visual Studio Code Command Palette or a Visual Studio Code Terminal Window as well. Note that in Visual Studio Code 1.3 there is support for multiple terminals.

dotnet restore

Now it's time to start programming.

Create a new Web Host with WebHostBuilder

The dotnet new command using the dotnet CLI creates a console application. I need to modify the Main method of the Program Class in program.cs to initiate and run a web host. I am using Kestrel as a web server and pointing the host to the Startup Class as my entry point for the ASP.NET Core Application.

using System.IO;
using Microsoft.AspNetCore.Hosting;

namespace ConsoleApplication {
    public class Program {
        public static void Main(string[] args) {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }
}

Startup and ASP.NET Core Routing

The entry point for all ASP.NET Core Applications is the Startup Class. This is where I configure my new route using ASP.NET Core Routing.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

namespace FibApp {
    public class Startup {
        public void ConfigureServices(IServiceCollection services) {
            services.AddRouting();
        }

        public void Configure(IApplicationBuilder app) {
            var rb = new RouteBuilder(app);

            rb.Routes.Add(new Route(new FibRouter(), "fib/{number:int}",
                app.ApplicationServices.GetService<IInlineConstraintResolver>()));

            app.UseRouter(rb.Build());
        }
    }
}

The services.AddRouting() statement in ConfigureServices adds any ASP.NET Core Routing Services to the dependency injection framework.

In the Configure method I create a new route using RouteBuilder and tell the application to use the new route and send all requests that match this route to FibRouter. The route looks like the following:

http://localhost:5000/fib/{number}

where {number} is the Fibonacci number. Therefore, if I want the 20th Fibonacci number, the URL will look as follows:

http://localhost:5000/fib/20

Notice the constraint in the route, {number:int}.The number parameter must be an integer. An implementation of IInlineConstraintResolver will be verifying that constraint, and if the parameter provided is not an integer, it will not match the route and execute the code. Thus, this is not a good URL.

http://localhost:5000/fib/abcd

FibRouter

When a request matches the pattern, ASP.NET Core Routing will send the request to FibRouter. I just need to verify I indeed have a good request, and return the appropriate Fibonacci number.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

namespace FibApp {
    public class FibRouter: IRouter {
        public Task RouteAsync(RouteContext context) {
            var number = context.RouteData.Values["number"] as string;
            if (string.IsNullOrEmpty(number)) {
                return Task.FromResult(0);
            }

            int value;
            if (!Int32.TryParse(number, out value)) {
                return Task.FromResult(0);
            }

            var requestPath = context.HttpContext.Request.Path;
            if (requestPath.StartsWithSegments("/fib", StringComparison.OrdinalIgnoreCase)) {
                context.Handler = async c => {
                    var answer = Fibonacci.FindNumber(value);
                    await c.Response.WriteAsync($"Fib({number}) = {answer}");
                };
            }
            return Task.FromResult(0);
        }

        public VirtualPathData GetVirtualPath(VirtualPathContext context) {
            return null;
        }
    }
}

This is a fair amount of code, but most of it is just defensive programming verifying I received an integer and the request is actually for a Fibonacci number. If everything looks good, I just caculate the Fibonacci number and return the value.

Fibonacci Number Calculation

The last bit is just a static class that uses a bit of dynamic programming to caculate the Fibonacci number. I have a bunch of posts on Fibonacci so I won't go into the details.

using System;

namespace FibApp {
    public static class Fibonacci {
        public static Int64 FindNumber(int number) {
            if (number < 2)
                return number;

            Int64 fibMinusOne = 1;
            Int64 fibMinusTwo = 0;
            Int64 fib = 0;

            for (int i = 2; i < number + 1; i++) {
                fib = fibMinusOne + fibMinusTwo;
                fibMinusTwo = fibMinusOne;
                fibMinusOne = fib;
            }

            return fib;
        }
    }
}

Running The ASP.NET Core Web Application

The program is done and I can run it from my bash terminal using dotnet run from the dotnet CLI. I could also run this from Visual Studio Code. I could even debug this from Visual Studio Code using breakpoints, watch variables, etc.

dotnet run

Project FibApp (.NETCoreApp,Version=v1.0) will be compiled because expected outputs are missing
Compiling FibApp for .NETCoreApp,Version=v1.0

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

Time elapsed 00:00:01.1045825
 

Hosting environment: Production
Content root path: /Users/Sasquatch/Projects/Core/FibApp
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

When I request the 30th Fibonacci number I get the following response.

ASP.NET Core Routing Tutorial

Conclusion

It works! I was able to use ASP.NET Core and ASP.NET Core Routing to provide a simple solution to solve Fibonacci numbers. I could add other routes that provide other services. I could also use Web API and ASP.NET Core MVC, but the goal was to understand the basics of ASP.NET Core Routing. I hope this helps. I think I will try this with Flask and Python as well as build something similar using Web API. Be on the lookout for other ASP.NET Core Tutorials.

Posted by Koder Dojo

I am a C# ASP.NET MVC Developer learning .NET Core and ASP.NET Core from Microsoft as well as Python. I started this website to share my learning experience and hope it helps others. There will be a lot of almost daily articles on 1) new ways of working with ASP.NET Core, MVC, and Web API, and 2) Python. I am attending 4 online courses on computer science, algorithms, data structures, and crytopgraphy in Python so I have a lot of material.

Related Posts: