Category Archives: ASP.NET Core

Creating an ASP.NET client using Eureka and Steeltoe

In the previous post Eureka Server (using Steeltoe) revisited I went through the process of running a Eureka instance and creating a default template based ASP.NET Web API which registers itself with the Eureka server as the application weatherapi.

Let’s now create a basic ASP.NET MVC project to interact with the Eureka server, get an instance of the API service and use it.

Note: This post is almost 100% based on the Channel 9 video Service Discovery with Steeltoe, so credit should go to Tim Hess for the sample code.

  • Create an ASP.NET Core application and then select Web Application (Model View Controller)
  • Add the following NuGet packages, Steeltoe.Discovery.ClientCore, Steeltoe.Discovery.Eureka and System.Net.Http.Json
  • Update the appsettings.json with the following
      "eureka": {
        "client": {
          "serviceUrl": "http://locahost:8761/eureka/",
          "shouldFetchRegistry": "true",
          "shouldRegisterWithEureka": false,
          "validateCertificates": false
        }
      }
    

    Notice we set shouldFetchRegistry to true as we want to get the latest registry information, and we set shouldRegisterWidthEureka to false as, in this case, we don’t want to register this client. Ofcourse change this is your client also exposes services.

  • Within Startup.cs, ConfigureServices add the following
    services.AddDiscoveryClient(Configuration);
    services.AddHttpClient("weather", 
       client => client.BaseAddress = new Uri("http://weatherapi/"))
          .AddServiceDiscovery();
    

    The interesting thing here is that we associate the name “weather” with an address which looks like a URL but really is the name of the service within Eureka that we want to access. Then, by using the AddServiceDiscovery this will be converted to an instance URL representing the instance of the service associated with the app name.

    Note: we can also use load balancing strategies, such as round robin or random.

  • Finally within the Startup.cs, method Configure, add the following
    app.UseDiscoveryClient();
    
  • We’re going to simply copy the WeatherForecast class from the service and add to the client, here it is

    public class WeatherForecast
    {
       public DateTime Date { get; set; }
       public int TemperatureC { get; set; }
       public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
       public string Summary { get; set; }
    }
    
  • Within HomeController.cs we need to add a variable of type IHttpClientFactory which will be injected into the constructor and then uses to call defined HTTP client, this will then used service discovery to return the URL of an instance (as already discussed) and then we’re use that to call the weather API to get a list of values. Here’s the changes required to HomeController.cs
    private readonly IHttpClientFactory _httpClientFactory;
    
    public HomeController(IHttpClientFactory httpClientFactory, ILogger<HomeController> logger)
    {
       _httpClientFactory = httpClientFactory;
       _logger = logger;
    }
    
    public async Task<IActionResult> Index()
    {
       var client = _httpClientFactory.CreateClient("weather");
       var weather = await client.GetFromJsonAsync<IList<WeatherForecast>>("weatherforecast");
       return View(weather);
    }
    
  • Finally, let’s change the Index.cshtml to display the weather forecast data returned in the Index method. Firstly we declare the @model and then simply create a table to output the items from that model in columns and rows, so here’s the change to be added to the top of the file
    @model IList<EurekaWebClient.Controllers.WeatherForecast>
    

    and within the main div, just add the following

    <table class="table">
       <tr><th>Day of Week</th><th>Summary</th><th>Temp</th></tr>
       @foreach (var weather in Model)
       {
          <tr><td>@weather.Date.DayOfWeek</td><td>@weather.Summary</td><td>@weather.TemperatureF</td></tr>
       }
    </table>
    

That should be it. Ensure Eureka is running, your service is up and you should now see the weather service data in a nice little table.

Blazor/ASP.NET core on docker

I wanted to get a Blazor server application up and running on Ubuntu within a docker container (I’m running the whole thing on a Raspberry Pi 4 with Ubuntu Server).

The first stage for this post will simply be about creating a Dockerfile and creating a Blazor server application via the dotnet template.

We’re going to want the latest version of dotnet core, so let’s start by creating a very bare bones Dockerfile which will create an image based upon
mcr.microsoft.com/dotnet/core/sdk:3.1, it will also expose the standard HTTP port used in the Blazor server template, i.e. port 5000

Here’s the Dockerfile

