Skip to content

Commit

Permalink
add initial docs for Stream API
Browse files Browse the repository at this point in the history
  • Loading branch information
mgravell committed Oct 14, 2024
1 parent 1416650 commit e188b98
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 11 deletions.
4 changes: 2 additions & 2 deletions Build.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.Build.Traversal/2.0.19">
<ItemGroup>
<ProjectReference Include="src\**\*.csproj" Exclude="examples\**\*.csproj" />
<ProjectReference Include="src\**\*.csproj" Exclude="examples\**\*.csproj;docs\**\*.csproj" />
</ItemGroup>
<ItemGroup Condition="$(Packing) != 'true'">
<ProjectReference Include="**\*.csproj" Exclude="examples\**\*.csproj" />
<ProjectReference Include="**\*.csproj" Exclude="examples\**\*.csproj;docs\**\*.csproj" />
</ItemGroup>
</Project>
6 changes: 6 additions & 0 deletions docs/docs.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- this file exists only to make it easy to work with the folder in devenv -->
<TargetFramework>$(DefaultTFM)</TargetFramework>
</PropertyGroup>
</Project>
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- [Build Tools ("contract-first" focus)](https://protobuf-net.github.io/protobuf-net/contract_first)
- [Create Proto File](createProtoFile)
- [Register Client Service in Startup.cs](registerClientService)
- [.NET Streams](streams)

Other Content

Expand Down
48 changes: 48 additions & 0 deletions docs/streams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Streams

gRPC has a `stream` concept that allows client-streaming, server-streaming, and full-duplex (independent bidirectional) streaming of messages. Inside
protobuf-net.Grpc, this is typically exposed via the `IAsyncEnumerable<T>` API, which is an asynchronous sequence of messages of type `T`. For example,

```
public async IAsyncEnumerable<SomeResponse> SomeDuplexMethod(IAsyncEnumerable<SomeRequest> requests)
{
// very basic request/response server using streaming
await foreach (var req in requests)
{
yield return ApplySomeTransformation(req);
}
}
```

This is *fine*, but .NET has another "stream", i.e. `System.IO.Stream` - a sequence of *bytes*.

As of 1.2.2, protobuf-net.Grpc has limited (and growing) support for `Stream` as an exchange mechanism. Currently supported scenarios:

- `Task<Stream> SomeMethod(/* optional single request message, optional context/cancellation */);`
- `ValueTask<Stream> SomeMethod(/* optional single request message, optional context/cancellation */);`

For example:

``` c#
public async Task<Stream> GetFileContents(SomeRequest request)
{
var localPath = await CheckAccessAndMapToLocalPath(request.Path);

return File.OpenRead(localPath);
}
```

This hands a `Stream` back to the library, with the library assuming control of how to transmit that, disposing the stream when done (as an implementation detail: it
is sent as a `stream` of [`BytesValue`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/wrappers.proto) messages,
with bespoke marshalling). As you would expect, the client can access this data trivially:

``` c#
await using var data = proxy.GetFileContents(request);
await using var localFile = File.Create(localCachePath);
await data.CopyToAsync(localFile);
```

---

These are just trivial examples; more complex scenarios are possible, for example using `Pipe` on the server to allow the worker to provide
data after the initial response (this will be more direct when the supported APIs are extended to include pipes directly).
19 changes: 10 additions & 9 deletions protobuf-net.Grpc.sln
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{8D5FDB6F-6111-4604-8EDF-6A59F8B12D7E}"
ProjectSection(SolutionItems) = preProject
appveyor.yml = appveyor.yml
Build.csproj = Build.csproj
Directory.build.props = Directory.build.props
Directory.Build.targets = Directory.Build.targets
Directory.Packages.props = Directory.Packages.props
Expand Down Expand Up @@ -71,15 +72,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "managed", "managed", "{3949
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "native", "native", "{BE48D1A2-CE10-4AEE-B370-ED8E373B082B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{6065C30D-7C5D-4C54-97B4-F407B56C7A89}"
ProjectSection(SolutionItems) = preProject
docs\configuration.md = docs\configuration.md
docs\gettingstarted.md = docs\gettingstarted.md
docs\index.md = docs\index.md
docs\projects.md = docs\projects.md
docs\releasenotes.md = docs\releasenotes.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "examples\grpc\Client\Client.csproj", "{301A0DD5-0300-4B6B-BEE7-65DB6604DD2F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "examples\grpc\Server\Server.csproj", "{A5D8E4BD-7204-4CF7-A323-F2F5A44659D9}"
Expand Down Expand Up @@ -149,6 +141,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TraderSys.Portfolios.Client
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TraderSys.Portfolios.Shared", "examples\wcf-port\TraderSys\src\TraderSys.Portfolios.Shared\TraderSys.Portfolios.Shared.csproj", "{80479131-FE55-473E-AE68-55601AD96668}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "docs", "docs\docs.csproj", "{9479D65D-A0E8-4520-99EC-93774A217EF6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -402,6 +396,12 @@ Global
{80479131-FE55-473E-AE68-55601AD96668}.Release|Any CPU.Build.0 = Release|Any CPU
{80479131-FE55-473E-AE68-55601AD96668}.VS|Any CPU.ActiveCfg = Debug|Any CPU
{80479131-FE55-473E-AE68-55601AD96668}.VS|Any CPU.Build.0 = Debug|Any CPU
{9479D65D-A0E8-4520-99EC-93774A217EF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9479D65D-A0E8-4520-99EC-93774A217EF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9479D65D-A0E8-4520-99EC-93774A217EF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9479D65D-A0E8-4520-99EC-93774A217EF6}.Release|Any CPU.Build.0 = Release|Any CPU
{9479D65D-A0E8-4520-99EC-93774A217EF6}.VS|Any CPU.ActiveCfg = Debug|Any CPU
{9479D65D-A0E8-4520-99EC-93774A217EF6}.VS|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -462,6 +462,7 @@ Global
{87D27844-3A62-431A-9B53-92AFC09A1C3C} = {2B3F5AED-24B3-4915-900E-EFC58414EA29}
{AC65761B-5CF5-4F3E-AF60-41F977E8070D} = {2B3F5AED-24B3-4915-900E-EFC58414EA29}
{80479131-FE55-473E-AE68-55601AD96668} = {2B3F5AED-24B3-4915-900E-EFC58414EA29}
{9479D65D-A0E8-4520-99EC-93774A217EF6} = {8D5FDB6F-6111-4604-8EDF-6A59F8B12D7E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BA14B07C-CA29-430D-A600-F37A050636D3}
Expand Down

0 comments on commit e188b98

Please sign in to comment.