public async Task <T> CallAsync <T>(string functionName, object parameter = null) where T : class { var request = new AmqpRpcRequest() { Method = functionName, Parameters = parameter, Type = RpcRequestType.Call }; return(await this.SendRequestAsync <T>(request)); }
public async Task NotifyAsync(string functionName, object parameter = null) { var request = new AmqpRpcRequest() { Method = functionName, Parameters = parameter, Type = RpcRequestType.Notify }; await this.SendRequestAsync <object>(request); }
private async Task <T> SendRequestAsync <T>(AmqpRpcRequest request) where T : class { var _message = new Message() { BodySection = new AmqpValue <AmqpRpcRequest>(request) }; var id = Guid.NewGuid().ToString(); _message.Properties = new Properties() { Subject = this._subject, To = this._amqpNode, ReplyTo = request.Type.Equals(RpcRequestType.Call) ? this._clientReceiveAddress : string.Empty, MessageId = id, CorrelationId = id }; _message.Header = new Header() { Ttl = this._timeout }; _ = this._sender.SendAsync(_message); if (request.Type.Equals(RpcRequestType.Call)) { try { var tcs = new TaskCompletionSource <T>(); this._pendingRequests.TryAdd(id, new PendingRequest <T>(tcs)); return(await tcs.Task.TimeoutAfterAsync <T>(timeout : unchecked ((int)this._timeout))); } catch (TimeoutException) { this._isTimedout = true; throw new AmqpRpcRequestTimeoutException($"Request timedout while executing {request.Method}"); } } return(null); }
private async void ProcessIncomingRpcRequestAsync(IReceiverLink receiver, Message message) { //Accept the message since we would be replying using sender, hence disposition does not make sense await Task.Run(async() => { receiver.Accept(message); //Deserialize the body AmqpRpcRequest _rpcRequest = message.GetBody <AmqpRpcRequest>(); string _replyTo = message.Properties.ReplyTo; string _correlationId = message.Properties.CorrelationId; if (!_rpMethodTypes.Contains(_rpcRequest.Type)) { Log.Error($"Invalid request type received: {_rpcRequest.Type}"); await this.SendResponseAsync(replyTo: _replyTo, correlationId: _correlationId, requestType: _rpcRequest.Type, response: null, ex: new AmqpRpcInvalidRpcTypeException(_rpcRequest.Type)); return; } if (string.IsNullOrEmpty(_rpcRequest.Method)) { Log.Error("Missing RPC function call name: {@_rpcRequest}", _rpcRequest); await this.SendResponseAsync(replyTo: _replyTo, correlationId: _correlationId, requestType: _rpcRequest.Type, response: null, ex: new AmqpRpcMissingFunctionNameException(JsonConvert.SerializeObject(_rpcRequest))); return; } if (!this._serverFunctions.ContainsKey(_rpcRequest.Method)) { Log.Error($"Unknown RPC method request received: {_rpcRequest.Method}"); await this.SendResponseAsync(replyTo: _replyTo, correlationId: _correlationId, requestType: _rpcRequest.Type, response: null, ex: new AmqpRpcUnknownFunctionException($"{_rpcRequest.Method} is not bound to remote server")); return; } var _requestObjectType = this._serverFunctions.SingleOrDefault(x => x.Key.Equals(_rpcRequest.Method)); if (_requestObjectType.Value == null) { Log.Error($"Unknown RPC method request received: {_rpcRequest.Method}"); await this.SendResponseAsync(replyTo: _replyTo, correlationId: _correlationId, requestType: _rpcRequest.Type, response: null, ex: new AmqpRpcUnknownFunctionException($"{_rpcRequest.Method} is not bound to remote server")); return; } var _methodParameter = this._utility.PeeloutAmqpWrapper(deserializationType: _requestObjectType.Value.RequestParameterType, parameters: _rpcRequest.Parameters); var _classInstance = Activator.CreateInstance(_requestObjectType.Value.FunctionWrapperType); MethodInfo _method = _requestObjectType.Value.FunctionWrapperType.GetMethod(_requestObjectType.Key); var _asyncAttribute = _method.GetCustomAttribute <AsyncStateMachineAttribute>(); var _isAsync = (_asyncAttribute != null) || (_method.ReturnType.BaseType.Equals(typeof(Task))); try { if (!(_methodParameter is null) && _method.GetParameters().Length > 0) { //TODO: check for missing properties from rpc calls //await this.SendResponse(replyTo: _replyTo, correlationId: _correlationId, _rpcRequest.type, null, new AmqpRpcUnknowParameterException($"{_rpcRequest.method} invokation failed, mismatch in parameter")); object _rtnVal = null; try { if (_isAsync) { _rtnVal = await(dynamic) _method.Invoke(_classInstance, new[] { _methodParameter }); } else { _rtnVal = _method.Invoke(_classInstance, new[] { _methodParameter }); } await this.SendResponseAsync(replyTo: _replyTo, correlationId: _correlationId, requestType: _rpcRequest.Type, response: _rtnVal, ex: null); } catch (Exception ex) { await this.SendResponseAsync(replyTo: _replyTo, correlationId: _correlationId, requestType: _rpcRequest.Type, response: null, ex: ex); return; } } else if (_methodParameter is null && _method.GetParameters().Length.Equals(0)) { object _rtnVal = null; try { if (_isAsync) { _rtnVal = await(dynamic) _method.Invoke(_classInstance, null); } else { _rtnVal = _method.Invoke(_classInstance, null); } await this.SendResponseAsync(replyTo: _replyTo, correlationId: _correlationId, requestType: _rpcRequest.Type, response: _rtnVal, ex: null); } catch (Exception ex) { await this.SendResponseAsync(replyTo: _replyTo, correlationId: _correlationId, requestType: _rpcRequest.Type, response: null, ex: ex); return; } }