Calling ASP.NET Web API end-points for testing purposes with Refit in .NET Core
Back in August I wrote Calling ASP.NET Web API end-points for testing purposes where I described a "bare metal" approach to calling Web Api methods using HttpClient by creating a wrapper that could then be used to periodically call methods in an application, which I was using in production to verify the health of certain application components. This code can be massively simplified by using the Refit library to do the heavy lifting.
Using Refit in a .NET Core Console App
First up is creating the console app which I've done this time around using Visual Studio, then adding a reference to Refit via the Package Manager console:
Install-Package Refit
With Refit added to the project, the next thing to do is to add an interface that describes the API methods that will be called, annotating them with an attribute that describes the HTTP method that each method requires along with parameters that describe the, well, parameters that each API method takes when called:
using Refit; using System.Threading.Tasks; namespace TestingWebApiMethodsWithRefit { public interface ILoginApi { [Post("/api/login/authenticatecredentials")] Task<LoginResponse> Login([Body]LoginRequest loginRequest); } }
Here's the definition of the API method that this will be used to call:
[Route("api/login/authenticatecredentials")] public async Task<IHttpActionResult> AuthenticateCredentialsAsync([FromBody] AuthenticateCredentials authenticateCredentials)
So the ILoginApi interface has one member, a method called Login which will be used to call a Web Api method via the URI /api/login/authenticatecredentials returning a response that can be translated into a class called LoginResponse (shown below). This method actually takes multiple parameters (Username and Password) contained in an instance of AuthenticateCredentials via the Body of the POST request, which is why the only parameter to ILoginApi.Login is annotated with the Body attribute.
In my .NET Core console app I've defined LoginResponse and LoginRequest as:
public class LoginRequest { public string Username { get; set; } public string Password { get; set; } } public class LoginResponse { public int[] SecondFactorLetterPosition { get; set; } public string TemporaryAuthenticationToken { get; set; } }
With these defined it's now a matter of making a call to the API method and seeing it succeed (which does also require me to enter the password correctly in the test code!). This can be achieved by adding two lines to the programs Main method:
var api = RestService.For<ILoginApi>("https://localhost"); var loginResult = await api.Login(new LoginRequest { Username = "[email protected]", Password = "MyPasswordGoesHere" });
This is a lot simpler than the solution I wrote previously as up until this point the only code I've written is boiler-plate that describes the API surface, there's not one single line of code that actually really does anything until we get to the code that goes in the Main method. Unfortunately, building the app throws up a small niggle as I'm using await in a method that isn't async. This is easy to fix by changing the signature of the Main method to:
static async Task Main(string[] args)
But (and there's always a but!) that then throws up CS5001 Program does not contain a static 'Main' method suitable for an entry point from the compiler. Luckily that's quite easily solved by updating the project to target a version of C# that supports async Main:
With that out of the way, building and hitting F5 (after setting a breakpoint on the line after the call to api.Login so the result can be seen!) spins for a moment and then hits the breakpoint so we can take a look at the result:
Looks good! If you want/need to handle failures (which you will!) you can catch instances of Refit.ApiException being thrown and react accordingly.