Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds MapGrpcService overload for ServerServiceDefinition #2586

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Adds new API: GrpcEndpointRouteBuilderExtensions.MapGrpcService
  • Loading branch information
aka-nse committed Dec 16, 2024
commit 740bdf6093b39737e73de3f3d0e277712ce9898c
18 changes: 18 additions & 0 deletions examples/GreeterByServiceDefinition/Client/Client.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Protobuf Include="..\Proto\greet.proto" GrpcServices="Client" Link="Protos\greet.proto" />

<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufPackageVersion)" />
<PackageReference Include="Grpc.Tools" Version="$(GrpcToolsPackageVersion)" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Grpc.Net.Client\Grpc.Net.Client.csproj" />
</ItemGroup>
</Project>
30 changes: 30 additions & 0 deletions examples/GreeterByServiceDefinition/Client/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#endregion

using Greet;
using Grpc.Net.Client;

using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);

var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
Console.WriteLine("Greeting: " + reply.Message);

Console.WriteLine("Shutting down");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
84 changes: 84 additions & 0 deletions examples/GreeterByServiceDefinition/GreeterByServiceDefinition.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33829.357
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{32B810EF-93B2-46C2-879A-BBA345A10E71}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core.Api", "..\..\src\Grpc.Core.Api\Grpc.Core.Api.csproj", "{BF8BD8C9-70D7-486F-BE4D-9ED2C7EA8CB1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Common", "..\..\src\Grpc.Net.Common\Grpc.Net.Common.csproj", "{912BCAE2-04D8-4FFE-B9A5-C7FAEA7EF808}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.ClientFactory", "..\..\src\Grpc.Net.ClientFactory\Grpc.Net.ClientFactory.csproj", "{3F49C6CE-D3AC-4609-B416-5E180DA59C7F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server.ClientFactory", "..\..\src\Grpc.AspNetCore.Server.ClientFactory\Grpc.AspNetCore.Server.ClientFactory.csproj", "{B38F8199-FD16-4E02-B1E2-CECEBF29A638}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore.Server", "..\..\src\Grpc.AspNetCore.Server\Grpc.AspNetCore.Server.csproj", "{5E857C51-76FF-4263-9BD7-CCB7997795F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.AspNetCore", "..\..\src\Grpc.AspNetCore\Grpc.AspNetCore.csproj", "{7D83B407-3C89-4671-BF97-A1B196633B0D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Net.Client", "..\..\src\Grpc.Net.Client\Grpc.Net.Client.csproj", "{CD4371A4-F789-4752-B1C0-DD95B1D6A090}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{534AC5F8-2DF2-40BD-87A5-B3D8310118C4}.Release|Any CPU.Build.0 = Release|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48A1D3BC-A14B-436A-8822-6DE2BEF8B747}.Release|Any CPU.Build.0 = Release|Any CPU
{BF8BD8C9-70D7-486F-BE4D-9ED2C7EA8CB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF8BD8C9-70D7-486F-BE4D-9ED2C7EA8CB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF8BD8C9-70D7-486F-BE4D-9ED2C7EA8CB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF8BD8C9-70D7-486F-BE4D-9ED2C7EA8CB1}.Release|Any CPU.Build.0 = Release|Any CPU
{912BCAE2-04D8-4FFE-B9A5-C7FAEA7EF808}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{912BCAE2-04D8-4FFE-B9A5-C7FAEA7EF808}.Debug|Any CPU.Build.0 = Debug|Any CPU
{912BCAE2-04D8-4FFE-B9A5-C7FAEA7EF808}.Release|Any CPU.ActiveCfg = Release|Any CPU
{912BCAE2-04D8-4FFE-B9A5-C7FAEA7EF808}.Release|Any CPU.Build.0 = Release|Any CPU
{3F49C6CE-D3AC-4609-B416-5E180DA59C7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F49C6CE-D3AC-4609-B416-5E180DA59C7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F49C6CE-D3AC-4609-B416-5E180DA59C7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F49C6CE-D3AC-4609-B416-5E180DA59C7F}.Release|Any CPU.Build.0 = Release|Any CPU
{B38F8199-FD16-4E02-B1E2-CECEBF29A638}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B38F8199-FD16-4E02-B1E2-CECEBF29A638}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B38F8199-FD16-4E02-B1E2-CECEBF29A638}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B38F8199-FD16-4E02-B1E2-CECEBF29A638}.Release|Any CPU.Build.0 = Release|Any CPU
{5E857C51-76FF-4263-9BD7-CCB7997795F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E857C51-76FF-4263-9BD7-CCB7997795F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E857C51-76FF-4263-9BD7-CCB7997795F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E857C51-76FF-4263-9BD7-CCB7997795F9}.Release|Any CPU.Build.0 = Release|Any CPU
{7D83B407-3C89-4671-BF97-A1B196633B0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D83B407-3C89-4671-BF97-A1B196633B0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D83B407-3C89-4671-BF97-A1B196633B0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D83B407-3C89-4671-BF97-A1B196633B0D}.Release|Any CPU.Build.0 = Release|Any CPU
{CD4371A4-F789-4752-B1C0-DD95B1D6A090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD4371A4-F789-4752-B1C0-DD95B1D6A090}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD4371A4-F789-4752-B1C0-DD95B1D6A090}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD4371A4-F789-4752-B1C0-DD95B1D6A090}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{BF8BD8C9-70D7-486F-BE4D-9ED2C7EA8CB1} = {32B810EF-93B2-46C2-879A-BBA345A10E71}
{912BCAE2-04D8-4FFE-B9A5-C7FAEA7EF808} = {32B810EF-93B2-46C2-879A-BBA345A10E71}
{3F49C6CE-D3AC-4609-B416-5E180DA59C7F} = {32B810EF-93B2-46C2-879A-BBA345A10E71}
{B38F8199-FD16-4E02-B1E2-CECEBF29A638} = {32B810EF-93B2-46C2-879A-BBA345A10E71}
{5E857C51-76FF-4263-9BD7-CCB7997795F9} = {32B810EF-93B2-46C2-879A-BBA345A10E71}
{7D83B407-3C89-4671-BF97-A1B196633B0D} = {32B810EF-93B2-46C2-879A-BBA345A10E71}
{CD4371A4-F789-4752-B1C0-DD95B1D6A090} = {32B810EF-93B2-46C2-879A-BBA345A10E71}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D22B3129-3BFB-41FA-9FCE-E45EBEF8C2DD}
EndGlobalSection
EndGlobal
33 changes: 33 additions & 0 deletions examples/GreeterByServiceDefinition/Proto/greet.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package greet;

// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}
36 changes: 36 additions & 0 deletions examples/GreeterByServiceDefinition/Server/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#endregion

using Grpc.Core;
using Server;
using Microsoft.AspNetCore.Builder;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();

var app = builder.Build();
app.MapGrpcService(getGreeterService);

app.Run();

static ServerServiceDefinition getGreeterService(IServiceProvider serviceProvider)
{
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var service = new GreeterService(loggerFactory);
return Greet.Greeter.BindService(service);
}
16 changes: 16 additions & 0 deletions examples/GreeterByServiceDefinition/Server/Server.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Protobuf Include="..\Proto\greet.proto" GrpcServices="Server" Link="Protos\greet.proto" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Grpc.AspNetCore\Grpc.AspNetCore.csproj" />
<ProjectReference Include="..\..\..\src\Grpc.AspNetCore.Server\Grpc.AspNetCore.Server.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#endregion

using System.Threading.Tasks;
using Greet;
using Grpc.Core;
using Microsoft.Extensions.Logging;

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

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

public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
_logger.LogInformation($"Sending hello to {request.Name}");
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Grpc": "Information",
"Microsoft": "Information"
}
}
}
13 changes: 13 additions & 0 deletions examples/GreeterByServiceDefinition/Server/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
}
}
10 changes: 10 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,13 @@ The error example shows how to use a richer error model with `Grpc.StatusProto`.
* Error handling
* Validation
* [`google.rpc.Status`](https://cloud.google.com/apis/design/errors#error_model)


## [GreeterByServiceDefinition](./GreeterByServiceDefinition)

This sample is similar with [Greeter](#greeter), but its service instance for server is mapped by using `ServerServiceDefinition`.

##### Scenarios:

* Mapping server service by using `ServerServiceDefinition`
* Unary call
38 changes: 38 additions & 0 deletions src/Grpc.AspNetCore.Server/GrpcEndpointRouteBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System.Diagnostics.CodeAnalysis;
using Grpc.AspNetCore.Server.Internal;
using Grpc.AspNetCore.Server.Model.Internal;
using Grpc.Core;
using Grpc.Shared;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -48,6 +49,43 @@ public static class GrpcEndpointRouteBuilderExtensions
return new GrpcServiceEndpointConventionBuilder(endpointConventionBuilders);
}

/// <summary>
/// Maps incoming requests to the specified <see cref="ServerServiceDefinition"/> instance.
/// </summary>
/// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
/// <param name="serviceDefinition">The instance of <see cref="ServerServiceDefinition"/>.</param>
/// <returns>A <see cref="GrpcServiceEndpointConventionBuilder"/> for endpoints associated with the service.</returns>
[RequiresUnreferencedCode("Due to type erasure in ServerServiceDefinition, MapGrpcService is incompatible with trimming.")]
public static GrpcServiceEndpointConventionBuilder MapGrpcService(this IEndpointRouteBuilder builder, ServerServiceDefinition serviceDefinition)
{
ArgumentNullException.ThrowIfNull(builder, nameof(builder));
ArgumentNullException.ThrowIfNull(serviceDefinition, nameof(serviceDefinition));

var serviceRouteBuilder = builder.ServiceProvider.GetRequiredService<ServiceRouteBuilder>();
var endpointConventionBuilders = serviceRouteBuilder.Build(builder, serviceDefinition);

return new GrpcServiceEndpointConventionBuilder(endpointConventionBuilders);
}

/// <summary>
/// Maps incoming requests to the <see cref="ServerServiceDefinition"/> instance from the specified factory.
/// </summary>
/// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
/// <param name="getServiceDefinition">The factory for <see cref="ServerServiceDefinition"/> instance.</param>
/// <returns>A <see cref="GrpcServiceEndpointConventionBuilder"/> for endpoints associated with the service.</returns>
[RequiresUnreferencedCode("Due to type erasure in ServerServiceDefinition, MapGrpcService is incompatible with trimming.")]
public static GrpcServiceEndpointConventionBuilder MapGrpcService(this IEndpointRouteBuilder builder, Func<IServiceProvider, ServerServiceDefinition> getServiceDefinition)
{
ArgumentNullException.ThrowIfNull(builder, nameof(builder));
ArgumentNullException.ThrowIfNull(getServiceDefinition, nameof(getServiceDefinition));

var serviceDefinition = getServiceDefinition(builder.ServiceProvider);
var serviceRouteBuilder = builder.ServiceProvider.GetRequiredService<ServiceRouteBuilder>();
var endpointConventionBuilders = serviceRouteBuilder.Build(builder, serviceDefinition);

return new GrpcServiceEndpointConventionBuilder(endpointConventionBuilders);
}

private static void ValidateServicesRegistered(IServiceProvider serviceProvider)
{
var marker = serviceProvider.GetService(typeof(GrpcMarkerService));
Expand Down
2 changes: 2 additions & 0 deletions src/Grpc.AspNetCore.Server/GrpcServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ public static IGrpcServerBuilder AddGrpc(this IServiceCollection services)
#endif
services.AddOptions();
services.TryAddSingleton<GrpcMarkerService>();
services.TryAddSingleton(typeof(ServerCallHandlerFactory));
services.TryAddSingleton(typeof(ServerCallHandlerFactory<>));
services.TryAddSingleton(typeof(IGrpcServiceActivator<>), typeof(DefaultGrpcServiceActivator<>));
services.TryAddSingleton(typeof(IGrpcInterceptorActivator<>), typeof(DefaultGrpcInterceptorActivator<>));
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<GrpcServiceOptions>, GrpcServiceOptionsSetup>());

// Model
services.TryAddSingleton<ServiceMethodsRegistry>();
services.TryAddSingleton(typeof(ServiceRouteBuilder));
services.TryAddSingleton(typeof(ServiceRouteBuilder<>));
services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IServiceMethodProvider<>), typeof(BinderServiceMethodProvider<>)));

Expand Down
Loading