#c# #rest #unit-testing #nullreferenceexception #refit
Вопрос:
Я пытаюсь проверить некоторые ответы на ошибки (неверный запрос, несанкционированный, …) с помощью Refit, и поэтому я реализовал тест-манипулятор, который возвращает любой желаемый ответ. Ответ отлично работает с ответом «ОК» (код состояния HTTP 200) .:
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);
}
Однако всякий раз, когда я изменяю код состояния ответа, например, на BadRequest (400), NotFound (404) или Unauthorized (401), при обновлении возникает 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:UsersRobSourceReposRefitTestRefitTestProgram.cs:line 18
Это указывает на строку 183 RefitSettings.cs. Но я не могу понять, почему 200 ОК сработает, но любой другой ответ не сработает? Что я делаю не так?
Редактировать: В попытке отладить это дальше, я клонировал Refit и заменил пакет Refit NuGet ссылкой на проект Refit. Это приводит к 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
. Кроме того, возврат к нескольким версиям (я перешел на 5.2.4) не помогает.
Комментарии:
1.
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?
github.com/reactiveui/refit/blob/… этот метод вызывается для неудачных ответов, таких как 400, 404, 401… И, вероятно, вы получаетеNullReferenceException
это потому, что ! (не прощающий) docs.microsoft.com/en-us/dotnet/csharp/language-reference/…` поддерживается только в C# 82. @демо У меня есть
<LangVersion>latest</LangVersion>
в моем файле проекта .net 5.0.3. @demo Также добавил
<Nullable>enable</Nullable>
, на всякий случай, никакой разницы.4. тогда похоже, что ответ равен нулю… или я не понимаю, что/почему…
5. @demo Ответ содержится в коде:
new StringContent("Yay!")
(и да, я также пробовал допустимый JSON, на случай, если при переоборудовании ожидался бы JSON). И, как указано в вопросе: он отлично работает с 200 ок. Просто не со статусами 4xx (еще не пробовал 3xx или 5xx).
Ответ №1:
Нашел его с помощью коллеги! Оказывается HttpResponseMessage
, нужны некоторые/любые RequestMessage
.
Изменить
public TestHandler(HttpStatusCode httpStatusCode)
=> _response = new HttpResponseMessage(httpStatusCode)
{
Content = new StringContent("Yay!")
};
Для:
public TestHandler(HttpStatusCode httpStatusCode)
=> _response = new HttpResponseMessage(httpStatusCode)
{
RequestMessage = new(), // <-- This one here...
Content = new StringContent("Yay!")
};
И это работает так, как и ожидалось. Как и в вопросе (и комментариях), я был близок, но, по-видимому, в полусне, потому что это именно то, на что он указал мне.
Я представил здесь проблему.