All of the examples I've been able to find show the client consuming services from a root address. When I tried consuming from a subfolder, the client strips the relative path and just uses the base Uri.
For example:
var channel = GrpcChannel.ForAddress("mydomain.com/myApi", new GrpcChannelOptions
{
HttpClient = new HttpClient(handler)
});
Shows up in Chrome as
Request URL: http://mydomain.com/Class.Collection/GetMethod
Instead of
Request URL: http://mydomain.com/myApi/Class.Collection/GetMethod
Ahh, digging into this it looks like it's intentional. Unfortunate. Works fine in my corp environment where I have a hundreds of thousands of dollars system with containers, ingress management, wildcard certs and all the fixings! Each service being deployed on it's own node with it's own subdomain works like a charm!
Sucks for my hobby projects hosted on a shared host with a bargain bin cert and no frills. :( I've got a dozen different web apps and one domain. So either I need to package all of my services into a single deployable app, or pony up hundreds of dollars to get a wildcard cert for an unpaid hobby site :(
See also some earlier discussion in https://github.com/grpc/grpc-dotnet/issues/110.
Would hosting each service on a different port work in your situation? That may be a different way to approach this.
Unfortunately not. Running on a shared instance el-cheapo host. Best case is building out URL rewrites and getting another cert. Or just admitting defeat, that gRPC isn't appropriate for this usecase, and going back to the sad world of REST end points :(
Is your issue with the server not supporting gRPC services in sub-directories or the client being able to call gRPC services in sub-directories?
Here is an example of a DelegatingHandler that you could use to inject a subdirectory into a gRPC call URI:
/// <summary>
/// A delegating handler that will add a subdirectory to the URI of gRPC requests.
/// </summary>
public class SubdirectoryHandler : DelegatingHandler
{
private readonly string _subdirectory;
public SubdirectoryHandler(HttpMessageHandler innerHandler, string subdirectory) : base(innerHandler)
{
_subdirectory = subdirectory;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var url = $"{request.RequestUri.Scheme}://{request.RequestUri.Host}{_subdirectory}{request.RequestUri.AbsolutePath}";
request.RequestUri = new Uri(url, UriKind.Absolute);
return base.SendAsync(request, cancellationToken);
}
}
Using it:
var handler = new SubdirectoryHandler(new HttpClientHandler(), "/TestSubdirectory");
var httpClient = new HttpClient(handler);
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greet.GreeterClient(channel);
The call will go to the URL: https://localhost:5001/TestSubdirectory/greet.Greeter/SayHello
Nice, I'll give this a try!
Most helpful comment
Here is an example of a DelegatingHandler that you could use to inject a subdirectory into a gRPC call URI:
Using it:
The call will go to the URL:
https://localhost:5001/TestSubdirectory/greet.Greeter/SayHellohttps://github.com/grpc/grpc-dotnet/pull/882