public static async Task <TChRspEnvelope> HandleChannelRequest <TReq, TRsp, TChReq, TChRsp, TChRspEnvelope>( Container container, IMapper mapper, ServerCallContext ctx, string serverId, CqrsInfo info, TChReq chReq, CancellationToken cancellationToken = default) { GrpcResponseEnvelope <TRsp> rsp = null; Exception exception = null; // get logger var logger = (container.TryGetInstance(typeof(ILoggerFactory)) as ILoggerFactory)?.CreateLogger("CqrsGrpcServer"); // get aspect var aspect = container.TryGetInstance(typeof(IGrpcServerAspect)) as IGrpcServerAspect; // call recieved aspect?.OnCallRecieved(ctx); // name var name = chReq?.GetType()?.Name ?? "Unknown"; var watch = Stopwatch.StartNew(); try { // before execution logger?.LogDebug("Request {requestName} started on server {serverId}.", name, serverId); var req = mapper.Map <TReq>(chReq); aspect?.BeforeExecution(req); // execution function Func <Task <GrpcResponseEnvelope <TRsp> > > execFnc = () => { var processor = container.GetInstance <IGrpcCqrsServerProcessor>(); return(Task.Run(async() => await processor.ProcessRequestAsync <TReq, TRsp>(req, info, cancellationToken))); }; // execute rsp = await(aspect != null ? aspect.ExecuteAsync(container, execFnc) : execFnc.Invoke()); // execution completed var chRsp = mapper.Map <TChRspEnvelope>(rsp); watch.Stop(); logger?.LogInformation("Request {requestName} completed on server {serverId}. Call duration was {durationMs}ms.", name, serverId, watch.ElapsedMilliseconds); return(chRsp); } catch (ValidationErrorResponseException e) { exception = e; watch.Stop(); logger.LogInformation("Request {requestName} validation error on server {serverId}. Call duration was {durationMs}ms.", name, serverId, watch.ElapsedMilliseconds); rsp = new GrpcResponseEnvelope <TRsp> { IsValidationError = true, ValidationError = e.Response }; var chRsp = mapper.Map <TChRspEnvelope>(rsp); return(chRsp); } catch (Exception e) { exception = e; watch.Stop(); logger.LogError(e, "Request {requestName} failed on server {serverId}. Call duration was {durationMs}ms.", name, serverId, watch.ElapsedMilliseconds); rsp = new GrpcResponseEnvelope <TRsp> { IsExecutionError = true, ErrorMessage = e.Message }; var chRsp = mapper.Map <TChRspEnvelope>(rsp); return(chRsp); } finally { aspect?.AfterExecution(rsp, exception); } }
private async Task <GrpcResponseEnvelope <TResponse> > CallUnaryMethodAsync <TRequest, TResponse, TChRequest, TChResponse, TChResponseEnvelope>(TRequest req, CancellationToken ct) where TRequest : class where TChRequest : class where TChResponseEnvelope : class { GrpcResponseEnvelope <TResponse> rsp = null; Exception exception = null; var reqName = req.GetType().Name; var watch = Stopwatch.StartNew(); try { _logger?.LogDebug("Request {requestName} started on client {clientId} for host {host}.", reqName, Id, Host); var chReq = _mapper.Map <TChRequest>(req); _clientAspect?.BeforeExecution(req); var chRsp = await CallUnaryMethodChannelAsync <TChRequest, TChResponseEnvelope>(chReq, ct); rsp = _mapper.Map <GrpcResponseEnvelope <TResponse> >(chRsp); watch.Stop(); // execution error if (rsp.IsExecutionError) { _logger?.LogError("Request {requestName} failed on client {clientId} with host {host} execution error. Call duration was {durationMs}ms.", reqName, Id, Host, watch.ElapsedMilliseconds); throw new GrpcClientExecutionException($"Execution error: {rsp.ErrorMessage}"); } // data validation error if (rsp.IsValidationError) { _logger?.LogInformation("Request {requestName} completed on client {clientId} with host {host} validation error. Call duration was {durationMs}ms.", reqName, Id, Host, watch.ElapsedMilliseconds); throw new ValidationErrorResponseException(rsp.ValidationError); } // no error return(rsp); } catch (ValidationErrorResponseException e) { throw e; } catch (Exception e) { exception = e; watch.Stop(); _logger?.LogError(e, "Request {requestName} failed on client {clientId} for host {host}. Call duration was {durationMs}ms.", reqName, Id, Host, watch.ElapsedMilliseconds); // do not handle exceptions if (!_configuration.HandleExceptions) { throw; } // handled exception rsp = new GrpcResponseEnvelope <TResponse> { IsExecutionError = true, ErrorMessage = e.Message }; return(rsp); } finally { _clientAspect?.AfterExecution(rsp, exception); } }