FROM mcr.microsoft.com/dotnet/core/sdk:3.1
ENV APP_HOME /home
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
EXPOSE 5000
CMD [ "bash" ]

To build this image run the following

docker rmi dotnet-env --force
docker build -t dotnet-env .

The first line is solely there to remove any existing image (which will be especially useful whilst developing the image). The second line will build the Dockerfile and name it dotnet-env.

Once built, let’s run the image to see all is good with it. So simply run

docker run -it --rm -p 5000:5000 -v /home/share:/home/share dotnet-env

In this example we’ll run docker in interactive mode and map ports using -p to map the host port 5000 to the exposed port in the image. We’ll also also created a volume link from the container to the host.

Once we’ve run the image up we should be placed into a BASH command prompt, now we can simply run

dotnet new blazorserver -o MyServer

To create the project MyServer, once created cd into the MyServer folder. Now run

dotnet run

A kestrel server should start up, and you might be able to access the server using http://server-ip-address. I say might, because you may well see an error at startup, saying something like

Unable to bind to http://localhost:5000 on the IPv6 loopback interface: ‘Cannot assign requested address’.

What you need to do is go into the Properties folder and open launchSettings.json, change the line

"applicationUrl": "https://localhost:5001;http://localhost:5000",

to

"applicationUrl": "http://0.0.0.0:5001;http://0.0.0.0:5000",

Next Step

This obvious next step to our docker build is to create a Docker image which contains our application and runs it when the container is started. We’re going to build and publish the using dotnet publish -c Release -o publish and then include the published files in our docker container, alternatively you might prefer to have the Dockerfile build and publish the project as part of its build process.

For now let’s just build our Blazor server application, then publish it to a folder.

We’re going to host the application in Kestrel, so before we go any further open the appsetting.json file from the publish folder and add the following

"Kestrel": {
  "EndPoints": {
    "Http": {
      "Url": "http://0.0.0.0:5000"
    }   
  }
},

Now we’ll make the changes to the Dockerfile to copy the published folder to the image and start up the Kestrel server when the image is run, here’s the Dockerfile

FROM mcr.microsoft.com/dotnet/core/sdk:3.1

ENV APP_HOME /home
RUN mkdir -p $APP_HOME

WORKDIR $APP_HOME

COPY ./BlazorServer/BlazorServer/publish ${APP_HOME}

EXPOSE 5000

CMD [ "dotnet", "BlazorServer.dll" ]

Now you should be able to access your server using http://your_server_name:5000.

ASP.NET Core and Web API

In the past I’ve looked at ServiceStack for developing REST services however there are alternatives to ServiceStack, one of which is Web Api. Let’s create a simple starter project using ASP.NET Core and Web Api to implement our services.

  • Create a new ASP.NET Core Web Application
  • Select API

The generated service supplies a Controllers/ValuesController.cs file which includes a controller class with the various REST methods.

Controllers partition your application’s API, so for example you might have an AuthenticateController solely for authentication methods and another controller for CRUD operations on a datasource.

For example this is a simple AuthenticateController class

[Route("[controller]")]
[ApiController]
public class AuthenticateController : ControllerBase
{
   [HttpPost]
   public ActionResult<AuthenticateReponse> Post([FromBody] User user)
   {
      return new AuthenticateReponse
      {
         Token = $"{user.Name}|1234"
      };
   }
}

Here, the Route is set to [controller] so our URL would be http://localhost/Authenticate. In this example we intend for the user to send data within an HTTP POST method, passing a User object (which is a simple name/password object). An AuthenticateResponse object is return via the ActionResult.

The ActionResult return value allows us to return HTTP 200 OK or using subclasses such as BadRequest for an HTTP 400 and there are other derivations for other HTTP responses.

The Action<> allows us to return a 200 OK without the need of using the Ok() method, although this can be used if preferred.

When using different return responses it’s good to also document these by adding

[ProducesResponseType(400)]

This indicates that the method may return an HTTP 400. This is useful for use with Open API tools such as Swagger.

As can be seen in the Post method, the User object is expected within the method’s body and the HttpPost attribute declare the method uses HTTP POST, the method name is superfluous in terms of the REST API.

The different HTTP methods

The code generated by the template creates a ValuesController with various HTTP methods, which I’ll recreate here for reference

HTTP GET without URL parameters

[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
   return new string[] { "value1", "value2" };
}

