#c# #async-await #grpc
#c# #асинхронное ожидание #grpc
Вопрос:
Я пытаюсь прочитать заголовок / метаданные ответа из вызова службы grpc. Чтобы сделать это в одной центральной точке, я использую пользовательский вызывающий вызов, который инкапсулирует реальную основу HttpClientInvoker
.
Мой вызывающий код пока очень прост, просто позвоните 3 раза
var greeter = new GreeterClient(new MyCustomCallInvoker());
await greeter.SayHelloAsync(new HelloRequest { Name = nameof(TestSayHello) });
await greeter.SayHelloAsync(new HelloRequest { Name = nameof(TestSayHello) });
await greeter.SayHelloAsync(new HelloRequest { Name = nameof(TestSayHello) });
Пользовательский вызыватель делает что-то вроде этого
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
Method<TRequest, TResponse> method,
string host,
CallOptions options,
TRequest request)
{
var result = Invoker.AsyncUnaryCall<TRequest, TResponse>(method, host, options, request);
Action updateMetadata = delegate
{
var trailers = result.GetTrailers();
UpdateMetadata(trailers);
};
result.GetAwaiter().OnCompleted(updateMetadata);
return resu<
}
Я знаю, что использование GetAwaiter()
не очень приятно. К сожалению, вызывающий здесь не используется Task
и AsyncUnaryCall
закрыт.
Однако вызов приветствия прошел 2 раза, прежде чем трейлеры были обновлены в первый раз.
Я не видел способа обновить локальные трейлеры сразу после Invoker.AsyncUnaryCall
прохождения и до того, как он вернется к вызывающему коду, не блокируя процесс. (РЕДАКТИРОВАТЬ: если я просто поставлю консоль.Напишите («готово») в OnCompleted, он работает так, как ожидалось.)
Это возможно каким-то образом?
Комментарии:
1. @yogihosting это не связано с моим вопросом. я думаю, это просто seo-ссылка для вашего сайта.
2. Я полагаю, вы имеете в виду
CallInvoker/DefaultCallInvoker
нетHttpClientInvoker
? Кроме того, откудаOnCompleted
берется?3. @IanKemp Я предполагаю, что это так: learn.microsoft.com/en-us/dotnet/api /…
4. @ChrisYungmann Ах, я ожидал чего-то в gRPC … не отправленный метод, помеченный как «Этот API поддерживает инфраструктуру продукта и не предназначен для использования непосредственно из вашего кода». IDisposable , вам, вероятно, не следует использовать этот метод, учитывая документацию.
5. Извините, вы правы @IDisposable ответ, который я опубликовал, не будет работать из-за упомянутой вами проблемы. Может быть, это поможет? github.com/grpc/grpc/issues/21489 Похоже, вам следует вернуть новый
AsyncUnaryCall
экземпляр, который затем вы можете предоставить любой асинхронной логике.
Ответ №1:
Потребовалось некоторое время, но я нашел решение, которым хочу поделиться с сообществом. Проблема здесь заключалась в том, что AsyncUnaryCall(который проводит TaskAwaiter) закрыт.
Я заглядываю в исходный код grpc и вижу, что AsyncUnaryCall — это просто контейнер для нескольких обратных вызовов. прототипы ctor выглядят следующим образом:
public AsyncUnaryCall(Task<TResponse> responseAsync, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction);
public AsyncUnaryCall(Task<TResponse> responseAsync, Func<object, Task<Metadata>> responseHeadersAsync, Func<object, Status> getStatusFunc, Func<object, Metadata> getTrailersFunc, Action<object> disposeAction, object state)
Это было решением моей проблемы: создать второй AsyncUnaryCall в качестве прокси, который инкапсулирует исходный AsyncUnaryCall и слегка модифицирует их, добавив GetTrailers в обратный вызов ResponseAsync.
Надеюсь, это поможет кому-то в будущем.