I'm trying to test some error responses (BadRequest, Unauthorized, ...) with Refit and so I implemented a TestHandler that returns any desired response. The response works fine with an "OK" (HTTP status code 200) response:
public class Program
{
private static async Task Main()
{
var api = RestService.For<ITest>(
new HttpClient(new TestHandler(HttpStatusCode.OK))
{
BaseAddress = new Uri("https://example.com")
}
);
Console.WriteLine(await api.Test("foo").ConfigureAwait(false));
}
}
public interface ITest
{
[Get("/foo/{bar}")]
Task<string> Test(string bar);
}
public class TestHandler : HttpMessageHandler
{
private readonly HttpResponseMessage _response;
public TestHandler(HttpStatusCode httpStatusCode)
=> _response = new HttpResponseMessage(httpStatusCode) { Content = new StringContent("Yay!") };
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
=> Task.FromResult(_response);
}
However, whenever I change the response status code to, for example, BadRequest (400), NotFound (404) or Unauthorized (401) Refit throws a NullReferenceException
:
Object reference not set to an instance of an object.
at Refit.DefaultApiExceptionFactory.<CreateExceptionAsync>d__4.MoveNext() in /_/Refit/RefitSettings.cs:line 183
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at Refit.RequestBuilderImplementation.<>c__DisplayClass14_0`2.<<BuildCancellableTaskFuncForMethod>b__0>d.MoveNext() in /_/Refit/RequestBuilderImplementation.cs:line 313
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at RefitTest.Program.<Main>d__0.MoveNext() in C:\Users\Rob\Source\Repos\RefitTest\RefitTest\Program.cs:line 18
This points to RefitSettings.cs line 183. But I can't figure out why a 200 OK would work but any other response won't? What am I doing wrong?
Edit: In an effort to debug this further I cloned Refit and swapped the Refit NuGet package for a project reference to the Refit project. This results in a InvalidOperationException: ITest doesn't look like a Refit interface. Make sure it has at least one method with a Refit HTTP method attribute and Refit is installed in the project
. Also, going back a few versions (I've gone to 5.2.4) doesn't help.
CodePudding user response:
Found it, with help from a colleague! Turns out the HttpResponseMessage
needs some/any RequestMessage
.
Change
public TestHandler(HttpStatusCode httpStatusCode)
=> _response = new HttpResponseMessage(httpStatusCode)
{
Content = new StringContent("Yay!")
};
To:
public TestHandler(HttpStatusCode httpStatusCode)
=> _response = new HttpResponseMessage(httpStatusCode)
{
RequestMessage = new(), // <-- This one here...
Content = new StringContent("Yay!")
};
And it works as expected. As in the question (and comments), I was close but, apparently half-asleep, because it's exactly where it pointed me at.