HTTP GET with URL parameters

[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
   return "value";
}

HTTP POST without URL parameters

[HttpPost]
public void Post([FromBody] string value)
{
}

HTTP PUT with URL parameters

[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}

HTTP DELETE with URL parameters

[HttpDelete("{id}")]
public void Delete(int id)
{
}

HTTP HEAD

[HttpGet, HttpHead]
public IActionResult Head()
{
   return Ok();
}

We would request the headers using HttpHead along with an HttpGet.

HTTP PATCH

[HttpPatch]
public IActionResult Patch()
{
   return Ok();
}

Adding Swagger support

As per ASP.NET Core Web API help pages with Swagger / OpenAPI we can add Swagger support using either Swashbuckle.AspNetCore or NSwag (there may be others). Both are simple to add to our project.

Websockets and Kestrel

In my post Websockets with Fleck we looked at using Fleck to create a websocket based server, let’s not turn our attention to integrating websockets with an ASP.NET core application using Kestrel.

This is NOT meant to implement anything near as complete as the Fleck library, but is just an example of how we might implement websockets in a Kestrel application and we’re going to try to emulate the code we had for that Fleck example.

  • Create an ASP.NET Core Web Application
  • Select the Empty template

Let’s clean out the Properties | launchSettings.json by remove the iisExpression and IIS Express profile, so mine looks like this

{
  "profiles": {
    "YOUR_APP_NAME": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Obviously keep your application name in the YOUR_APP_NAME string.

Now in Program.cs we’ll add code to allow us to use the 8181 port, so the CreateHostBuilder method should now look like this

public static IHostBuilder CreateHostBuilder(string[] args) =>
  Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
      webBuilder.UseStartup<Startup>();
      webBuilder.UseUrls("http://*:8181");
    });

Delete everything within the Startup.cs’s Configure method and replace with

app.UseWebSockets();

this adds the websocket middleware.

We’re actually going to then create our own middleware to handle web socket requests, so
let’s create the file WebSocketManagerMiddleware.cs. Here’s the code…

public class WebSocketManagerMiddleware
{
  private readonly RequestDelegate _next;
  private readonly WebSocketConnection _connection;

  public WebSocketManagerMiddleware(
    RequestDelegate next, 
    WebSocketConnection connection)
  {
    _next = next;
    _connection = connection;
  }

  public async Task InvokeAsync(HttpContext context)
  {
    if (context.WebSockets.IsWebSocketRequest)
    {
      var socket = await context.WebSockets.AcceptWebSocketAsync();

      _connection.OnOpen(socket);

      await Receive(socket, (result, buffer) =>
      {
        switch (result.MessageType)
        {
          case WebSocketMessageType.Text:
            var s = Encoding.UTF8.GetString(buffer);
            _connection.OnMessage(socket, s.Substring(0, Math.Max(0, s.IndexOf('\0'))));
            break;
          case WebSocketMessageType.Binary:
            _connection.OnBinary(socket, buffer);
            break;
          case WebSocketMessageType.Close:
            _connection.OnClose(socket);
            break;
        }
      });
    }
    await _next(context);
  }

  private async Task Receive(
    WebSocket socket, 
    Action<WebSocketReceiveResult, 
    byte[]> handler)
  {
    var buffer = new byte[1024];

    while (socket.State == WebSocketState.Open)
    {
      var result = await socket.ReceiveAsync(buffer: 
        new ArraySegment<byte>(buffer),
        cancellationToken: CancellationToken.None);

      handler(result, buffer);
    }
  }
}

Middleware expects an Invoke or InvokeAsync method that returns a Task. In our example, we firstly ensure this is a websocket request before accepting the request. In this example we pass in a WebSocketConnection instance (we’ll have a look at that next), but basically this middleware intercepts the websockets and then calls the WebSocketConnection class in a manner similar to the way our Fleck server was implemented, i.e. using OnOpen, OnClose, OnMessage and OnBinary calls.

At the end of the code we pass the context through to the next piece of middleware in the pipeline.

The reason we have a WebSocketConnection class is to just give us an abstraction for creating our actual application websocket code.

Add the file WebScocketConnection.cs, this is going to expose OnOpen, OnClose etc. extension points as well as a SendAsync method for sending data to the connected client, here’s the code

