internal async Task OnMethodCalledAsync()

in iothub/device/src/InternalClient.cs [892:981]


        internal async Task OnMethodCalledAsync(MethodRequestInternal methodRequestInternal)
        {
            Tuple<MethodCallback, object> callbackContextPair = null;

            if (Logging.IsEnabled)
                Logging.Enter(this, methodRequestInternal?.Name, methodRequestInternal, nameof(OnMethodCalledAsync));

            if (methodRequestInternal == null)
            {
                return;
            }

            MethodResponseInternal methodResponseInternal = null;
            byte[] requestData = methodRequestInternal.GetBytes();

            await _methodsSemaphore.WaitAsync().ConfigureAwait(false);
            try
            {
                Utils.ValidateDataIsEmptyOrJson(requestData);
                if (!_deviceMethods.TryGetValue(methodRequestInternal.Name, out callbackContextPair))
                {
                    callbackContextPair = _deviceDefaultMethodCallback;
                }
            }
            catch (Exception ex) when (!ex.IsFatal())
            {
                if (Logging.IsEnabled)
                    Logging.Error(this, ex, nameof(OnMethodCalledAsync));

                methodResponseInternal = new MethodResponseInternal(methodRequestInternal.RequestId, (int)MethodResponseStatusCode.BadRequest);

                await SendMethodResponseAsync(methodResponseInternal, methodRequestInternal.CancellationToken).ConfigureAwait(false);

                if (Logging.IsEnabled)
                    Logging.Error(this, ex, nameof(OnMethodCalledAsync));

                return;
            }
            finally
            {
                try
                {
                    methodResponseInternal?.Dispose();
                }
                finally
                {
                    // Need to release this semaphore even if the above dispose call fails
                    _methodsSemaphore.Release();
                }
            }

            if (callbackContextPair == null)
            {
                methodResponseInternal = new MethodResponseInternal(
                    methodRequestInternal.RequestId,
                    (int)MethodResponseStatusCode.MethodNotImplemented);
            }
            else
            {
                try
                {
                    MethodResponse rv = await callbackContextPair
                        .Item1(new MethodRequest(methodRequestInternal.Name, requestData), callbackContextPair.Item2)
                        .ConfigureAwait(false);

                    methodResponseInternal = rv.Result == null
                        ? new MethodResponseInternal(methodRequestInternal.RequestId, rv.Status)
                        : new MethodResponseInternal(rv.Result, methodRequestInternal.RequestId, rv.Status);
                }
                catch (Exception ex)
                {
                    if (Logging.IsEnabled)
                        Logging.Error(this, ex, nameof(OnMethodCalledAsync));

                    methodResponseInternal = new MethodResponseInternal(methodRequestInternal.RequestId, (int)MethodResponseStatusCode.UserCodeException);
                }
            }

            try
            {
                await SendMethodResponseAsync(methodResponseInternal, methodRequestInternal.CancellationToken).ConfigureAwait(false);
            }
            finally
            {
                methodResponseInternal?.Dispose();
            }

            if (Logging.IsEnabled)
                Logging.Exit(this, methodRequestInternal.Name, methodRequestInternal, nameof(OnMethodCalledAsync));
        }