TReturn IQueryClient.Call <TReturn>(Type interfaceType, string methodName, object[] arguments) { var providerName = interfaceType.Name; var stringArguments = arguments.Select(x => JsonSerializer.Serialize(x)).ToArray(); var returnType = typeof(TReturn); var data = new CQRSRequestData() { ProviderType = providerName, ProviderMethod = methodName, }; data.AddProviderArguments(arguments); var returnTypeDetails = TypeAnalyzer.GetTypeDetail(returnType); if (returnTypeDetails.IsTask) { var callRequestAsyncMethodGeneric = TypeAnalyzer.GetGenericMethodDetail(requestAsyncMethod, returnTypeDetails.InnerTypes.ToArray()); return((TReturn)callRequestAsyncMethodGeneric.Caller(this, new object[] { endpointAddress, providerName, requestContentType, data, true })); } else { var model = Request <TReturn>(endpointAddress, providerName, requestContentType, data, true); return(model); } }
private static Task Dispatch(CQRSRequestData data) { var commandType = Discovery.GetTypeFromName(data.MessageType); var typeDetail = TypeAnalyzer.GetTypeDetail(commandType); if (!typeDetail.Interfaces.Contains(typeof(ICommand))) { throw new Exception($"Type {data.MessageType} is not a command"); } bool exposed = typeDetail.Attributes.Any(x => x is ServiceExposedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == NetworkType.Api)) && !typeDetail.Attributes.Any(x => x is ServiceBlockedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == NetworkType.Api)); if (!exposed) { throw new Exception($"Command {data.MessageType} is not exposed to {NetworkType.Api}"); } var command = (ICommand)JsonSerializer.Deserialize(data.MessageData, commandType); if (data.MessageAwait) { return(Bus.HandleRemoteCommandDispatchAwaitAsync(command)); } else { return(Bus.HandleRemoteCommandDispatchAsync(command)); } }
private static Task <RemoteQueryCallResponse> Call(CQRSRequestData data) { var providerType = Discovery.GetTypeFromName(data.ProviderType); if (!providerType.IsInterface) { throw new ArgumentException($"Provider {data.ProviderType} is not an interface type"); } var typeDetail = TypeAnalyzer.GetTypeDetail(providerType); bool exposed = typeDetail.Attributes.Any(x => x is ServiceExposedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == NetworkType.Api)) && !typeDetail.Attributes.Any(x => x is ServiceBlockedAttribute attribute && (attribute.NetworkType == NetworkType.Api || !attribute.NetworkType.HasValue)); MethodBase method = null; foreach (var methodInfo in typeDetail.MethodDetails) { if (methodInfo.MethodInfo.Name == data.ProviderMethod && methodInfo.ParametersInfo.Count == (data.ProviderArguments != null ? data.ProviderArguments.Length : 0)) { if (!exposed && (!methodInfo.Attributes.Any(x => x is ServiceExposedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == NetworkType.Api)) || methodInfo.Attributes.Any(x => x is ServiceBlockedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == NetworkType.Api)))) { throw new Exception($"Method {data.ProviderType}.{data.ProviderMethod} is not exposed to {NetworkType.Api}"); } method = methodInfo.MethodInfo; break; } } if (method == null) { throw new Exception($"Method {data.ProviderType}.{data.ProviderMethod} does not exsist"); } return(Bus.HandleRemoteQueryCallAsync(providerType, data.ProviderMethod, data.ProviderArguments)); }
Task ICommandClient.DispatchAsyncAwait(ICommand message) { var commandType = message.GetType(); var commendTypeName = commandType.GetNiceFullName(); var commandData = JsonSerializer.Serialize(message, commandType); var data = new CQRSRequestData() { MessageType = commendTypeName, MessageData = commandData, MessageAwait = true }; return(RequestAsync <object>(endpointAddress, commendTypeName, requestContentType, data, false)); }
protected override async Task DispatchInternal(ICommand command, bool messageAwait) { var messageType = command.GetType(); var messageTypeName = messageType.GetNiceName(); var messageData = System.Text.Json.JsonSerializer.Serialize(command, messageType); var data = new CQRSRequestData() { MessageType = messageTypeName, MessageData = messageData, MessageAwait = messageAwait }; switch (networkType) { case NetworkType.Internal: data.AddClaims(); break; case NetworkType.Api: break; default: throw new NotImplementedException(); } var stopwatch = Stopwatch.StartNew(); var client = new TcpClient(endpoint.AddressFamily); client.NoDelay = true; var bufferOwner = BufferArrayPool <byte> .Rent(TcpRawCommon.BufferLength); var buffer = bufferOwner.AsMemory(); Stream stream = null; Stream requestBodyStream = null; FinalBlockStream requestBodyCryptoStream = null; Stream responseBodyStream = null; try { await client.ConnectAsync(endpoint.Address, endpoint.Port); stream = client.GetStream(); //Request Header var requestHeaderLength = TcpRawCommon.BufferHeader(buffer, data.MessageType, contentType); #if NETSTANDARD2_0 await stream.WriteAsync(bufferOwner, 0, requestHeaderLength); #else await stream.WriteAsync(buffer.Slice(0, requestHeaderLength)); #endif requestBodyStream = new TcpRawProtocolBodyStream(stream, null, true); if (encryptionKey != null) { requestBodyCryptoStream = SymmetricEncryptor.Encrypt(encryptionAlgorithm, encryptionKey, requestBodyStream, true, true); await ContentTypeSerializer.SerializeAsync(contentType, requestBodyCryptoStream, data); #if NET5_0_OR_GREATER await requestBodyCryptoStream.FlushFinalBlockAsync(); #else requestBodyCryptoStream.FlushFinalBlock(); #endif #if NETSTANDARD2_0 requestBodyCryptoStream.Dispose(); #else await requestBodyCryptoStream.DisposeAsync(); #endif requestBodyCryptoStream = null; } else { await ContentTypeSerializer.SerializeAsync(contentType, requestBodyStream, data); await requestBodyStream.FlushAsync(); } #if NETSTANDARD2_0 requestBodyStream.Dispose(); #else await requestBodyStream.DisposeAsync(); #endif requestBodyStream = null; //Response Header var headerPosition = 0; var headerLength = 0; var requestHeaderEnd = false; while (!requestHeaderEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRawCQRSClient)} Header Too Long"); } #if NETSTANDARD2_0 var bytesRead = await stream.ReadAsync(bufferOwner, headerPosition, buffer.Length - headerPosition); #else var bytesRead = await stream.ReadAsync(buffer.Slice(headerPosition, buffer.Length - headerPosition)); #endif if (bytesRead == 0) { throw new EndOfStreamException(); } headerLength += bytesRead; requestHeaderEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var responseHeader = TcpRawCommon.ReadHeader(buffer, headerPosition, headerLength); //Response Body responseBodyStream = new TcpRawProtocolBodyStream(stream, responseHeader.BodyStartBuffer, false); if (responseHeader.IsError) { if (encryptionKey != null) { responseBodyStream = SymmetricEncryptor.Decrypt(encryptionAlgorithm, encryptionKey, responseBodyStream, false, false); } var responseException = await ContentTypeSerializer.DeserializeExceptionAsync(contentType, responseBodyStream); throw responseException; } if (responseBodyStream != null) { #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif } client.Dispose(); stopwatch.Stop(); _ = Log.TraceAsync($"{nameof(TcpRawCQRSClient)}Sent: {messageTypeName} {stopwatch.ElapsedMilliseconds}"); } catch { if (responseBodyStream != null) { #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif } if (requestBodyStream != null) { #if NETSTANDARD2_0 requestBodyStream.Dispose(); #else await requestBodyStream.DisposeAsync(); #endif } if (stream != null) { #if NETSTANDARD2_0 stream.Dispose(); #else await stream.DisposeAsync(); #endif } client.Dispose(); throw; } finally { BufferArrayPool <byte> .Return(bufferOwner); } }
protected override TReturn CallInternal <TReturn>(bool isStream, Type interfaceType, string methodName, object[] arguments) { var data = new CQRSRequestData() { ProviderType = interfaceType.Name, ProviderMethod = methodName }; data.AddProviderArguments(arguments); switch (networkType) { case NetworkType.Internal: data.AddClaims(); break; case NetworkType.Api: break; default: throw new NotImplementedException(); } var stopwatch = Stopwatch.StartNew(); var client = new TcpClient(endpoint.AddressFamily); var bufferOwner = BufferArrayPool <byte> .Rent(TcpRawCommon.BufferLength); var buffer = bufferOwner.AsMemory(); Stream stream = null; Stream requestBodyStream = null; FinalBlockStream requestBodyCryptoStream = null; Stream responseBodyStream = null; try { client.Connect(endpoint.Address, endpoint.Port); stream = client.GetStream(); //Request Header var requestHeaderLength = TcpRawCommon.BufferHeader(buffer, data.ProviderType, contentType); #if NETSTANDARD2_0 stream.Write(bufferOwner, 0, requestHeaderLength); #else stream.Write(buffer.Span.Slice(0, requestHeaderLength)); #endif requestBodyStream = new TcpRawProtocolBodyStream(stream, null, true); if (encryptionKey != null) { requestBodyCryptoStream = SymmetricEncryptor.Encrypt(encryptionAlgorithm, encryptionKey, requestBodyStream, true, true); ContentTypeSerializer.Serialize(contentType, requestBodyCryptoStream, data); requestBodyCryptoStream.FlushFinalBlock(); requestBodyCryptoStream.Dispose(); requestBodyCryptoStream = null; } else { ContentTypeSerializer.Serialize(contentType, requestBodyStream, data); requestBodyStream.Flush(); } requestBodyStream.Dispose(); requestBodyStream = null; //Response Header var headerPosition = 0; var headerLength = 0; var requestHeaderEnd = false; while (!requestHeaderEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRawCQRSClient)} Header Too Long"); } #if NETSTANDARD2_0 var bytesRead = stream.Read(bufferOwner, headerPosition, buffer.Length - headerPosition); #else var bytesRead = stream.Read(buffer.Span.Slice(headerPosition, buffer.Length - headerPosition)); #endif if (bytesRead == 0) { throw new EndOfStreamException(); } headerLength += bytesRead; requestHeaderEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var responseHeader = TcpRawCommon.ReadHeader(buffer, headerPosition, headerLength); responseBodyStream = new TcpRawProtocolBodyStream(stream, responseHeader.BodyStartBuffer, false); if (encryptionKey != null) { responseBodyStream = SymmetricEncryptor.Decrypt(encryptionAlgorithm, encryptionKey, responseBodyStream, false, false); } if (responseHeader.IsError) { var responseException = ContentTypeSerializer.DeserializeException(contentType, responseBodyStream); throw responseException; } stopwatch.Stop(); _ = Log.TraceAsync($"{nameof(TcpRawCQRSClient)} Query: {interfaceType.GetNiceName()}.{data.ProviderMethod} {stopwatch.ElapsedMilliseconds}"); if (isStream) { return((TReturn)(object)responseBodyStream); //TODO better way to convert type??? } else { var model = ContentTypeSerializer.Deserialize <TReturn>(contentType, responseBodyStream); responseBodyStream.Dispose(); client.Dispose(); return(model); } } catch { try { //crypto stream can error, we want to throw the actual error if (responseBodyStream != null) { responseBodyStream.Dispose(); } } catch { } if (requestBodyStream != null) { requestBodyStream.Dispose(); } if (requestBodyCryptoStream != null) { requestBodyCryptoStream.Dispose(); } if (stream != null) { stream.Dispose(); } client.Dispose(); throw; } finally { BufferArrayPool <byte> .Return(bufferOwner); } }
protected override TReturn CallInternal <TReturn>(bool isStream, Type interfaceType, string methodName, object[] arguments) { var data = new CQRSRequestData() { ProviderType = interfaceType.Name, ProviderMethod = methodName }; data.AddProviderArguments(arguments); HttpAuthHeaders authHeaders = null; switch (networkType) { case NetworkType.Internal: data.AddClaims(); break; case NetworkType.Api: if (apiAuthorizer != null) { authHeaders = apiAuthorizer.BuildAuthHeaders(); } break; default: throw new NotImplementedException(); } var stopwatch = Stopwatch.StartNew(); var client = new TcpClient(endpoint.AddressFamily); client.NoDelay = true; var bufferOwner = BufferArrayPool <byte> .Rent(HttpCommon.BufferLength); var buffer = bufferOwner.AsMemory(); Stream stream = null; Stream requestBodyStream = null; Stream responseBodyStream = null; try { client.Connect(endpoint.Address, endpoint.Port); stream = client.GetStream(); //Request Header var requestHeaderLength = HttpCommon.BufferHeader(buffer, data.ProviderType, contentType, serviceUrl, authHeaders); #if NETSTANDARD2_0 stream.Write(bufferOwner, 0, requestHeaderLength); #else stream.Write(buffer.Span.Slice(0, requestHeaderLength)); #endif requestBodyStream = new HttpProtocolBodyStream(null, stream, null, true); ContentTypeSerializer.Serialize(contentType, requestBodyStream, data); requestBodyStream.Flush(); requestBodyStream.Dispose(); requestBodyStream = null; //Response Header var headerPosition = 0; var headerLength = 0; var headerEnd = false; while (!headerEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(HttpCQRSClient)} Header Too Long"); } #if NETSTANDARD2_0 var bytesRead = stream.Read(bufferOwner, headerPosition, buffer.Length - headerPosition); #else var bytesRead = stream.Read(buffer.Span.Slice(headerPosition, buffer.Length - headerPosition)); #endif if (bytesRead == 0) { throw new EndOfStreamException(); } headerLength += bytesRead; headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var responseHeader = HttpCommon.ReadHeader(buffer, headerPosition, headerLength); //Response Body responseBodyStream = new HttpProtocolBodyStream(null, stream, responseHeader.BodyStartBuffer, false); if (responseHeader.IsError) { var responseException = ContentTypeSerializer.DeserializeException(contentType, responseBodyStream); throw responseException; } stopwatch.Stop(); _ = Log.TraceAsync($"{nameof(HttpCQRSClient)} Query: {interfaceType.GetNiceName()}.{data.ProviderMethod} {stopwatch.ElapsedMilliseconds}"); if (isStream) { return((TReturn)(object)responseBodyStream); } else { var model = ContentTypeSerializer.Deserialize <TReturn>(contentType, responseBodyStream); responseBodyStream.Dispose(); client.Dispose(); return(model); } } catch { if (responseBodyStream != null) { responseBodyStream.Dispose(); } if (requestBodyStream != null) { requestBodyStream.Dispose(); } if (stream != null) { stream.Dispose(); } client.Dispose(); throw; } finally { BufferArrayPool <byte> .Return(bufferOwner); } }
public static async Task <ApiResponseData> HandleRequestAsync(ContentType?contentType, CQRSRequestData data) { if (!String.IsNullOrWhiteSpace(data.ProviderType)) { if (contentType == null) { return(null); } var response = await Call(data); if (response.Stream != null) { return(new ApiResponseData(response.Stream)); } else if (response.Model != null) { var bytes = ContentTypeSerializer.Serialize(contentType.Value, response.Model); return(new ApiResponseData(bytes)); } else { return(new ApiResponseData(Array.Empty <byte>())); } } else if (!String.IsNullOrWhiteSpace(data.MessageType)) { await Dispatch(data); return(new ApiResponseData()); } return(null); }