public Task SetDesiredPropertyUpdateCallbackAsync()

in iothub/device/src/ModuleClient.cs [581:892]


        public Task SetDesiredPropertyUpdateCallbackAsync(DesiredPropertyUpdateCallback callback, object userContext) =>
            InternalClient.SetDesiredPropertyUpdateCallbackAsync(callback, userContext);

        /// <summary>
        /// Set a callback that will be called whenever the client receives a state update
        /// (desired or reported) from the service.
        /// Set callback value to null to clear.
        /// </summary>
        /// <remarks>
        /// This has the side-effect of subscribing to the PATCH topic on the service.
        /// </remarks>
        /// <param name="callback">Callback to call after the state update has been received and applied.</param>
        /// <param name="userContext">Context object that will be passed into callback.</param>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        public Task SetDesiredPropertyUpdateCallbackAsync(DesiredPropertyUpdateCallback callback, object userContext, CancellationToken cancellationToken) =>
            InternalClient.SetDesiredPropertyUpdateCallbackAsync(callback, userContext, cancellationToken);

        /// <summary>
        /// Retrieve a module twin object for the current module.
        /// </summary>
        /// <returns>The module twin object for the current module</returns>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        public Task<Twin> GetTwinAsync() => InternalClient.GetTwinAsync();

        /// <summary>
        /// Retrieve a module twin object for the current module.
        /// </summary>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The module twin object for the current module</returns>
        public Task<Twin> GetTwinAsync(CancellationToken cancellationToken) => InternalClient.GetTwinAsync(cancellationToken);

        /// <summary>
        /// Push reported property changes up to the service.
        /// </summary>
        /// <param name="reportedProperties">Reported properties to push.</param>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        public Task UpdateReportedPropertiesAsync(TwinCollection reportedProperties) =>
            InternalClient.UpdateReportedPropertiesAsync(reportedProperties);

        /// <summary>
        /// Push reported property changes up to the service.
        /// </summary>
        /// <param name="reportedProperties">Reported properties to push.</param>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        public Task UpdateReportedPropertiesAsync(TwinCollection reportedProperties, CancellationToken cancellationToken) =>
            InternalClient.UpdateReportedPropertiesAsync(reportedProperties, cancellationToken);

        #region Module Specific API

        // APIs that are available only in module client

        /// <summary>
        /// Sends an event to IoT hub.
        /// </summary>
        /// <remarks>
        /// In case of a transient issue, retrying the operation should work. In case of a non-transient issue, inspect the error details and take steps accordingly.
        /// Please note that the above list is not exhaustive.
        /// </remarks>
        /// <param name="outputName">The output target for sending the given message.</param>
        /// <param name="message">The message to send.</param>
        /// <exception cref="ArgumentNullException">Thrown when a required parameter is null.</exception>
        /// <exception cref="TimeoutException">Thrown if the service does not respond to the request within the timeout specified for the operation.
        /// The timeout values are largely transport protocol specific. Check the corresponding transport settings to see if they can be configured.
        /// The operation timeout for the client can be set using <see cref="OperationTimeoutInMilliseconds"/>.</exception>
        /// <exception cref="IotHubCommunicationException">Thrown if the client encounters a transient retryable exception. </exception>
        /// <exception cref="SocketException">Thrown if a socket error occurs.</exception>
        /// <exception cref="WebSocketException">Thrown if an error occurs when performing an operation on a WebSocket connection.</exception>
        /// <exception cref="IOException">Thrown if an I/O error occurs.</exception>
        /// <exception cref="ClosedChannelException">Thrown if the MQTT transport layer closes unexpectedly.</exception>
        /// <exception cref="IotHubException">Thrown if an error occurs when communicating with IoT hub service.
        /// If <see cref="IotHubException.IsTransient"/> is set to <c>true</c> then it is a transient exception.
        /// If <see cref="IotHubException.IsTransient"/> is set to <c>false</c> then it is a non-transient exception.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The message containing the event</returns>
        public Task SendEventAsync(string outputName, Message message) =>
            InternalClient.SendEventAsync(outputName, message);

        /// <summary>
        /// Sends an event to IoT hub.
        /// </summary>
        /// <remarks>
        /// In case of a transient issue, retrying the operation should work. In case of a non-transient issue, inspect the error details and take steps accordingly.
        /// Please note that the above list is not exhaustive.
        /// </remarks>
        /// <param name="outputName">The output target for sending the given message.</param>
        /// <param name="message">The message to send.</param>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="ArgumentNullException">Thrown when a required parameter is null.</exception>
        /// <exception cref="OperationCanceledException">Thrown if the service does not respond to the request before the expiration of the passed <see cref="CancellationToken"/>.
        /// If a cancellation token is not supplied to the operation call, a cancellation token with an expiration time of 4 minutes is used.
        /// </exception>
        /// <exception cref="IotHubCommunicationException">Thrown if the client encounters a transient retryable exception. </exception>
        /// <exception cref="SocketException">Thrown if a socket error occurs.</exception>
        /// <exception cref="WebSocketException">Thrown if an error occurs when performing an operation on a WebSocket connection.</exception>
        /// <exception cref="IOException">Thrown if an I/O error occurs.</exception>
        /// <exception cref="ClosedChannelException">Thrown if the MQTT transport layer closes unexpectedly.</exception>
        /// <exception cref="IotHubException">Thrown if an error occurs when communicating with IoT hub service.
        /// If <see cref="IotHubException.IsTransient"/> is set to <c>true</c> then it is a transient exception.
        /// If <see cref="IotHubException.IsTransient"/> is set to <c>false</c> then it is a non-transient exception.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The message containing the event</returns>
        public Task SendEventAsync(string outputName, Message message, CancellationToken cancellationToken) =>
            InternalClient.SendEventAsync(outputName, message, cancellationToken);

        /// <summary>
        /// Sends a batch of events to IoT hub. Use AMQP or HTTPs for a true batch operation.
        /// </summary>
        /// <remarks>
        /// MQTT will just send the messages one after the other as it does not support true batching.
        /// For more information on IoT Edge module routing <see href="https://docs.microsoft.com/azure/iot-edge/module-composition?view=iotedge-2018-06#declare-routes"/>
        /// </remarks>
        /// <param name="outputName">The output target for sending the given message.</param>
        /// <param name="messages">A list of one or more messages to send.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The task containing the event</returns>
        public Task SendEventBatchAsync(string outputName, IEnumerable<Message> messages) =>
            InternalClient.SendEventBatchAsync(outputName, messages);

        /// <summary>
        /// Sends a batch of events to IoT hub. Use AMQP or HTTPs for a true batch operation. MQTT will just send the messages one after the other.
        /// For more information on IoT Edge module routing <see href="https://docs.microsoft.com/azure/iot-edge/module-composition?view=iotedge-2018-06#declare-routes"/>
        /// </summary>
        /// <param name="outputName">The output target for sending the given message.</param>
        /// <param name="messages">A list of one or more messages to send.</param>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The task containing the event</returns>
        public Task SendEventBatchAsync(string outputName, IEnumerable<Message> messages, CancellationToken cancellationToken) =>
            InternalClient.SendEventBatchAsync(outputName, messages, cancellationToken);

        /// <summary>
        /// Sets a new delegate for the particular input. If a delegate is already associated with
        /// the input, it will be replaced with the new delegate.
        /// </summary>
        /// <param name="inputName">The name of the input to associate with the delegate.</param>
        /// <param name="messageHandler">The delegate to be used when a message is sent to the particular inputName.</param>
        /// <param name="userContext">generic parameter to be interpreted by the client code.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The task containing the event</returns>
        public Task SetInputMessageHandlerAsync(string inputName, MessageHandler messageHandler, object userContext) =>
            InternalClient.SetInputMessageHandlerAsync(inputName, messageHandler, userContext, _isAnEdgeModule);

        /// <summary>
        /// Sets a new delegate for the particular input. If a delegate is already associated with
        /// the input, it will be replaced with the new delegate.
        /// </summary>
        /// <param name="inputName">The name of the input to associate with the delegate.</param>
        /// <param name="messageHandler">The delegate to be used when a message is sent to the particular inputName.</param>
        /// <param name="userContext">generic parameter to be interpreted by the client code.</param>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The task containing the event</returns>
        public Task SetInputMessageHandlerAsync(string inputName, MessageHandler messageHandler, object userContext, CancellationToken cancellationToken) =>
            InternalClient.SetInputMessageHandlerAsync(inputName, messageHandler, userContext, _isAnEdgeModule, cancellationToken);

        /// <summary>
        /// Sets a new default delegate which applies to all endpoints.
        /// </summary>
        /// <remarks>
        /// If a delegate is already associated with the input, it will be called, else the default delegate will be called.
        /// If a default delegate was set previously, it will be overwritten.
        /// </remarks>
        /// <param name="messageHandler">The delegate to be called when a message is sent to any input.</param>
        /// <param name="userContext">generic parameter to be interpreted by the client code.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The task containing the event</returns>
        public Task SetMessageHandlerAsync(MessageHandler messageHandler, object userContext) =>
            InternalClient.SetMessageHandlerAsync(messageHandler, userContext, _isAnEdgeModule);

        /// <summary>
        /// Sets a new default delegate which applies to all endpoints. If a delegate is already associated with
        /// the input, it will be called, else the default delegate will be called. If a default delegate was set previously,
        /// it will be overwritten.
        /// </summary>
        /// <param name="messageHandler">The delegate to be called when a message is sent to any input.</param>
        /// <param name="userContext">generic parameter to be interpreted by the client code.</param>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The task containing the event</returns>
        public Task SetMessageHandlerAsync(MessageHandler messageHandler, object userContext, CancellationToken cancellationToken) =>
            InternalClient.SetMessageHandlerAsync(messageHandler, userContext, _isAnEdgeModule, cancellationToken);

        /// <summary>
        /// Interactively invokes a method from an edge module to an edge device.
        /// Both the edge module and the edge device need to be connected to the same edge hub.
        /// </summary>
        /// <param name="deviceId">The unique identifier of the edge device to invoke the method on.</param>
        /// <param name="methodRequest">The details of the method to invoke.</param>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The result of the method invocation.</returns>
        public Task<MethodResponse> InvokeMethodAsync(string deviceId, MethodRequest methodRequest) =>
            InvokeMethodAsync(deviceId, methodRequest, CancellationToken.None);

        /// <summary>
        /// Interactively invokes a method from an edge module to an edge device.
        /// Both the edge module and the edge device need to be connected to the same edge hub.
        /// </summary>
        /// <param name="deviceId">The unique identifier of the edge device to invoke the method on.</param>
        /// <param name="methodRequest">The details of the method to invoke.</param>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The result of the method invocation.</returns>
        public Task<MethodResponse> InvokeMethodAsync(string deviceId, MethodRequest methodRequest, CancellationToken cancellationToken) =>
            InvokeMethodAsync(GetDeviceMethodUri(deviceId), methodRequest, cancellationToken);

        /// <summary>
        /// Interactively invokes a method from an edge module to a different edge module.
        /// Both of the edge modules need to be connected to the same edge hub.
        /// </summary>
        /// <param name="deviceId">The unique identifier of the device.</param>
        /// <param name="moduleId">The unique identifier of the edge module to invoke the method on.</param>
        /// <param name="methodRequest">The details of the method to invoke.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The result of the method invocation.</returns>
        public Task<MethodResponse> InvokeMethodAsync(string deviceId, string moduleId, MethodRequest methodRequest) =>
            InvokeMethodAsync(deviceId, moduleId, methodRequest, CancellationToken.None);

        /// <summary>
        /// Interactively invokes a method from an edge module to a different edge module.
        /// Both of the edge modules need to be connected to the same edge hub.
        /// </summary>
        /// <param name="deviceId">The unique identifier of the device.</param>
        /// <param name="moduleId">The unique identifier of the edge module to invoke the method on.</param>
        /// <param name="methodRequest">The details of the method to invoke.</param>
        /// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
        /// <exception cref="OperationCanceledException">Thrown when the operation has been canceled.</exception>
        /// <exception cref="ObjectDisposedException">When the client has been disposed.</exception>
        /// <returns>The result of the method invocation.</returns>
        public Task<MethodResponse> InvokeMethodAsync(string deviceId, string moduleId, MethodRequest methodRequest, CancellationToken cancellationToken) =>
            InvokeMethodAsync(GetModuleMethodUri(deviceId, moduleId), methodRequest, cancellationToken);

        private async Task<MethodResponse> InvokeMethodAsync(Uri uri, MethodRequest methodRequest, CancellationToken cancellationToken)
        {
            if (InternalClient.IsDisposed)
            {
                throw new ObjectDisposedException("IoT client", DefaultDelegatingHandler.ClientDisposedMessage);
            }

            methodRequest.ThrowIfNull(nameof(methodRequest));

            if (_httpTransportHandler == null)
            {
                Func<object, X509Certificate, X509Chain, SslPolicyErrors, bool> customCertificateValidation = _certValidator.GetCustomCertificateValidation();

                // The HTTP message handlers created in this block are disposed when this client is
                // disposed.
#pragma warning disable CA2000 // Dispose objects before losing scope
#if !NET451
                var httpMessageHandler = new HttpClientHandler();
#else
                var httpMessageHandler = new WebRequestHandler();
#endif
#pragma warning restore CA2000 // Dispose objects before losing scope

                if (customCertificateValidation != null)
                {
                    TlsVersions.Instance.SetLegacyAcceptableVersions();

#if !NET451
                    httpMessageHandler.ServerCertificateCustomValidationCallback = customCertificateValidation;
                    httpMessageHandler.SslProtocols = TlsVersions.Instance.Preferred;
#else
                    httpMessageHandler.ServerCertificateValidationCallback = (sender, certificate, chain, errors) =>
                    {
                        return customCertificateValidation(sender, certificate, chain, errors);
                    };
#endif
                }

                // We need to add the certificate to the httpTransport if DeviceAuthenticationWithX509Certificate
                if (InternalClient.Certificate != null)
                {
                    httpMessageHandler.ClientCertificates.Add(InternalClient.Certificate);
                }

                // Note that this client is ignoring any HttpTransportSettings that the user may have
                // provided. This is because the kinds of settings a user would want to override
                // aren't as applicable for this particular operation.
                var transportSettings = new Http1TransportSettings()
                {
                    HttpClient = new HttpClient(httpMessageHandler, true)
                };

                var context = new PipelineContext
                {
                    ProductInfo = new ProductInfo
                    {
                        Extra = InternalClient.ProductInfo
                    }
                };

                _httpTransportHandler = new HttpTransportHandler(context, InternalClient.IotHubConnectionString, transportSettings);
            }

            var methodInvokeRequest = new MethodInvokeRequest(methodRequest.Name, methodRequest.DataAsJson, methodRequest.ResponseTimeout, methodRequest.ConnectionTimeout);
            MethodInvokeResponse result = await _httpTransportHandler.InvokeMethodAsync(methodInvokeRequest, uri, cancellationToken).ConfigureAwait(false);
            return new MethodResponse(Encoding.UTF8.GetBytes(result.GetPayloadAsJson()), result.Status);
        }