public class WebSocketConnection
{
  public void Start(Action<WebSocketConnection> connection)
  {
    connection(this);
  }

  public Action<WebSocket> OnOpen { get; set; } = 
    webSocket => { };
  public Action<WebSocket> OnClose { get; set; } = 
    webSocket => { };
  public Action<WebSocket, string> OnMessage { get; set; } = 
    (webSocket, message) => { };
  public Action<WebSocket, byte[]> OnBinary { get; set; } = 
    (webSocket, bytes) => { };

  public async Task SendAsync(WebSocket socket, string message)
  {
    if (socket.State == WebSocketState.Open)
    {
      await socket.SendAsync(
        new ArraySegment<byte>(Encoding.ASCII.GetBytes(message),
          0,
          message.Length),
        WebSocketMessageType.Text,
        true,
        CancellationToken.None);
      }
    }
  }
}

Finally let’s return to Startup.cs and the Configure method, here’s the full code

var websocketServer = new WebSocketConnection();
websocketServer.Start(connection =>
{
  connection.OnOpen = socket => Console.WriteLine("OnOpen");
  connection.OnClose = socket => Console.WriteLine("OnClose");
  connection.OnMessage = async (socket, message) =>
  {
    Console.WriteLine($"OnMessage {message}");
    await connection.SendAsync(socket, $"Echo: {message}");
  };
  connection.OnBinary = (socket, bytes) => 
    Console.WriteLine($"OnBinary {Encoding.UTF8.GetString(bytes)}");
});

app.UseWebSockets();
app.UseMiddleware<WebSocketManagerMiddleware>(websocketServer);

References

WebSockets support in ASP.NET Core
Write custom ASP.NET Core middleware

Writing a GraphQL service using graphql-dotnet and ASP.NET core

Introduction

GraphQL is classified as a query language for querying your data.

I’m not going to go into a full description of it’s capabilities/uses, for that go to the GraphQL website, but one thing which has always interested me, is an API where the client application can tell the server API what data to return. Thus allow the client to reduce bandwidth as well as reduce the amount of data being deserialised to exactly what the client application requires – obviously particularly useful for mobile applications.

Using graphiql-dotnet and ASP.NET core

We’re going to be using graphql-dotnet and ASP.NET core to implement a basic

  • Create an ASP.NET Core Web Application, mine’s named GraphQLService
  • Select an Empty project
  • I’m going to uncheck “Configure for HTTPS”
  • Now add the following packages via NuGet
    • GraphQL.Server.Transports.AspNetCore
    • GraphQL.Server.Transports.WebSockets
    • GraphQL.Server.Ui.GraphiQL
    • GraphQL.Server.Ui.Playground
    • GraphQL.Server.Ui.Voyager
    • GraphQL-Parser

