コード例 #1
0
    public async Task ServerHasNoLeakWhenRequestIsRejected()
    {
        Task <MultiplexingStream.Channel> clientRpcChannelTask = this.clientMx.OfferChannelAsync("custom", this.TimeoutToken);
        Task <MultiplexingStream.Channel> serverRpcChannelTask = this.serverMx.AcceptChannelAsync("custom", this.TimeoutToken);

        MultiplexingStream.Channel clientRpcChannel = await clientRpcChannelTask;
        MultiplexingStream.Channel serverRpcChannel = await serverRpcChannelTask;

        this.serverRpc = new JsonRpc(new HeaderDelimitedMessageHandler(serverRpcChannel, new JsonMessageFormatter {
            MultiplexingStream = this.serverMx
        }), new ServerWithOverloads());
        this.serverRpc.StartListening();

        // Send a message, advertising a channel.
        // We *deliberately* avoid using the JsonRpc on the client side and send arguments that will cause no good match on the server
        // so as to exercise and verify the path where the server sends an error back to the client, after trying to open the channel, but without invoking the server method,
        // and without the client having a chance to close the channel before we can verify that the server did.
        MultiplexingStream.Channel oobChannel = this.clientMx.CreateChannel();
        var clientHandler = new HeaderDelimitedMessageHandler(clientRpcChannel, new JsonMessageFormatter());
        await clientHandler.WriteAsync(
            new StreamJsonRpc.Protocol.JsonRpcRequest
        {
            Id            = 1,
            Method        = nameof(ServerWithOverloads.OverloadedMethod),
            ArgumentsList = new object[] { false, oobChannel.Id, new object() },
        },
            this.TimeoutToken);

        await clientRpcChannel.Output.FlushAsync(this.TimeoutToken);

        // Wait for the client to receive the error message back, but don't let any of our client code handle it.
        ReadResult readResult = await clientRpcChannel.Input.ReadAsync(this.TimeoutToken);

        clientRpcChannel.Input.AdvanceTo(readResult.Buffer.Start);

        // The test intends to exercise that the server actually accepts (or perhaps rejects) the channel.
        await oobChannel.Acceptance.WithCancellation(this.TimeoutToken);

        // Assuming it has accepted it, we want to verify that the server closes the channel.
        await oobChannel.Completion.WithCancellation(this.TimeoutToken);
    }
コード例 #2
0
        public ulong?GetULongToken(IDuplexPipe?duplexPipe)
        {
            Verify.NotDisposed(this);

            MultiplexingStream mxstream = this.GetMultiplexingStreamOrThrow();

            if (this.formatterState.SerializingMessageWithId.IsEmpty)
            {
                duplexPipe?.Output.Complete();
                duplexPipe?.Input.Complete();

                throw new NotSupportedException(Resources.MarshaledObjectInNotificationError);
            }

            if (duplexPipe is null)
            {
                return(null);
            }

            MultiplexingStream.Channel channel = mxstream.CreateChannel(new MultiplexingStream.ChannelOptions {
                ExistingPipe = duplexPipe
            });

            if (!this.RequestIdBeingSerialized.IsEmpty)
            {
                ImmutableInterlocked.AddOrUpdate(
                    ref this.outboundRequestChannelMap,
                    this.RequestIdBeingSerialized,
                    ImmutableList.Create(channel),
                    (key, value) => value.Add(channel));
            }

            // Track open channels to assist in diagnosing abandoned channels.
            ImmutableInterlocked.TryAdd(ref this.openOutboundChannels, channel.QualifiedId, channel);
            channel.Completion.ContinueWith(_ => ImmutableInterlocked.TryRemove(ref this.openOutboundChannels, channel.QualifiedId, out MultiplexingStream.Channel? removedChannel), CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default).Forget();

            return(channel.QualifiedId.Id);
        }
コード例 #3
0
    public async Task InitializeAsync()
    {
        Tuple <Nerdbank.FullDuplexStream, Nerdbank.FullDuplexStream> streams = Nerdbank.FullDuplexStream.CreateStreams();

        TraceSource mxServerTraceSource = new TraceSource("MX Server", SourceLevels.Information);
        TraceSource mxClientTraceSource = new TraceSource("MX Client", SourceLevels.Information);

        mxServerTraceSource.Listeners.Add(new XunitTraceListener(this.Logger));
        mxClientTraceSource.Listeners.Add(new XunitTraceListener(this.Logger));

        MultiplexingStream[] mxStreams = await Task.WhenAll(
            MultiplexingStream.CreateAsync(
                streams.Item1,
                new MultiplexingStream.Options
        {
            TraceSource = mxServerTraceSource,
            DefaultChannelTraceSourceFactory = (id, name) => new TraceSource("MX Server channel " + id, SourceLevels.Verbose)
            {
                Listeners = { new XunitTraceListener(this.Logger) }
            },
        },
                this.TimeoutToken),
            MultiplexingStream.CreateAsync(
                streams.Item2,
                new MultiplexingStream.Options
        {
            TraceSource = mxClientTraceSource,
            DefaultChannelTraceSourceFactory = (id, name) => new TraceSource("MX Client channel " + id, SourceLevels.Verbose)
            {
                Listeners = { new XunitTraceListener(this.Logger) }
            },
        },
                this.TimeoutToken));

        this.serverMx = mxStreams[0];
        this.clientMx = mxStreams[1];

        MultiplexingStream.Channel[] rpcStreams = await Task.WhenAll(
            this.serverMx.AcceptChannelAsync(string.Empty, this.TimeoutToken),
            this.clientMx.OfferChannelAsync(string.Empty, this.TimeoutToken));

        MultiplexingStream.Channel rpcServerStream = rpcStreams[0];
        MultiplexingStream.Channel rpcClientStream = rpcStreams[1];

        this.InitializeFormattersAndHandlers();

        var serverHandler = new LengthHeaderMessageHandler(rpcServerStream, this.serverMessageFormatter);
        var clientHandler = new LengthHeaderMessageHandler(rpcClientStream, this.clientMessageFormatter);

        this.serverRpc = new JsonRpc(serverHandler, this.server);
        this.clientRpc = new JsonRpc(clientHandler);

        this.serverRpc.TraceSource = new TraceSource("Server", SourceLevels.Information);
        this.clientRpc.TraceSource = new TraceSource("Client", SourceLevels.Information);

        this.serverRpc.TraceSource.Listeners.Add(new XunitTraceListener(this.Logger));
        this.clientRpc.TraceSource.Listeners.Add(new XunitTraceListener(this.Logger));

        this.serverRpc.StartListening();
        this.clientRpc.StartListening();
    }