dotnet / dotnet/aspnetcore

ASP.NET gRPC service in IIS10 does propagate gRPC status codes

Open
#60,929 1 comment 0 reactions 0 assignees View on GitHub
area-grpc feature-iis
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 10h
Merged PRs (30d)
281

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Describe the bug

We have an ASP.NET application providing a number of gRPC services that works well hosted in Kestrel that we need to host with IIS10.
In IIS, gRPC calls the result in a success status code work fine. The trouble begins when the service reports an error status code. Any status code in the service always results in status code 13 (Internal) in the client. After lots of searching I found some mention of similar problems, that did not seem to get to the core of the problem. Most notably an [issue ](https://github.com/grpc/grpc-dotnet/issues/2062) in the dotnet-grpc repo that lead @JamesNK to open [this issue](https://github.com/grpc/grpc-dotnet/issues/2062) in this repo here. I can't tell if those lead to any action. It seems to have moved to .NET8 milestone but the issue seems to persist in .NET9.
In the aforementioned issue the problem was complicated by the reporter using a proxy service, so I decided to create a minimal example for myself to get to the root of the problem.

### Expected Behavior

An ASP.NET application hosted in IIS10 meeting the minimal requirements for servicing gRPC services propagates RpcExceptions thrown in the service correctly to the client, no matter the gRPC implementation.

### Steps To Reproduce

### 1. Create the following minimal example, based on the [Greeter-Service](https://github.com/grpc/grpc-dotnet/tree/5816e69828ece5b5f3474d98057c2bc89a64dfd7/examples/Greeter)
GreeterService.cs
```C#
using Greet;
using Grpc.Core;

namespace Server
{
public class GreeterService : Greeter.GreeterBase
{
private readonly ILogger _logger;

public GreeterService(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger();
}

public override Task SayHello(HelloRequest request, ServerCallContext context)
{
_logger.LogInformation($"Sending hello to {request.Name}");
throw new RpcException(new Status(StatusCode.PermissionDenied, "error"));
}
}
}
```
Program.cs
```C#
using Grpc.Core.Interceptors;
using Grpc.Core;
using Server;
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddGrpc(o =>
{
o.Interceptors.Add();
});
builder.Services.AddGrpcReflection();
var app = builder.Build();

// Configure the HTTP request pipeline.
app.MapGrpcService();
app.MapGrpcReflectionService();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");

app.Run();

public class WriteResponseHeadersInterceptor : Interceptor
{
public override async Task UnaryServerHandler(TRequest request, ServerCallContext context, UnaryServerMethod continuation)
{
// await context.WriteResponseHeadersAsync(new());
return await base.UnaryServerHandler(request, context, continuation);
}
}

```

The Program.cs contains an interceptor with the suggested workaround. The line providing the actual "fix" is commented out because the observed behavior is the same.

### 2. Start with IIS from Visual Studio

![Image](https://github.com/user-attachments/assets/9c181ce7-33e6-4117-ac7e-241ced936edf)

### 3. Test with grpcurl

![Image](https://github.com/user-attachments/assets/83f6ef18-9e12-487e-b6fe-8bde79ee3e07)

### 4. Positive-Control with Kestrel

![Image](https://github.com/user-attachments/assets/b33d3eb7-1ea0-4bc5-9f7e-795c0da78131)

![Image](https://github.com/user-attachments/assets/fd6bf2aa-eecd-4fae-9c5f-6f6b3f73a878)

The same behavior can be observed with Postman. The clients that connect to the production server use the C++ gRPC implementation and seem to suffer the same problem.

I can't think of a more minimal example than this. As far as I can tell, all prerequisites for using gRPC in IIS10 should be met (see below) and I would expect that status codes to be propagated correctly to any client regardless of the gRPC implementation.

I'm still hoping I'm doing something wrong and there is an easy fix!

### Exceptions (if any)

_No response_

### .NET Version

9.0.103

### Anything else?

Below are the version of the products I used locally for the minimal example. On the actual server where the problem surfaced we use Windows Server 2022 Version 10.0.20348 Build 20348

### Version information
#### Visual Studio
Microsoft Visual Studio Professional 2022 (64-bit) - Current
Version 17.12.5
#### Windows
Microsoft Windows 11 Pro
10.0.22631 Build 22631
#### grpcurl
v1.9.3
#### Build-Target
net8/net9

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.