IndependentReserve.Grpc.Tools
4.0.194
See the version list below for details.
dotnet add package IndependentReserve.Grpc.Tools --version 4.0.194
NuGet\Install-Package IndependentReserve.Grpc.Tools -Version 4.0.194
<PackageReference Include="IndependentReserve.Grpc.Tools" Version="4.0.194"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add IndependentReserve.Grpc.Tools --version 4.0.194
#r "nuget: IndependentReserve.Grpc.Tools, 4.0.194"
// Install IndependentReserve.Grpc.Tools as a Cake Addin #addin nuget:?package=IndependentReserve.Grpc.Tools&version=4.0.194 // Install IndependentReserve.Grpc.Tools as a Cake Tool #tool nuget:?package=IndependentReserve.Grpc.Tools&version=4.0.194
IndependentReserve.Grpc.Tools
Purpose
This package contains MSBuild tasks and targets for automatic generation of gRPC/Protobuf code from plain C# interface(s).
How it works
When this package is referenced by a project it adds itself into compilation pipeline in the following way:
For every depended project which is marked by GenerateGrpc
attribute it loads all eligible C# interfaces and for every such source interface it generates the following code:
- a set of
*.proto
files defining gRPC service and messages plus the hierarchy of all DTO classes referenced by the source interface; - a set of C#
partial
classes which provideimplicit
conversion operators forProtobuf ↔ DTO
conversion for every generated*.proto
file; - gRPC service implementation which depends on source interface and internally calls this interface for corresponding interface method implementation;
- gRPC client class which implements the source interface by calling gRPC server via gRPC.
How to use it
To generate all required gRPC/Protobuf code in a project you need to point the package to a separate project which contains interface (or interfaces) which you want to generate gRPC/Protobuf types for. To do that simply add GenerateGrpc="true"
attribute to ProjectReference
element of the relevant source project, e.g.:
<ItemGroup>
<ProjectReference Include="..\Service.Interface.csproj" GenerateGrpc="true" />
</ItemGroup>
By default the tool searches for all public interfaces which names match Service$
regular expression (e.g. ISomeService
) and generates all required gRPC-related code for every found interface.
To use a different pattern for interface search specify a custom regular expression (.NET flavor) via GrpcServicePattern
attribute, e.g.:
<ItemGroup>
<ProjectReference Include="..\Service.Interface.csproj" >
<GenerateGrpc>true</GenerateGrpc>
<GrpcServicePattern>I[^.]*ServiceInterface$</GrpcServicePattern>
</ProjectReference>
</ItemGroup>
Note: the source interfaces must be in a separate dependent project because the tool uses reflection to load and process source interfaces during the build.
All generated files are placed in obj/[Configuration]/[TargetFramework]/Grpc
root folder and are automatically included into project's build.
All *.proto
files are placed in Protos
subfolder:
[service-name].proto
file: gRPC service definition file which defines all methods mirroring source interface methods;[service-name]/Messages/*.proto
files: these files contain all*Request
and*Response
messages referenced from[service-name].proto
file;[class-name].proto
files: a hierarchy of messages which are referenced (directly or indirectly) by messages from[service-name]Messages.proto
.
All *.cs
files are placed in Partials
subfolder:
[service-name]GrpcService.cs
: gRPC service class:
This class depends on the source interface and it is expected that the implementation of this interface passed to gRPC service class constructor (e.g. via dependency injection) contains the internal implementation of the service logic;[service-name]GrpcClient.cs
: gRPC client implementation:
This class implements source interface by calling the service via gRPC (using internal gRPC client class in turn generated by Grpc.Tools). For each method from source interface both synchronous and asynchronous methods are generated.[class-name].cs
files: a set ofpartial
C# classes which addimplicit
conversion operators (Protobuf ↔ DTO
) to generated byGrpc.Tools
C# classes.
There is one to one correspondence between this set and[class-name].proto
files set.
From the above set of files normally only C# code is relevant to the user of this package. The Protobuf code can be considered internal. In practice developer only needs to know about two classes:
- gRPC service: to host the service in ASP.NET;
- gRPC client: to call the service.
Both classes either depend or implement the source interface while all boilerplate conversion to/from Protobuf messages is handled by AutoMapper framework.
.NET to Protobuf conversion rules
- Every public method of source interface is converted to gRPC service method;
- Every .NET type which is referenced by any convertible source interface method directly or transitively is converted to Protobuf message using the following approach:
- Any well-known built-in type, i.e. a type which has direct corresponding Protobuf type (e.g.
Boolean
,Int32
,String
, etc.) or one of built-in .NET-specific types from IndependentReserve.Grpc package (e.g.:Decimal
,Guid
,DateTime
etc.) is directly convertible; - A collection (i.e. a type which implements
IEnumerable<>
interface, includingIDictionary<,>
) or a single-dimensional array (including jagged arrays) with elements of convertible type are convertible; - Enums are convertible (but see note below);
- For any other .NET type a custom Protobuf message is generated using all public fields and properties of convertible types;
- Any .NET entity which is not convertible (i.e. which is ignored or is not currently supported) is omitted during Protobuf code generation (with detailed MSBuild warning issued in build log). Such ignored entity will be absent in Protobuf code and will most likely always have
default
value in source type.
- Any well-known built-in type, i.e. a type which has direct corresponding Protobuf type (e.g.
Ignored .NET entities
The following .NET entities are ignored (i.e. they are not convertible):
- Open generic source interfaces;
- Interfaces and abstract classes (except for classes and interfaces which implement
IEnumerable<>
interface); - Any type which is not built-in and does not have any convertible public fields or properties.
Currently not supported .NET entities
The following .NET entities are not currently supported (i.e. they are currently not convertible) but they might be supported in future versions:
- Nested .NET types;
- Multidimensional arrays;
- Enums with underlying type smaller than
Int32
; ref
andout
source interface method parameters;- Source interface properties;
- Source interface open generic methods without default implementation;
- Source interface events;
Nullable annotations
The tool takes into account nullable annotations when they are available. Generally not-nullable arguments and type members produce more efficient Protobuf code. This is especially noticiable in collections, e.g. serialisation of a property of type string[]
(i.e. an array of non-nullable string
) is several times faster than serialisation of a similar property but of type string?[]
(i.e. an array which can contain null
elements).
gRPC Streaming
Generated code use gRPC streaming to handle return type of a method or a single argument of a method of type IEnumerable<>
or IAsyncEnumerable<>
.
Example of generated C# code
If we pass the following source interface to the tool:
public interface ITestService
{
int Plus(int a, int b);
}
it will generate the following gRPC service class:
public partial class TestServiceGrpcService : TestServiceBase
{
private readonly ILogger<TestServiceGrpcService> _logger;
private readonly ITestService _testService;
public TestServiceGrpcService(
ILogger<TestServiceGrpcService> logger,
ITestService testService)
{
_logger = logger;
_testService = testService;
}
public override async Task<PlusResponse> Plus(PlusRequest request, ServerCallContext context)
{
var args = MapperTo<ValueTuple<System.Int32, System.Int32>>.MapFrom(new { Item1 = request.A, Item2 = request.B });
var result = _testService.Plus(args.Item1, args.Item2);
return MapperTo<PlusResponse>.MapFrom(new { Result = result });
}
}
along with the following gRPC client class:
public partial class TestServiceGrpcClient : GrpcClient, ITestService
{
private readonly Lazy<TestServiceClient> _client;
public TestServiceGrpcClient(IGrpcServiceConfiguration config, bool useGrpcWeb = true)
: base(config, useGrpcWeb)
{
var invoker = Channel.CreateCallInvoker();
SetupCallInvoker(ref invoker);
_client = new(() => new(invoker));
}
partial void SetupCallInvoker(ref CallInvoker invoker);
private TestServiceClient Client => _client.Value;
public System.Int32 Plus(System.Int32 a, System.Int32 b)
{
var response = Client.Plus(MapperTo<PlusRequest>.MapFrom(new { A = a, B = b }));
return MapperTo<Wrapper<System.Int32>>.MapFrom(response).Result;
}
public async Task<System.Int32> PlusAsync(System.Int32 a, System.Int32 b)
{
var response = await Client.PlusAsync(MapperTo<PlusRequest>.MapFrom(new { A = a, B = b }));
return MapperTo<Wrapper<System.Int32>>.MapFrom(response).Result;
}
}
DTO ↔ Protobuf conversion code test generation
This tool can also generate unit tests for DTO → gRPC → byte[] → gRPC → DTO
(round-trip) conversion/serialization path which check that after conversion/serialization the source DTO content is matched by the resulting DTO content.
To add test generation step to a project add GenerateGrpcTests="true"
attribute to the ProjectReference
to the source interface project, e.g.:
<ItemGroup>
<ProjectReference Include="..\Service.Interface.csproj" GenerateGrpcTests="true" />
</ItemGroup>
The tool then generates unit tests for every DTO referenced by the source interface. It uses xUnit since this test framework allows test input being provided by an external class via ClassData attribute. Every test is run against generated test data (random DTO content). By default it generates 1000
random DTO instances in every test. This limit can be controlled by setting Arbitrary.TestCount
property, e.g.:
public partial class TestServiceConversionTests
{
static TestServiceConversionTests()
{
Arbitrary.TestCount = 10000;
}
}
Note: GenerateGrpcTests="true"
does not generate source Protobuf code (only tests) since normally unit tests are placed in a separate project which references a project which contains generated (via GenerateGrpc="true"
) Protobuf code. If you require both code and the tests to be generated in the same project add both GenerateGrpc
and GenerateGrpcTests
attributes to relevant ProjectReference
.
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Grpc.Tools (>= 2.52.0)
- IndependentReserve.Grpc (>= 4.0.194)
-
.NETStandard 2.1
- Grpc.Tools (>= 2.52.0)
- IndependentReserve.Grpc (>= 4.0.194)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
4.3.253 | 2,760 | 8/13/2024 |
4.2.221 | 138 | 7/11/2024 |
4.2.219 | 5,472 | 7/6/2024 |
4.1.215 | 17,458 | 12/15/2023 |
4.1.210 | 1,093 | 11/30/2023 |
4.0.201 | 954 | 11/21/2023 |
4.0.194 | 884 | 11/17/2023 |
4.0.189 | 2,973 | 11/9/2023 |
4.0.186 | 783 | 11/8/2023 |
4.0.185 | 812 | 11/8/2023 |
3.2.149 | 2,814 | 8/15/2023 |
3.2.146 | 904 | 8/11/2023 |
3.1.145 | 5,880 | 4/28/2023 |
3.1.143 | 1,214 | 4/4/2023 |
3.1.140 | 1,076 | 3/29/2023 |
3.1.138 | 1,230 | 3/29/2023 |
3.1.136 | 1,307 | 3/21/2023 |
3.1.134 | 1,243 | 3/21/2023 |
3.1.132 | 1,240 | 3/19/2023 |
3.1.130 | 1,121 | 3/16/2023 |
2.3.124 | 1,110 | 3/13/2023 |
2.2.119 | 1,397 | 3/8/2023 |
2.2.115 | 1,873 | 3/5/2023 |
2.2.114 | 1,283 | 3/5/2023 |
2.1.108 | 1,264 | 3/3/2023 |
1.9.116 | 1,253 | 3/5/2023 |
1.9.106 | 1,470 | 3/3/2023 |
1.9.104 | 1,366 | 3/2/2023 |
1.8.94 | 1,487 | 2/27/2023 |
1.7.88 | 1,227 | 2/27/2023 |
1.7.86 | 1,064 | 2/27/2023 |
1.6.81 | 1,892 | 2/2/2023 |
1.5.77 | 1,487 | 1/26/2023 |
1.4.69 | 1,592 | 1/9/2023 |
1.4.61 | 1,457 | 1/3/2023 |
1.3.52 | 1,981 | 12/16/2022 |
1.3.48 | 1,367 | 12/15/2022 |
1.2.42 | 1,886 | 12/14/2022 |
1.2.36 | 1,574 | 11/29/2022 |
1.2.33 | 1,696 | 11/28/2022 |