A Web Server that Echoes Requests and Sometimes Faults with a 500 Error

Download full source code.

Last month I wrote a post about building a server that echoes the request it receives. I use it when I want to test HttpClient, HttpClientFactory, or related tools.

I thought it would be fun to build a faulting echo server. This server will return a 500 error for a percentage of the time. This is a great way to test your error handling code. The provided code throws an exception 50% of the time, but you can easily extend the example to take parameters to control the percentage of errors, or the type of error. If you wanted to do this, I suggest doing it via header parameters.

Here are the basics.

The Response

The first thing I need is a model to send as the response. I’ll call it EchoResponse. I’ve included the properties from the request that I’m interested in, you may want fewer, or more -

public class EchoResponse
{
   public string Body { get; set; }
   public IHeaderDictionary Headers { get; set; }
   public string Method { get; set; }
   public PathString Path {get; set; }
   public QueryString QueryString { get; set; } 
   public IQueryCollection Query { get; set; }
}

Then I need an extension method to convert the HttpRequest to an EchoResponse -

public static class ExtensionMethods
{
   public static async Task<EchoResponse> ToEchoResponseAsync(this HttpRequest request)
   {
      var echoResponse = new EchoResponse();
      using (StreamReader streamReader = new StreamReader(request.Body))
      {
         echoResponse.Body = await streamReader.ReadToEndAsync();
      };
      echoResponse.Method = request.Method;
      echoResponse.Headers = request.Headers;
      echoResponse.Path = request.Path;
      echoResponse.QueryString = request.QueryString;
      echoResponse.Query = request.Query;
      
      return echoResponse;
   }
}

The Simmy NuGet Package

Simmy allows you to inject faults into your code. I’ve written a few posts about it.

Add Simmy to your project -

dotnet add package Polly.Contrib.Simmy

Create the fault policy

Open the Program.cs file and add two using statements -

using Polly.Contrib.Simmy;
using Polly.Contrib.Simmy.Outcomes;

Below the line where WebApplication.CreateBuilder(args) is called, add the following -

Exception fault = new Exception("Big problem");
AsyncInjectOutcomePolicy chaosPolicy = MonkeyPolicy.InjectExceptionAsync(with =>
    with.Fault(fault)
        .InjectionRate(0.5)
        .Enabled()
);
builder.Services.AddSingleton<AsyncInjectOutcomePolicy>(chaosPolicy);

The above creates the chaos policy and adds it to the service collection. The policy will inject a fault 50% of the time.

You can now use the policy with API endpoints, or full controllers.

Minimal API Endpoint

This will map all HTTP methods to the same endpoint, for all URLs -

app.Map("{*anyurl}", async (HttpRequest httpRequest, AsyncInjectOutcomePolicy chaosPolicy) => 
{
    return await chaosPolicy.ExecuteAsync(() => httpRequest.ToEchoResponseAsync());
});

Now you can use GET/PUT/POST/PATCH/DELETE with any URL and this endpoint will be hit.

That’s it! Simple!

Controller

To use the policy with a controller, add the policy to the constructor -

using Microsoft.AspNetCore.Mvc;
using Polly.Contrib.Simmy.Outcomes;

[ApiController]
[Route("[controller]")]
public class EchoController : ControllerBase
{
    private readonly AsyncInjectOutcomePolicy _chaosPolicy;
    public EchoController(AsyncInjectOutcomePolicy chaosPolicy)
    {
        _chaosPolicy = chaosPolicy;
    }
    
    public async Task<EchoResponse> All()
    {
        return await _chaosPolicy.ExecuteAsync(() => Request.ToEchoResponseAsync());
    }
}

You should use only the minimal endpoint or the controller at one time.

Testing it out

Use tools such as Fiddler, Postman, or Rest Client for VS Code (I’ve included a sample file in the attached zip) to make requests to the API.

Download full source code.

comments powered by Disqus

Related