【问题标题】:gRPC C#: how to cancel upload correctlygRPC C#:如何正确取消上传
【发布时间】:2020-04-14 13:30:56
【问题描述】:

为了将图像从客户端上传到服务器,我使用了分块。

这是客户端代码:

private async Task UploadPersonImage(int personId, string fileName, CancellationToken cancellationToken)
{
    var stream = Client.UploadPersonImage();
    PersonImageMessage personImageMessage = new PersonImageMessage();
    personImageMessage.PersonId = personId;
    personImageMessage.ImageType = ImageType.Jpg;
    byte[] image = File.ReadAllBytes(fileName);
    int imageOffset = 0;
    byte[] imageChunk = new byte[imageChunkSize];
    while (imageOffset < image.Length && !cancellationToken.IsCancellationRequested)
    {
        int length = Math.Min(imageChunkSize, image.Length - imageOffset);
        Buffer.BlockCopy(image, imageOffset, imageChunk, 0, length);
        imageOffset += length;
        ByteString byteString = ByteString.CopyFrom(imageChunk);
        personImageMessage.ImageChunk = byteString;
        await stream.RequestStream.WriteAsync(personImageMessage).ConfigureAwait(false);
    }
    await stream.RequestStream.CompleteAsync().ConfigureAwait(false);
    if (!cancellationToken.IsCancellationRequested)
    {
        var uploadPersonImageResult = await stream.ResponseAsync.ConfigureAwait(false);
        // Process answer...
    }
}

这是服务器代码:

public override async Task<TransferStatusMessage> UploadPersonImage(
    IAsyncStreamReader<PersonImageMessage> requestStream, ServerCallContext context)
{
    TransferStatusMessage transferStatusMessage = new TransferStatusMessage();
    transferStatusMessage.Status = TransferStatus.Success;
    try
    {
        await Task.Run(
            async () =>
            {
                CancellationToken cancellationToken = context.CancellationToken;
                await using (Stream fs = File.OpenWrite(ImageFileName))
                {
                    await foreach (PersonImageMessage personImageMessage in
                        requestStream.ReadAllAsync(cancellationToken).ConfigureAwait(false))
                    {
                        fs.Write(personImageMessage.ImageChunk.ToByteArray());
                    }
                }
            }).ConfigureAwait(false);
    }
    // Is thrown on cancellation -> ignore...
    catch (OperationCanceledException)
    {
        transferStatusMessage.Status = TransferStatus.Cancelled;
    }
    catch (RpcException rpcEx)
    {
        if (rpcEx.StatusCode == StatusCode.Cancelled)
        {
            transferStatusMessage.Status = TransferStatus.Cancelled;
        }
        else
        {
            _logger.LogError($"Exception while processing image file '{ImageFileName}'. Exception: '{requestStream}'");
            transferStatusMessage.Status = TransferStatus.Failure;
        }
    }
    // Delete incomplete file
    if (transferStatusMessage.Status != TransferStatus.Success)
    {
        File.Delete(ImageFileName);
    }
    return transferStatusMessage;
}

一切正常。我想在发送块之间取消上传。现在,调用 CompleteAsync() 并且服务器认为数据传输成功结束。我正在寻找一种方法来通过客户端触发服务器中的取消(即 ServerCallContext 中的 CancellationToken)。 作为一种解决方法,我可以向 PersonImageMes​​sage 添加一个标志,例如“upload_cancelled”,以告诉服务器传输已中止。但必须有一个内置的机制。

有人知道诀窍吗?

【问题讨论】:

    标签: c# grpc cancellation


    【解决方案1】:

    您可以将cancellationToken 传递给您的客户端流 RPC 方法。然后服务器可以将其接收为context.cancellationToken

    var stream = Client.UploadPersonImage(cancellationToken: cancellationToken);
    

    如果客户端取消,则不应调用stream.RequestStream.CompleteAsync()

    【讨论】:

      猜你喜欢
      • 2013-10-18
      • 2023-03-23
      • 1970-01-01
      • 2021-03-25
      • 1970-01-01
      • 1970-01-01
      • 2020-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多