1
votes

The following code snippet shows how gRPC web is enabled in a gRPC AspNet core application:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseDefaultFiles();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseGrpcWeb();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<SubmissionService>().EnableGrpcWeb();
        });
    }
}

The client app's code looks like the following:

public static async Task SendSomethingAsync(string payload, ILoggerFactory loggerFactory)
        {
            const string url = "https://MASKED.azurewebsites.net/";
            //const string url = "https://localhost:44308";
            AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
            var handler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler());
            using var channel = GrpcChannel.ForAddress(url, new GrpcChannelOptions
            {
                HttpClient = new HttpClient(handler),
                LoggerFactory = loggerFactory
            });

            var client = new TestgRPC.gRPC.PayloadSubmission.PayloadSubmissionClient(channel);
            var submitted = await client.SubmitAsync(new SubmissionRequest
            {
                ClientKey = "678",
                ConnectionId = "abcdef",
                UserId = "3",
                MyObjectPayload= payload,
            });

            Console.WriteLine($"Submitted: {submitted}");
        }

The client code (above) receives the reply back from gRPC server when it's hosted on localhost (the development machine). The same client code fails to communicate with the server's instance hosted on Azure and it logs the following failure message:

dbug: Grpc.Net.Client.Internal.GrpcCall[18] Sending message. fail: Grpc.Net.Client.Internal.GrpcCall[20] Error sending message. System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Net.Http.TaskCompletionSourceWithCancellation1.WaitWithCancellationAsync(CancellationToken cancellationToken) at System.Net.Http.Http2Connection.Http2Stream.SendDataAsync(ReadOnlyMemory1 buffer, CancellationToken cancellationToken) at Grpc.Net.Client.Web.Internal.Base64RequestStream.WriteAsync(ReadOnlyMemory1 data, CancellationToken cancellationToken) at Grpc.Net.Client.StreamExtensions.WriteMessageAsync[TMessage](Stream stream, ILogger logger, TMessage message, Action2 serializer, String grpcEncoding, Nullable1 maximumMessageSize, Dictionary2 compressionProviders, CallOptions callOptions) fail: Grpc.Net.Client.Internal.GrpcCall[6] Error starting gRPC call. System.Threading.Tasks.TaskCanceledException: The operation was canceled. at System.Net.Http.CancellationHelper.ThrowOperationCanceledException(Exception innerException, CancellationToken cancellationToken) at System.Net.Http.CancellationHelper.ThrowIfCancellationRequested(CancellationToken cancellationToken) at System.Net.Http.Http2Connection.Http2Stream.GetCancelableWaiterTask(CancellationToken cancellationToken) at System.Net.Http.Http2Connection.Http2Stream.ReadResponseHeadersAsync(CancellationToken cancellationToken) at System.Net.Http.Http2Connection.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at Grpc.Net.Client.Web.GrpcWebHandler.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts) at Grpc.Net.Client.Internal.GrpcCall2.RunCall(HttpRequestMessage request, Nullable`1 timeout) info: Grpc.Net.Client.Internal.GrpcCall[3] Call failed with gRPC error status. Status code: 'Cancelled', Message: ''. dbug: Grpc.Net.Client.Internal.GrpcCall[4] Finished gRPC call.

I could not find out what is hindering this communication to happen and what solution to implement. Any ideas why?

As a side note, I exhausted everything in this github ticket but no luck at all.

1
@Thiago Custodio the code snippet that I already posted shows that I am using grpc-web, doesn't it?Arash
@ThiagoCustodio please check out this link: github.com/grpc/grpc-dotnet/issues/759#issuecomment-583318085 It confirms that a gRPC-web app can be hosted on Azure.Arash

1 Answers

1
votes

The issue is that we needed to deploy the application as a self-contained application. Apparently the default .net core 3.1 installed on Azure app services cannot accommodate a gRPC-web app.