Note: We’ve added the GraphQL.Server.Ui.Playground package to allow us to write queries within an interactive environment (http://localhost:5000/ui/playground) which also allows us to view the schema definitions etc. We’ve added GraphQL.Server.Ui.Voyager which adds a cool schema/type viewer (http://localhost:5000/ui/voyager). Finally we’ve added GraphQL.Server.Ui.GraphiQL to allow us to use the well known GraphiQL interactive environment (http://localhost:5000/ui/graphiql), feel free to remove all or some of these as required.

Remove the code from the Configure method of the Startup.cs file except for the following

if (env.IsDevelopment())
{
   app.UseDeveloperExceptionPage();
}

Now we’re going to add some tools, the playground (an interactive query web app) the voyager for digging into the schema and the GraphQL endpoint. So add the following to the Startup.cs below the code shown above

app.UseWebSockets();
app.UseGraphQLWebSockets<PersonSchema>("/graphql");
app.UseGraphQL<PersonSchema>("/graphql");
app.UseGraphQLPlayground(new GraphQLPlaygroundOptions()
{
   Path = "/ui/playground",
});
app.UseGraphiQLServer(new GraphiQLOptions
{
   GraphiQLPath = "/ui/graphiql",
   GraphQLEndPoint = "/graphql"
});
app.UseGraphQLVoyager(new GraphQLVoyagerOptions()
{
   GraphQLEndPoint = "/graphql",
   Path = "/ui/voyager"
});

Finally within Startup.cs, within the ConfigureServices method add the following code, which will register some types (which we’ll be supplying soon, the schema and query classes) and configures the GraphQL middleware.

services.AddSingleton<PersonSchema>();

services.AddGraphQL(options =>
{
   options.EnableMetrics = true;
   options.ExposeExceptions = true;
})
.AddWebSockets()
.AddDataLoader();

Schema

At this point we can see a need for the classes PersonSchema and PersonQuery. As you’ve realised, we are needing to create a schema object which will define our queries and types that we can query against. We’ll just create the bare bones schema class in PersonSchema.cs

public class PersonSchema : Schema
{
   public PersonSchema()
   {
      Query = new PersonQuery();
   }
}

Queries

Now we’ll create a bare PersonQuery.cs file which will be the starting point for some query functionality

public class PersonQuery : ObjectGraphType
{
}

At this point we could compiler and run the ASP.NET core application and navigate to http://localhost:5000/ui/playground to view the playground web application. However there’s not much we can do at this point.

Let’s add a domain object which represents a Person object, so add the following class. This represents the class that might come from a database or from another service

public class Person
{
   public string Name { get; set; }
}

For graphql-dotnet to allow us to use this class we need to wrap our Person object within a graphql-dotnet type, so create the following PersonType

public class PersonType : ObjectGraphType<Person>
{
   public PersonType()
   {
      Field(o => o.Name);
   }
}

In this case graphql-dotnet will now map fields to the Person object via the Field methods. This type then needs to be added to the PersonQuery class, to allow for querying again PersonType (and then ultimately Person) data. So add the PersonQuery constructor with the following code

public PersonQuery()
{
   Field<ListGraphType<PersonType>>("people", resolve: context => new[]
   {
      new Person {Name = "Scooby Doo"},
      new Person {Name ="Daphne Blake" },
      new Person {Name ="Shaggy Rogers" },
      new Person {Name ="Velma Dinkley" },
      new Person {Name ="Fred Jones" }
   });
}

Now if we run the application and navigate to http://localhost:5000/ui/playground we’ll find a Schema tab which displays information about how to query our data and if we write the following query

{
  people {
     name
  }
}

and run it from the playground we’ll see a list of the names from our Person data.

The previous example omitted the query keyword, i.e. it would look like this in a more formal definition of a query

query {
  people {
     name
  }
}

We can also implement our own query methods that might be called using the following (the C# for this is shown further down the post)

find(input : "Scooby Doo") {
   name
}

Or we can create a query which takes parameters/arguments from query variables. This example shows the use of an operation name, i.e. getPerson.

Note: operation names can be used for queries, mutations and subcriptions.

query getPerson($input : String) {
  find(input : $input) {
    name
  }
}

along with the input

{
  "input" : "Scooby Doo"
}

We’ll now create an input type in C# which will work with the above queries, such as

public class PersonInputType : InputObjectGraphType
{
   public PersonInputType()
   {
      Field<StringGraphType>("input");
   }
}

Now add another field to the PersonQuery constructor like this

Field<PersonType>(
   "find", 
   arguments: new QueryArguments(
      new QueryArgument<StringGraphType> 
      {
         Name = "input"
     }),
   resolve: context =>
   {
      var i = context.GetArgument<string>("input");
      return new Person {Name = i.ToString()};
   });

In the above, we essentially have created a new field in the PersonQuery which acts like a method, it is of type PersonType (the return type in this instance) and named find it takes a single argument of type string and expects the argument name of input. Finally it resolves to a method which we can then write something more substantial code for querying our data. In this simple example we’re just returning the argument passed in.

Note: We can also create multiple queries, so for example say we want to locate Person A and Person B and return data as a single result, we could write

{
   A : find(input : "Scooby") {
      name
   }
   B : find(input : "Shaggy") {
      name
   }
}

In the above query we use a GraphQL feature using aliases, the A and B acting like variable names. This allows us to create multiple queries against the same query/method.

When our queries start to become more complicated, we might prefer to place the field selection into, what’s know as a fragment, for example

{
   find(input : "Scooby") {
    ...fields
   }
}

fragment fields on PersonType {
  name
}

Obviously in our example it took more work to create and use the fragment that just using the field name, but you get the idea. However fragments can also be reused if we had multiple queries, so hence with more fields this become a much more useful technique.

Mutations

We’ve created our queries, which is great for scenarios where we’re simply reading data, but we can also create mutations, i.e. code that changes our data.

We can write a GraphQL mutation like this

mutation addPerson($input : String) {
   addPerson(input : $input)
   {
      name
   }
}

along with input such as

{
  "input" : "Scooby Doo"
}

What we now need to do is create our mutation class, like this

public class PersonMutation : ObjectGraphType<Person>
{
   public PersonMutation()
   {
      Field<PersonType>("addPerson",
         arguments: new QueryArguments(
            new QueryArgument<StringGraphType> {Name = "input"}),
         resolve: context =>
         {
            var n = context.GetArgument<string>("input");
            return new Person { Name = n };
         });
    }
}

We also need to alter the PersonSchema constructor to look like this

public PersonSchema()
{
   Query = new PersonQuery();
   Mutation = new PersonMutation();
}

Subscriptions

As you might expect, subscriptions are a way to handle something similar to events, hence we can connect to our service and received updates. Here’s a simple example of a query

subscription {
  personAdded {
    name
  }
}

Here’s a simple example of a subscription, to keep things simple this will simply send a message every second to any subcribers

public class PersonSubscription : ObjectGraphType
{
   public PersonSubscription()
   {
      AddField(new EventStreamFieldType
      {
         Name = "personAdded",
         Type = typeof(PersonType),
         Resolver = new FuncFieldResolver<Person>(ResolvePerson),
         Subscriber = new EventStreamResolver<Person>(SubscribePerson)
      });
   }

   private Person ResolvePerson(ResolveFieldContext context)
   {
      return context.Source as Person;
   }

   private IObservable<Person> SubscribePerson(ResolveEventStreamContext context)
   {
      return Observable.Interval(
         TimeSpan.FromSeconds(1))
           .Select(s => new Person 
           {
              Name = s.ToString()
           });
   }
}

Now we need to update the schema constructor like this

public PersonSubscription()
{
   AddField(new EventStreamFieldType
   {
      Name = "personAdded",
      Type = typeof(PersonType),
      Resolver = new FuncFieldResolver<Person>(ResolvePerson),
      Subscriber = new EventStreamResolver<Person>(SubscribePerson)
   });
}

Further reading

Refer to the GraphQL site for in depth examples and more complete explanations of the everything I’ve discussed above.

Also check out the GraphQL.net web site for graphql-dotnet documentation.

If you’re interested in code for the project, it’s available on GitHub.

More ASP.NET Core with C#

In the previous post I looked into the F# Giraffe library which makes writing all sorts of web request/response code pretty simple. This in turn is built on top of the existing functionality within ASP.NET Core.

Let’s again look at the bare bones code from running up Kestrel adding code to the pipeline

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;

namespace KestrelTest
{
    public class Startup
    {
        public void Configure(
            IApplicationBuilder applicationBuilder,
            IHostingEnvironment hostingEnvironment)
        {
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WebHost.CreateDefaultBuilder()
                .UseStartup<Startup>()
                .UseKestrel()
                .Build()
                .Run();
        }
    }
}

Within the Configure method we can start adding code to respond to different routes using the Map method, for example add the following to the Configure method

applicationBuilder.Map("/hello", app =>
{
   app.Run(async ctx =>
   {
      var request = 
         ctx.Request.Path.HasValue ? 
            ctx.Request.Path.Value.Substring(1) : 
            String.Empty;
       await ctx.Response.WriteAsync("Hello " + request);
   });
});
applicationBuilder.Map("/error", app =>
{
   app.Run(ctx => 
      Task.FromResult(
         ctx.Response.StatusCode = 404) 
   );
});

Note: The code is somewhat basic, obviously you would probably want to write some better code for extracting partial paths etc. from the routes/maps. However we’ll be covering a better alternative to this sort of code later in the post.

In the above we’ve created the equivalent of two “routes”. The first handles URL’s along the line of localhost:5000/hello/World where the return would become “Hello World”. The second route simply responds with a 404 for the URL localhost:5000/error.

We can also (as you’d expect) handle queries within our URL, so let’s say we expect this format URL, http://localhost:5000/hello?name=World, then we can amend our /hello code to the following

applicationBuilder.Map("/hello", app =>
{
   app.Run(async ctx =>
   {
      await ctx.Response.WriteAsync(
         "Hello " + ctx.Request.Query["name"]);
   });
});

These pieces of code write responses, but we can also insert code into the pipeline which doesn’t write to the response but instead might add debug/logging code. Other examples of usage might include (as per Writing Middleware) changes to the culture for the user response.

Here’s a simple example of such code, this is a little contrived as we’re going to (in essence) redirect calls to /hello path. Just place the following code before the applicationBuilder.Map method in the above

applicationBuilder.Use(async (ctx, next) =>
{
   if (ctx.Request.Path.Value == "/hello")
   {
      ctx.Request.Path = new PathString("/error");
   }
   await next.Invoke();
});

Note: there are redirect/URL rewriting capabilities already in ASP.NET Core, see URL Rewriting Middleware in ASP.NET Core.

Routing

In the previous example we demonstrated using the Map method to route our calls but ASP.NET Core libraries already supply a routing middleware which handles a lot of the standard routing type of functionality we’d expect. We can add the routing services by adding a method to the Startup class like this

public void ConfigureServices(
   IServiceCollection services)
{
   services.AddRouting();
}

Now the Configure method should look like this

public void Configure(
   IApplicationBuilder applicationBuilder,
   IHostingEnvironment hostingEnvironment)
{
   var routes = new RouteBuilder(applicationBuilder);
   routes.MapGet("hello/{name}", ctx =>
   {
      var name = ctx.GetRouteValue("name");
      return ctx.Response.WriteAsync($"Hello {name}");
   });

   applicationBuilder.UseRouter(routes.Build());
}

The RouteBuilder handles the routing in a more helpful/useful manner. Don’t forget to use the line applicationBuilder.UseRouter(routes.Build()); or you’ll find that the routes are not registered and hence your code will never get called.

References

ASP.NET Core MiddlewareRouting in ASP.NET Core

Using Giraffe as a service pipeline in Kestrel

In the previous post we looked at using Kestrel to run an ASP.NET Core application, now we’re going to use Giraffe to build some services.

Giraffe is an F# library to let get started by creating our application code.

  • Create Visual F# | .NET Core | Console App
  • My project is named GiraffeTest
  • Add via NuGet Giraffe and Microsoft.AspNetCore

Replace Program.fs code with the following

open Giraffe
open Microsoft.Extensions.DependencyInjection
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting
open Microsoft.AspNetCore

let webApp =
    choose [
        GET >=>
            choose [
                routeCif "/hello/%s" (fun name -> text (sprintf "Hello %s" name))
            ]
    ]

type Startup() =
    member this.ConfigureServices (services : IServiceCollection) =
        services.AddGiraffe() |> ignore

    member this.Configure (app : IApplicationBuilder) =
        app.UseGiraffe webApp

[<EntryPoint>]
let main _ =
    WebHost.CreateDefaultBuilder()
        .UseKestrel()
        .UseStartup<Startup>()
        .Build()
        .Run()
    0

In the previous post we saw how to create the Kestrel server, so the code in main is exactly the same (apart from obviously being F#) which creates the server and calls the Startup class to configure our middleware. In this case we add Giraffe to the services and runs the Giraffe webApp HTTP handler.

The webApp HTTP handler is basically our filter and routing function.

Run this code up and navigate to localhost:5000/hello/World and we should get Hello World displayed.

We didn’t actually need the GET handler as by default the GET will be used, but it’s shown here to be a little more explicit in what is being implemented. We can also support POST methods using the same syntax as our GET code.

Extending our routes

Giraffe allows us to declare multiple routes which can include static pages. Let’s start off my adding an index.html page to the “Content root path” as displayed when running the application, in my case this is the folder containing Program.fs. I’m using the following index.html

<html>
    <body>
        Hello World
    </body>
</html>

Now add a new route to the route section of the webApp. i.e.

choose [
    routeCif "/hello/%s" (fun name -> text (sprintf "Hello %s" name))
    route "/" >=> htmlFile "index.html"
]

This has now added a route for localhost:5000/ which returns the contents of the index.html file.

A list of different routes can be seen in the source for Routing.fs.

Below is an example of using some different routes

let helloName name = text (sprintf "Hello %s" name)

let webApp =
    choose [
        GET >=>
            choose [
                // case insensitive using anonymous function
                routeCif "/hello/%s" (fun name -> text (sprintf "Hello %s" name))
                route "/"       >=> htmlFile "index.html" 
                route "/error"  >=> setStatusCode 404
                route "/ping"   >=> text "pong"
                // case sensitive use function
                routef "/hello2/%s" helloName
            ]
    ]

Return from the fish (>=>) operator can be marked as different types of result types.
The functions text, htmlFile and other response writes available here ResponseWriters.fs. These include the usual suspects such as XML and JSON. Giraffe also supports Razor, see the NuGet package Giraffe.Razor.

References

Giraffe GitHub repos.

Kestrel – ASP.NET core web server

Kestrel is a .NET Core cross platform web server that can be used to host web sites, web/REST services etc.

Note: This code covers .NET core 2.0 and ASP.NET core 2.0.1

Take a look at Introduction to Kestrel web server implementation in ASP.NET Core for a great post about using Kestrel along with IIS, Nginx etc.

Getting Started

Let’s get started and build a very basic application running Kestrel.

  • Create a Visual C# | .NET Core | Console App (.NET Core) application
  • My project is named KestrelTest
  • Use NuGet to add the package Microsoft.AspNetCore

Now let’s create the most basic and most useless web server by writing the following code

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;

namespace KestrelTest
{
    public class Startup
    {
        public void Configure(IApplicationBuilder applicationBuilder,
            IHostingEnvironment hostingEnvironment)
        {
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WebHost.CreateDefaultBuilder()
                .UseStartup<Startup>()
                .UseKestrel()
                .Build()
                .Run();
        }
    }
}

In Main we create the webserver and we supply the Startup application which we’d use to configure our services. Minimally we need the Configure method in the Startup object and notice we’re not adhering to any specific interface or type.

We could pass the args to the CreateDefaultBuilder if we want to start the application with certain arguments and/or use the UseKestrel override to create options for our server, but we’re aiming to just create the bare essentials of a Kestrel based web server in this post.

Now we can run this code and we’ll get, by default, a web server running and exposing port 5000 on localhost. However the server does nothing else, no static pages, nothing.

So let’s now add the NuGet package Microsoft.AspNetCore.StaticFiles and change our Configure method to look like this

public void Configure(
   IApplicationBuilder applicationBuilder,
   IHostingEnvironment hostingEnvironment)
{
   applicationBuilder.UseWelcomePage();
}

Now run the application and using your preferred web browser, navigate to localhost:5000 and you should see a ASP.NET Core Welcome Page.

Again this is of little use but does show that everything is working.

Serving up some static content

See Work with static files in ASP.NET Core for more in depth information.

Let’s now use Kestrel to serve up some static pages. Change the Configure method to look like this

public void Configure(
   IApplicationBuilder applicationBuilder,
   IHostingEnvironment hostingEnvironment)
{
   applicationBuilder.UseStaticFiles();
}

Now in your project folder (i.e. the folder with your Program.cs file) which should be the same as the Content root path shown when you run the application. Here you can add a wwwroot folder and place an HTML page in the folder, i.e. here’s a simply index.html file

<html>
    <body>
        Hello World
    </body>
</html>

Make sure you set the file to have the “Copy to Output Directory” option as “Copy if Newer” in the properties window in Visual Studio.

Run the application again and navigate to localhost:5000/index.html and you should see the text Hello World.

Middleware

As we’ve seen in this post, the design of Kestrel is to supply a default web server application which we can then add our middleware code to, turning the application into a static web server or adding ASP.NET MVC into the mix etc. We can implement our own middle ware (see ASP.NET Core Middleware) which can be used to handle requests via a middleware pipeline.

I’m not going to go into any real depth in terms of developing my own middleware as we can already use various libraries for this, but just to demonstrate how we can intercept a request, change the Configure method to look like this

public void Configure(
   IApplicationBuilder applicationBuilder,
   IHostingEnvironment hostingEnvironment)
{
   applicationBuilder.Run(async context =>
   {
      await context.Response.WriteAsync("***Hello World***");
   });
}

Now if we run up the application and navigate to localhost:5000 we should see ***Hello World*** returned.

References

Introduction to Kestrel web server implementation in ASP.NET Core
BenchmarksASP.NET Core Web Servers: Kestrel vs IIS Feature Comparison and Why You Need Both