protected virtual RpcMultiPartResponse MultiPartMessage(RpcMultiPartRequest request, ExtensionRegistry registry) { RpcSession session = RpcCallContext.Session; string messageId = request.TransactionId.ToBase64(); Stream message; if (!session.TryGetValue(messageId, out message)) { if (request.CurrentPosition != 0) { throw new InvalidDataException("The TransactionId is not valid."); } session.Add(messageId, message = CreateStream(request.TotalBytes)); message.SetLength(request.TotalBytes); } if (request.MessageStatus == RpcMultiPartRequest.Types.RpcMessageStatus.CANCEL) { message.Dispose(); session.Remove(messageId); return(RpcMultiPartResponse.CreateBuilder().SetContinue(false).Build()); } if (message.Position != request.CurrentPosition || message.Length != request.TotalBytes || request.BytesSent != request.PayloadBytes.Length) { throw new InvalidDataException(); } request.PayloadBytes.WriteTo(message); if (request.MessageStatus == RpcMultiPartRequest.Types.RpcMessageStatus.COMPLETE) { using (message) { session.Remove(messageId); if (message.Position != request.TotalBytes) { throw new InvalidDataException(); } message.Position = 0; byte[] response = next.CallMethod(request.MethodName, CodedInputStream.CreateInstance(message), registry). ToByteArray(); return(RpcMultiPartResponse.CreateBuilder() .SetResponseBytes(ByteString.CopyFrom(response)) .SetContinue(true) .Build()); } } return(RpcMultiPartResponse.CreateBuilder() .SetContinue(true) .Build()); }
public void MultiPartMessageCancel() { //Notice that both client and server must enable multi-part messages... using (RpcServer.CreateRpc(iid, new SearchService.ServerStub(new AuthenticatedSearch())) .AddAuthNegotiate() .AddProtocol("ncacn_ip_tcp", "12345") .EnableMultiPart() .StartListening()) { ByteString transaction = ByteString.CopyFrom(Guid.NewGuid().ToByteArray()); using ( RpcClient client = RpcClient.ConnectRpc(iid, "ncacn_ip_tcp", "::1", "12345").Authenticate( RpcAuthenticationType.Self)) { RpcMultiPartResponse response = client.CallMethod(".multi", RpcMultiPartRequest.CreateBuilder() .SetTransactionId(transaction) .SetMessageStatus( RpcMultiPartRequest.Types.RpcMessageStatus .CONTINUE) .SetMethodName("Whatever") .SetCurrentPosition(0) .SetBytesSent(1000) .SetTotalBytes(2000) .SetPayloadBytes( ByteString.CopyFrom(new byte[1000])) .Build(), RpcMultiPartResponse.CreateBuilder()); Assert.IsTrue(response.Continue); response = client.CallMethod(".multi", RpcMultiPartRequest.CreateBuilder() .SetTransactionId(transaction) .SetMessageStatus(RpcMultiPartRequest.Types.RpcMessageStatus.CANCEL) .Build(), RpcMultiPartResponse.CreateBuilder()); Assert.IsFalse(response.Continue); } } }
TMessage IRpcDispatch.CallMethod <TMessage, TBuilder>(string method, IMessageLite request, IBuilderLite <TMessage, TBuilder> response) { int size = request.SerializedSize; if (size < multiPartThreshold) { return(next.CallMethod(method, request, response)); } else { ByteString transaction = ByteString.CopyFrom(Guid.NewGuid().ToByteArray()); byte[] requestBytes = request.ToByteArray(); RpcMultiPartRequest.Types.RpcMessageStatus status = RpcMultiPartRequest.Types.RpcMessageStatus.CONTINUE; try { int total = requestBytes.Length; int amt = multiPartThreshold - 1024; //reserved for header RpcMultiPartResponse mpr = RpcMultiPartResponse.DefaultInstance; for (int pos = 0; pos < total; pos += amt) { amt = Math.Min(amt, total - pos); status = (pos + amt) < total ? status : RpcMultiPartRequest.Types.RpcMessageStatus.COMPLETE; mpr = next.CallMethod(".multi", RpcMultiPartRequest.CreateBuilder() .SetTransactionId(transaction) .SetMethodName(method) .SetMessageStatus(status) .SetCurrentPosition(pos) .SetTotalBytes(total) .SetBytesSent(amt) .SetPayloadBytes(ByteString.CopyFrom(requestBytes, pos, amt)) .Build(), RpcMultiPartResponse.CreateBuilder() ); if (!mpr.Continue) { throw new InvalidDataException("The operation was canceled by the server."); } } if (!mpr.HasResponseBytes) { throw new InvalidDataException("The server did not provide a response."); } return(response.MergeFrom(mpr.ResponseBytes.ToByteArray(), extensions).Build()); } catch { if (status == RpcMultiPartRequest.Types.RpcMessageStatus.CONTINUE) { try { next.CallMethod(".multi", RpcMultiPartRequest.CreateBuilder() .SetTransactionId(transaction) .SetMessageStatus(RpcMultiPartRequest.Types.RpcMessageStatus.CANCEL) .Build(), RpcVoid.CreateBuilder() ); } catch (Exception e) { Trace.TraceWarning("Unable to cancel multi-part message: {0}, error = {1}", transaction, e); } } throw; } } }