< Summary

Information
Class: IceRpc.Ice.Operations.IceProxyExtensions
Assembly: IceRpc.Ice
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Ice/Operations/IceProxyExtensions.cs
Tag: 1321_24790053727
Line coverage
88%
Covered lines: 63
Uncovered lines: 8
Coverable lines: 71
Total lines: 182
Line coverage: 88.7%
Branch coverage
83%
Covered branches: 10
Total branches: 12
Branch coverage: 83.3%
Method coverage
100%
Covered methods: 5
Fully covered methods: 3
Total methods: 5
Method coverage: 100%
Full method coverage: 60%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
InvokeOperationAsync(...)83.33%7670%
ReadResponseAsync()100%11100%
InvokeOperationAsync(...)83.33%6690.47%
ReadResponseAsync()100%11100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc.Ice/Operations/IceProxyExtensions.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using IceRpc.Features;
 4using System.Collections.Immutable;
 5using System.IO.Pipelines;
 6
 7namespace IceRpc.Ice.Operations;
 8
 9/// <summary>Represents a delegate that decodes the return value from an Ice-encoded response.</summary>
 10/// <typeparam name="T">The type of the return value to read.</typeparam>
 11/// <param name="response">The incoming response.</param>
 12/// <param name="request">The outgoing request.</param>
 13/// <param name="sender">The proxy that sent the request.</param>
 14/// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 15/// <returns>A value task that contains the return value or a <see cref="IceException" /> when the status code of the
 16/// response is <see cref="StatusCode.ApplicationError" />.</returns>
 17public delegate ValueTask<T> ResponseDecodeFunc<T>(
 18    IncomingResponse response,
 19    OutgoingRequest request,
 20    IIceProxy sender,
 21    CancellationToken cancellationToken);
 22
 23/// <summary>Represents a delegate that decodes the "void" return value from an Ice-encoded response.</summary>
 24/// <param name="response">The incoming response.</param>
 25/// <param name="request">The outgoing request.</param>
 26/// <param name="sender">The proxy that sent the request.</param>
 27/// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 28/// <returns>A value task that contains a <see cref="IceException" /> when the status code of the response is
 29/// <see cref="StatusCode.ApplicationError" />.</returns>
 30public delegate ValueTask ResponseDecodeFunc(
 31    IncomingResponse response,
 32    OutgoingRequest request,
 33    IIceProxy sender,
 34    CancellationToken cancellationToken);
 35
 36/// <summary>Provides helper methods for generated proxy structs.</summary>
 37public static class IceProxyExtensions
 38{
 239    private static readonly IDictionary<RequestFieldKey, OutgoingFieldValue> _idempotentFields =
 240        new Dictionary<RequestFieldKey, OutgoingFieldValue>
 241        {
 242            [RequestFieldKey.Idempotent] = default
 243        }.ToImmutableDictionary();
 44
 45    /// <summary>Sends a request to a service and decodes the response.</summary>
 46    /// <typeparam name="TProxy">The type of the proxy struct.</typeparam>
 47    /// <typeparam name="T">The response type.</typeparam>
 48    /// <param name="proxy">A proxy to the remote service.</param>
 49    /// <param name="operation">The name of the operation, as specified in Ice Slice.</param>
 50    /// <param name="payload">The payload of the request.</param>
 51    /// <param name="responseDecodeFunc">The decode function for the response payload. It decodes and throws an
 52    /// exception when the status code of the response is <see cref="StatusCode.ApplicationError" />.</param>
 53    /// <param name="features">The invocation features.</param>
 54    /// <param name="idempotent">When <see langword="true" />, the request is idempotent.</param>
 55    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 56    /// <returns>The operation's return value.</returns>
 57    /// <exception cref="IceException">Thrown if the response carries an Ice exception.</exception>
 58    public static Task<T> InvokeOperationAsync<TProxy, T>(
 59        this TProxy proxy,
 60        string operation,
 61        PipeReader payload,
 62        ResponseDecodeFunc<T> responseDecodeFunc,
 63        IFeatureCollection? features = null,
 64        bool idempotent = false,
 65        CancellationToken cancellationToken = default) where TProxy : struct, IIceProxy
 3666    {
 3667        if (proxy.Invoker is not IInvoker invoker)
 068        {
 069            throw new InvalidOperationException("Cannot send requests using a proxy with a null invoker.");
 70        }
 71
 3672        var request = new OutgoingRequest(proxy.ServiceAddress)
 3673        {
 3674            Features = features ?? FeatureCollection.Empty,
 3675            Fields = idempotent ? _idempotentFields : ImmutableDictionary<RequestFieldKey, OutgoingFieldValue>.Empty,
 3676            Operation = operation,
 3677            Payload = payload
 3678        };
 79
 80        Task<IncomingResponse> responseTask;
 81        try
 3682        {
 3683            responseTask = invoker.InvokeAsync(request, cancellationToken);
 3684        }
 085        catch
 086        {
 087            request.Dispose();
 088            throw;
 89        }
 90
 91        // ReadResponseAsync is responsible for disposing the request
 3692        return ReadResponseAsync(responseTask, request);
 93
 94        async Task<T> ReadResponseAsync(Task<IncomingResponse> responseTask, OutgoingRequest request)
 3695        {
 96            try
 3697            {
 3698                IncomingResponse response = await responseTask.ConfigureAwait(false);
 3699                return await responseDecodeFunc(
 36100                    response,
 36101                    request,
 36102                    proxy,
 36103                    cancellationToken).ConfigureAwait(false);
 104            }
 105            finally
 36106            {
 36107                request.Dispose();
 36108            }
 36109        }
 36110    }
 111
 112    /// <summary>Sends a request to a service and decodes the "void" response.</summary>
 113    /// <typeparam name="TProxy">The type of the proxy struct.</typeparam>
 114    /// <param name="proxy">A proxy for the remote service.</param>
 115    /// <param name="operation">The name of the operation, as specified in Ice Slice.</param>
 116    /// <param name="payload">The payload of the request.</param>
 117    /// <param name="responseDecodeFunc">The decode function for the response payload. It decodes and throws an
 118    /// exception when the status code of the response is <see cref="StatusCode.ApplicationError" />.</param>
 119    /// <param name="features">The invocation features.</param>
 120    /// <param name="idempotent">When <see langword="true" />, the request is idempotent.</param>
 121    /// <param name="oneway">When <see langword="true" />, the request is sent one-way and an empty response is returned
 122    /// immediately after sending the request.</param>
 123    /// <param name="cancellationToken">A cancellation token that receives the cancellation requests.</param>
 124    /// <returns>A task that completes when the void response is returned.</returns>
 125    /// <exception cref="IceException">Thrown if the response carries a failure.</exception>
 126    public static Task InvokeOperationAsync<TProxy>(
 127        this TProxy proxy,
 128        string operation,
 129        PipeReader payload,
 130        ResponseDecodeFunc responseDecodeFunc,
 131        IFeatureCollection? features = null,
 132        bool idempotent = false,
 133        bool oneway = false,
 134        CancellationToken cancellationToken = default) where TProxy : struct, IIceProxy
 73135    {
 73136        if (proxy.Invoker is not IInvoker invoker)
 0137        {
 0138            throw new InvalidOperationException("Cannot send requests using a proxy with a null invoker.");
 139        }
 140
 73141        var request = new OutgoingRequest(proxy.ServiceAddress)
 73142        {
 73143            Features = features ?? FeatureCollection.Empty,
 73144            Fields = idempotent ? _idempotentFields : ImmutableDictionary<RequestFieldKey, OutgoingFieldValue>.Empty,
 73145            IsOneway = oneway,
 73146            Operation = operation,
 73147            Payload = payload,
 73148        };
 149
 150        Task<IncomingResponse> responseTask;
 151        try
 73152        {
 73153            responseTask = invoker.InvokeAsync(request, cancellationToken);
 72154        }
 1155        catch
 1156        {
 1157            request.Dispose();
 1158            throw;
 159        }
 160
 161        // ReadResponseAsync is responsible for disposing the request
 72162        return ReadResponseAsync(responseTask, request);
 163
 164        async Task ReadResponseAsync(Task<IncomingResponse> responseTask, OutgoingRequest request)
 72165        {
 166            try
 72167            {
 72168                IncomingResponse response = await responseTask.ConfigureAwait(false);
 169
 72170                await responseDecodeFunc(
 72171                    response,
 72172                    request,
 72173                    proxy,
 72174                    cancellationToken).ConfigureAwait(false);
 43175            }
 176            finally
 72177            {
 72178                request.Dispose();
 72179            }
 43180        }
 72181    }
 182}