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

Server and Duplex streaming out parameters alternative #18

Closed
max-ieremenko opened this issue Dec 26, 2020 · 1 comment
Closed

Server and Duplex streaming out parameters alternative #18

max-ieremenko opened this issue Dec 26, 2020 · 1 comment
Labels
enhancement New feature or request
Milestone

Comments

@max-ieremenko
Copy link
Owner

max-ieremenko commented Dec 26, 2020

Problem

gRPC protocol is message oriented and in server streaming calls does not allow to pass back to a caller external information.
The only way to achieve this is by using response headers.

As an example file download from server. Together with content i need also file creation date, owner information and file version:

[OperationContract]
Task<IAsyncEnumerable<byte[]>> DownloadFile(string fileName, CallContext context);

// server-side implementation
async Task<IAsyncEnumerable<byte[]>> DownloadFile(string fileName, CallContext context)
{
    DateTime fileCreationDate = ... // resolve file creation date
    string fileOwner = ... // resolve owner information
    string fileVersion = ... // resolve file version

    // pass external information in response headers
    ServerCallContext serverContext = context;
    await serverContext.WriteResponseHeadersAsync(new Metadata
    {
        { "creation-date", fileCreationDate.ToString() },
        { "owner", fileOwner },
        { "version", fileVersion  }
    });

    // pass file content via server streaming
    return ReadFileContent(fileName);
}
private IAsyncEnumerable<byte[]> ReadFileContent(string fileName)
{
    // convert file content to gRPC byte[] stream
    // the code is for demonstration purposes only !!!
    using (var stream = File.OpenRead(fileName))
    {
        var buffer = new byte[4 * 1204];
        while ((await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            yield return buffer;
        }
    }
}

// client-side implementation
var context = new CallContext();
var content = await DownloadFile("file name", context);

// extract external information from response headers
var fileCreationDate = context.ResponseHeaders.First(i => i.Key == "creation-date").Value;
var fileOwner = context.ResponseHeaders.First(i => i.Key == "owner").Value;
var fileVersion = context.ResponseHeaders.First(i => i.Key == "version").Value;

// download file content
await foreach(var buffer in content)
{
    // ...
}

Idea

The idea is to move "response headers" related implementation into ServiceModel.Grpc framework:

// no CallContext in the call, only CancellationToken
// pass external information in the method return type
[OperationContract]
Task<(DateTime CreationDate, string Owner, string Version, IAsyncEnumerable<byte[]> Content)> DownloadFile(string fileName, CancellationToken token);

// server-side implementation
async Task<(DateTime, string, string, IAsyncEnumerable<byte[]>)> DownloadFile(string fileName, CancellationToken token)
{
    DateTime fileCreationDate = ... // resolve file creation date
    string fileOwner = ... // resolve owner information
    string fileVersion = ... // resolve file version

    return (fileCreationDate, fileOwner, version, ReadFileContent(fileName));
}

// client-side implementation
var (fileCreationDate, fileOwner, fileVersion, content) = await DownloadFile("file name", CancellationToken);

// download file content
await foreach(var buffer in content)
{
    // ...
}
@max-ieremenko max-ieremenko added the enhancement New feature or request label Dec 26, 2020
@max-ieremenko max-ieremenko added this to the 1.1.7 milestone Dec 26, 2020
max-ieremenko added a commit that referenced this issue Jan 3, 2021
max-ieremenko added a commit that referenced this issue Jan 3, 2021
@max-ieremenko
Copy link
Owner Author

released in version 1.1.7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant