Exemple #1
0
        /// <summary>
        /// 发送json格式的Http Rpc远程调用
        /// </summary>
        /// <typeparam name="T">结果对象的类型</typeparam>
        /// <returns>返回远程调用结果</returns>
        public async Task <T> Call <T>()
        {
            // 远程请求
            byte[] data = null;
            using (var request = CreateRequestMessage())
                using (var content = new PushStreamContent((ws) => RpcClientKit.WriteFrame(ws, _data, _isCompressed)))
                {
                    request.Content = content;
                    HttpResponseMessage response;
                    try
                    {
                        response = await _client.SendAsync(request).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        throw new ServerException("服务器连接失败", $"调用【{_methodName}】时服务器连接失败!\r\n{ex.Message}");
                    }

                    if (response.StatusCode != System.Net.HttpStatusCode.OK)
                    {
#if !SERVER
                        // 无权限时
                        if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                        {
                            // 已登录则提示无权限
                            if (Kit.IsLogon)
                            {
                                throw new KnownException($"⚡对【{_methodName}】无访问权限!");
                            }

                            // 跳转到登录页面
                            Kit.Login(true);
                            throw new KnownException("请先登录您的账号!");
                        }
#endif
                        throw new ServerException($"服务器返回状态码:{response.StatusCode}", $"调用【{_methodName}】时返回状态码:{response.StatusCode}");
                    }

                    var stream = await response.Content.ReadAsStreamAsync();

                    data = await RpcClientKit.ReadFrame(stream);

                    response.Dispose();
                }
            return(ParseResult <T>(data));
        }
Exemple #2
0
        /// <summary>
        /// 读取从服务器返回的下一帧数据
        /// </summary>
        /// <returns></returns>
        public async Task <bool> MoveNext()
        {
            try
            {
                // _responseStream.ReadAsync 使用 CancellationToken 也只有第一次取消时有效,所以未使用!
                // 此处只在服务端取消连接时抛出异常!
                var data = await RpcClientKit.ReadFrame(_responseStream);

                _val = RpcKit.ParseBytes <object>(data);
                return(true);
            }
            catch
            {
                Dispose();
            }
            return(false);
        }
Exemple #3
0
        /// <summary>
        /// 向服务端写入一帧
        /// </summary>
        /// <param name="p_message">支持序列化的对象</param>
        /// <returns></returns>
        public async Task <bool> Write(object p_message)
        {
            // 请求流已关闭
            if (_rpc.RequestStream == null || _rpc.RequestCompleted)
            {
                _rpc.FinishRequest();
                return(false);
            }

            try
            {
                await RpcClientKit.WriteFrame(_rpc.RequestStream, p_message);

                return(true);
            }
            catch { }

            _rpc.FinishRequest();
            return(false);
        }
Exemple #4
0
        protected RequestWriter CreateWriter(HttpRequestMessage p_request)
        {
            _writeStreamTcs   = new TaskCompletionSource <Stream>(TaskCreationOptions.RunContinuationsAsynchronously);
            _writeCompleteTcs = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

            p_request.Content = new PushStreamContent(async(stream) =>
            {
                // 不同平台stream类型不同,造成uwp、android、ios客户端调用stream.FlushAsync()时并未发送!
                // asp.net core:System.Net.Http.Http2Connection.Http2Stream.Http2WriteStream
                // uwp:System.Net.Http.HttpContent.LimitMemoryStream
                // mono:System.Net.Http.HttpContent.FixedMemoryStream

                // 先发送调用帧
                await RpcClientKit.WriteFrame(stream, _data, _isCompressed).ConfigureAwait(false);
                // 允许自定义写入
                _writeStreamTcs.TrySetResult(stream);
                // 控制发送任务不结束,未结束前一直可发送
                await _writeCompleteTcs.Task;
            });
            return(new RequestWriter(this));
        }
Exemple #5
0
        /// <summary>
        /// 启动Http2协议的远程调用,客户端发送一个请求,服务端返回数据流响应
        /// </summary>
        /// <returns></returns>
        public async Task <ResponseReader> Call()
        {
            try
            {
                using (var request = CreateRequestMessage())
                    using (var content = new PushStreamContent((ws) => RpcClientKit.WriteFrame(ws, _data, _isCompressed)))
                    {
                        // 必须设置 WebAssemblyEnableStreamingResponse 为 true,WASM 才会返回 stream 类型的 response;
                        // 如果不设置,则只在整个response结束时收到一次,无法实现服务器推送流模式!!!参见:
                        // https://github.com/grpc/grpc-dotnet/blob/master/src/Grpc.Net.Client.Web/GrpcWebHandler.cs#L137
                        //
                        // 此限制和服务端无关,只是WASM客户端在收到服务器推送后的处理方式不同,默认response 非 stream模式,参见:
                        // https://github.com/mono/mono/blob/a0d69a4e876834412ba676f544d447ec331e7c01/sdks/wasm/framework/src/System.Net.Http.WebAssemblyHttpHandler/WebAssemblyHttpHandler.cs#L149
                        //
                        // https://github.com/mono/mono/issues/18718
#if WASM
#pragma warning disable CS0618
                        request.Properties["WebAssemblyEnableStreamingResponse"] = true;
#pragma warning restore CS0618
#endif

                        request.Content = content;
                        // 一定是ResponseHeadersRead,否则只在结束时收到一次!!!众里寻他千百度
                        var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None);

                        response.EnsureSuccessStatusCode();

                        var reader = new ResponseReader(response);
                        // wasm中增加上述设置后返回 stream 正常!
                        await reader.InitStream();

                        return(reader);
                    }
            }
            catch (Exception ex)
            {
                throw new Exception($"调用【{_methodName}】时服务器连接失败!\r\n{ex.Message}");
            }
        }