/// <summary> /// Makes a method request from a message /// </summary> /// <param name="message"></param> /// <param name="timeout"></param> /// <param name="ct"></param> /// <returns></returns> internal async Task <Message> InvokeDeviceMethodAsync(Message message, TimeSpan timeout, CancellationToken ct) { #endif if (string.IsNullOrEmpty(message.DeviceId)) { throw ProxyEventSource.Log.ArgumentNull("deviceId"); } var buffer = new MemoryStream(); var request = new MethodCallRequest(message, timeout); request.Encode(buffer, CodecId.Json); var uri = new UriBuilder { Scheme = "https", Host = _hubConnectionString.HostName, Path = $"/twins/{WebUtility.UrlEncode(message.DeviceId)}/methods", Query = "api-version=" + _apiVersion }; MethodCallResponse response; try { var stream = await _http.StreamAsync(uri.Uri, Http.Post, async h => { h.Add(HttpRequestHeader.Authorization.ToString(), await GetSasTokenAsync(3600).ConfigureAwait(false)); h.Add(HttpRequestHeader.UserAgent.ToString(), _clientId); }, (s, h) => { }, ct, Encoding.UTF8.GetString(buffer.ToArray()), "application/json").ConfigureAwait(false); using (stream) { response = MethodCallResponse.Decode(stream, CodecId.Json); } } catch (HttpResponseException hex) { if (hex.StatusCode != HttpStatusCode.NotFound) { ProxyEventSource.Log.HandledExceptionAsError(this, hex); throw new ProxyException( $"Remote proxy device method communication failure: {hex.StatusCode}.", hex); } else { ProxyEventSource.Log.HandledExceptionAsInformation(this, hex); throw new ProxyNotFoundException(hex); } } catch (OperationCanceledException) { throw; } catch (Exception ex) { ProxyEventSource.Log.HandledExceptionAsError(this, ex); throw new ProxyException($"Unknown proxy failure.", ex); } if (response.Status != 200) { throw ProxyEventSource.Log.Rethrow( new ProxyException($"Unexpected status {response.Status} returned by proxy.")); } return(response.Payload); }
private object OnMethodCallback(string methodName, List <object> parameterValues, List <object> parameterTypes, Type returnType) { //call server here, get response if needed MethodCallRequest request = new MethodCallRequest() { MethodName = methodName, ParameterTypes = parameterTypes.OfType <Type>().ToList(), ParameterValues = parameterValues, ReturnType = returnType }; var requestMessage = new PipeMessage <MethodCallRequest>(request); var json = JsonConvert.SerializeObject(requestMessage); byte[] requestBytes = Encoding.ASCII.GetBytes(json); this.client.Send(requestBytes); //eventhandler waitone responseEvent.Wait(TimeSpan.FromMilliseconds(receiveTimeout)); if (responseEvent.IsSet) { //get the response stored, reset the object var localResponse = responseMessage; responseMessage = null; responseEvent.Reset(); //parse the response and return it //deserialize it to MethodCallResponse var result = localResponse.GetPayload <MethodCallResponse>(); if (result.ReturnValue == null) { return(null); } else { if (result.ReturnType == typeof(ServerException)) { throw new ServerException(result.ReturnValue.ToString()); } if (result.ReturnValue.ToString().StartsWith("{") == false && result.ReturnValue.ToString().StartsWith("[") == false) { //not a json, it's a primitive if (result.ReturnType.BaseType == typeof(Enum)) { return(Convert.ChangeType(result.ReturnValue, typeof(int))); } return(Convert.ChangeType(result.ReturnValue, result.ReturnType)); } return(JsonConvert.DeserializeObject(result.ReturnValue.ToString(), returnType)); } } else { throw new ServerException("Server timeout reached"); } }
/// <summary> /// Makes a method request from a message /// </summary> /// <param name="message"></param> /// <param name="timeout"></param> /// <param name="ct"></param> /// <returns></returns> public async Task <Message> CallAsync(Message message, TimeSpan timeout, CancellationToken ct) { #if LOG_MESSAGES var sw = System.Diagnostics.Stopwatch.StartNew(); #endif #endif if (string.IsNullOrEmpty(message.DeviceId)) { throw ProxyEventSource.Log.ArgumentNull("deviceId"); } var buffer = new MemoryStream(); var request = MethodCallRequest.Create(message, timeout); request.Encode(buffer, CodecId.Json); var uri = new UriBuilder { Scheme = "https", Host = ConnectionString.HostName, Path = $"/twins/{WebUtility.UrlEncode(message.DeviceId)}/methods", Query = "api-version=" + IoTHubService._apiVersion }; MethodCallResponse response; try { var stream = await _http.StreamAsync(uri.Uri, Http.Post, async h => { h.Add(HttpRequestHeader.Authorization.ToString(), await IoTHubService.GetSasTokenAsync(ConnectionString, 3600).ConfigureAwait(false)); h.Add(HttpRequestHeader.UserAgent.ToString(), IoTHubService._clientId); }, (s, h) => { }, ct, Encoding.UTF8.GetString(buffer.ToArray()), "application/json").ConfigureAwait(false); using (stream) { response = Serializable.Decode <MethodCallResponse>(stream, CodecId.Json); } } catch (HttpResponseException hex) { ProxyEventSource.Log.HandledExceptionAsError(this, hex); if (hex.StatusCode == HttpStatusCode.NotFound) { throw new ProxyNotFound(hex); } if (hex.StatusCode == HttpStatusCode.Forbidden) { throw new ProxyPermission(hex); } if (hex.StatusCode == HttpStatusCode.GatewayTimeout) { throw new ProxyTimeout(hex.Message, hex); } throw new ProxyException( $"Remote proxy device method communication failure: {hex.StatusCode}.", hex); } catch (OperationCanceledException) { throw; } catch (Exception ex) { ProxyEventSource.Log.HandledExceptionAsError(this, ex); throw new ProxyException($"Unknown proxy failure.", ex); } #if LOG_MESSAGES finally { System.Diagnostics.Trace.TraceInformation( $" > {sw.Elapsed} < for InvokeDeviceMethodAsync({message})"); } #endif if (response.Status != 200) { throw ProxyEventSource.Log.Rethrow( new ProxyException($"Unexpected status {response.Status} returned by proxy.")); } return(response.Payload); }