From 620b7c6604a9c3524d98570caa10e444cb785391 Mon Sep 17 00:00:00 2001 From: Abhipsa Misra Date: Mon, 1 May 2023 17:29:41 -0700 Subject: [PATCH] inherit from DirectMethodRequest --- .../EdgeModuleMethodSample.cs | 6 ++--- .../src/DirectMethod/DirectMethodRequest.cs | 13 +++------- .../EdgeModuleDirectMethodRequest.cs | 25 +++++++++++++++++++ iothub/device/src/IotHubClientOptions.cs | 2 +- iothub/device/src/IotHubModuleClient.cs | 6 ++--- .../ConnectionStateDelegatingHandler.cs | 2 +- .../src/Pipeline/DefaultDelegatingHandler.cs | 2 +- .../src/Pipeline/ExceptionRemappingHandler.cs | 2 +- .../device/src/Pipeline/IDelegatingHandler.cs | 2 +- .../src/Pipeline/RetryDelegatingHandler.cs | 2 +- .../Transport/Http/HttpTransportHandler.cs | 4 +-- .../tests/IotHubModuleClientDisposeTests.cs | 4 +-- .../device/tests/IotHubModuleClientTests.cs | 6 ++--- 13 files changed, 48 insertions(+), 28 deletions(-) create mode 100644 iothub/device/src/DirectMethod/EdgeModuleDirectMethodRequest.cs diff --git a/iothub/device/samples/getting started/EdgeModuleMethodSample/EdgeModuleMethodSample.cs b/iothub/device/samples/getting started/EdgeModuleMethodSample/EdgeModuleMethodSample.cs index 5f9a758b3e..03729cb5d1 100644 --- a/iothub/device/samples/getting started/EdgeModuleMethodSample/EdgeModuleMethodSample.cs +++ b/iothub/device/samples/getting started/EdgeModuleMethodSample/EdgeModuleMethodSample.cs @@ -12,8 +12,8 @@ namespace Microsoft.Azure.Devices.Client.Samples public class EdgeModuleMethodSample { private readonly IotHubModuleClient _moduleClient; - private string _deviceId; - private string _moduleId; + private readonly string _deviceId; + private readonly string _moduleId; private readonly TimeSpan? _maxRunTime; public EdgeModuleMethodSample(IotHubModuleClient moduleClient, string deviceId, string moduleId, TimeSpan? maxRunTime) @@ -54,7 +54,7 @@ public async Task RunSampleAsync() } // Invoking a direct method request to the module itself. - var directMethodRequest = new DirectMethodRequest("ModuleToModule"); + var directMethodRequest = new EdgeModuleDirectMethodRequest("ModuleToModule"); await _moduleClient.InvokeMethodAsync(_deviceId, _moduleId, directMethodRequest, cts.Token); // You can unsubscribe from receiving a callback for direct methods by setting a null callback handler. diff --git a/iothub/device/src/DirectMethod/DirectMethodRequest.cs b/iothub/device/src/DirectMethod/DirectMethodRequest.cs index cc9af7c40b..8f96d4a911 100644 --- a/iothub/device/src/DirectMethod/DirectMethodRequest.cs +++ b/iothub/device/src/DirectMethod/DirectMethodRequest.cs @@ -24,12 +24,11 @@ internal DirectMethodRequest() /// /// Initialize an instance of this class. /// - /// The method name to invoke. /// - /// A direct method request can only be made by the service or a module; - /// a device client app will not need to instantiate this class. + /// This class can be inherited from and set by unit tests for mocking purposes. /// - public DirectMethodRequest(string methodName) + /// The method name to invoke. + protected internal DirectMethodRequest(string methodName) { MethodName = methodName; } @@ -84,12 +83,8 @@ public DirectMethodRequest(string methodName) /// /// The direct method payload. /// - /// - /// The direct method request payload is to be set by the client application only when using - /// to invoke a direct method on an edge device or on an edge module. - /// [JsonProperty("payload", NullValueHandling = NullValueHandling.Include)] - public byte[] Payload { get; set; } + protected internal byte[] Payload { get; set; } /// /// The convention to use with the direct method payload. diff --git a/iothub/device/src/DirectMethod/EdgeModuleDirectMethodRequest.cs b/iothub/device/src/DirectMethod/EdgeModuleDirectMethodRequest.cs new file mode 100644 index 0000000000..4480b01ad4 --- /dev/null +++ b/iothub/device/src/DirectMethod/EdgeModuleDirectMethodRequest.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Azure.Devices.Client +{ + /// + /// Parameters to execute a direct method on an edge device or an edge module by an . + /// + public class EdgeModuleDirectMethodRequest : DirectMethodRequest + { + /// + /// A direct method request to be initialized by the client application when using an for invoking + /// a direct method on an edge device or an edge module connected to the same edge hub. + /// + /// The method name to invoke. + /// The direct method payload. + public EdgeModuleDirectMethodRequest(string methodName, object payload = default) + : base(methodName) + { + Payload = payload == null + ? null + : PayloadConvention.GetObjectBytes(payload); + } + } +} diff --git a/iothub/device/src/IotHubClientOptions.cs b/iothub/device/src/IotHubClientOptions.cs index fd6001d3ac..59389ae001 100644 --- a/iothub/device/src/IotHubClientOptions.cs +++ b/iothub/device/src/IotHubClientOptions.cs @@ -58,7 +58,7 @@ public IotHubClientOptions(IotHubClientTransportSettings transportSettings) /// /// All file upload operations take place over HTTP regardless of the configured protocol. /// Additionally, all direct method invoking operations (such as - /// ) + /// ) /// take place over HTTP as well. The settings provided in this class will be used for all these operations. /// public IotHubClientHttpSettings HttpOperationTransportSettings { get; set; } = new IotHubClientHttpSettings(); diff --git a/iothub/device/src/IotHubModuleClient.cs b/iothub/device/src/IotHubModuleClient.cs index 36ba211a18..ffa67d8ba4 100644 --- a/iothub/device/src/IotHubModuleClient.cs +++ b/iothub/device/src/IotHubModuleClient.cs @@ -206,7 +206,7 @@ public async Task SendMessagesToRouteAsync(string outputName, IEnumerableThe operation has been canceled. /// An error occured when communicating with IoT hub service. /// The client has been disposed. - public Task InvokeMethodAsync(string deviceId, DirectMethodRequest methodRequest, CancellationToken cancellationToken = default) + public Task InvokeMethodAsync(string deviceId, EdgeModuleDirectMethodRequest methodRequest, CancellationToken cancellationToken = default) { Argument.AssertNotNullOrWhiteSpace(deviceId, nameof(deviceId)); Argument.AssertNotNull(methodRequest, nameof(methodRequest)); @@ -235,7 +235,7 @@ public Task InvokeMethodAsync(string deviceId, DirectMetho /// The operation has been canceled. /// An error occured when communicating with IoT hub service. /// The client has been disposed. - public Task InvokeMethodAsync(string deviceId, string moduleId, DirectMethodRequest methodRequest, CancellationToken cancellationToken = default) + public Task InvokeMethodAsync(string deviceId, string moduleId, EdgeModuleDirectMethodRequest methodRequest, CancellationToken cancellationToken = default) { Argument.AssertNotNullOrWhiteSpace(deviceId, nameof(deviceId)); Argument.AssertNotNullOrWhiteSpace(moduleId, nameof(moduleId)); @@ -245,7 +245,7 @@ public Task InvokeMethodAsync(string deviceId, string modu return InvokeMethodAsync(GetModuleMethodUri(deviceId, moduleId), methodRequest, cancellationToken); } - private async Task InvokeMethodAsync(Uri uri, DirectMethodRequest methodRequest, CancellationToken cancellationToken = default) + private async Task InvokeMethodAsync(Uri uri, EdgeModuleDirectMethodRequest methodRequest, CancellationToken cancellationToken = default) { methodRequest.PayloadConvention = _clientOptions.PayloadConvention; DirectMethodResponse result = await InnerHandler.InvokeMethodAsync(methodRequest, uri, cancellationToken).ConfigureAwait(false); diff --git a/iothub/device/src/Pipeline/ConnectionStateDelegatingHandler.cs b/iothub/device/src/Pipeline/ConnectionStateDelegatingHandler.cs index 74c6cb5edb..4e08ac07cd 100644 --- a/iothub/device/src/Pipeline/ConnectionStateDelegatingHandler.cs +++ b/iothub/device/src/Pipeline/ConnectionStateDelegatingHandler.cs @@ -429,7 +429,7 @@ await ValidateStateAndPerformOperationAsync( } } - public override async Task InvokeMethodAsync(DirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) + public override async Task InvokeMethodAsync(EdgeModuleDirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) { if (Logging.IsEnabled) Logging.Enter(this, methodInvokeRequest.RequestId, uri, cancellationToken, nameof(InvokeMethodAsync)); diff --git a/iothub/device/src/Pipeline/DefaultDelegatingHandler.cs b/iothub/device/src/Pipeline/DefaultDelegatingHandler.cs index ebc1ae9910..4b73d8ad19 100644 --- a/iothub/device/src/Pipeline/DefaultDelegatingHandler.cs +++ b/iothub/device/src/Pipeline/DefaultDelegatingHandler.cs @@ -142,7 +142,7 @@ public virtual Task CompleteFileUploadAsync(FileUploadCompletionNotification not return NextHandler?.CompleteFileUploadAsync(notification, cancellationToken) ?? Task.CompletedTask; } - public virtual Task InvokeMethodAsync(DirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) + public virtual Task InvokeMethodAsync(EdgeModuleDirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) { ThrowIfDisposed(); return NextHandler?.InvokeMethodAsync(methodInvokeRequest, uri, cancellationToken) ?? Task.FromResult(null); diff --git a/iothub/device/src/Pipeline/ExceptionRemappingHandler.cs b/iothub/device/src/Pipeline/ExceptionRemappingHandler.cs index 9f95da35cb..1cfe420cd0 100644 --- a/iothub/device/src/Pipeline/ExceptionRemappingHandler.cs +++ b/iothub/device/src/Pipeline/ExceptionRemappingHandler.cs @@ -110,7 +110,7 @@ public override Task CompleteFileUploadAsync(FileUploadCompletionNotification no return ExecuteWithExceptionRemappingAsync(() => base.CompleteFileUploadAsync(notification, cancellationToken)); } - public override Task InvokeMethodAsync(DirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) + public override Task InvokeMethodAsync(EdgeModuleDirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) { return RunWithExceptionRemappingAsync(() => base.InvokeMethodAsync(methodInvokeRequest, uri, cancellationToken)); } diff --git a/iothub/device/src/Pipeline/IDelegatingHandler.cs b/iothub/device/src/Pipeline/IDelegatingHandler.cs index 6f3b042aa7..525b27e487 100644 --- a/iothub/device/src/Pipeline/IDelegatingHandler.cs +++ b/iothub/device/src/Pipeline/IDelegatingHandler.cs @@ -50,7 +50,7 @@ internal interface IDelegatingHandler : IContinuationProvider InvokeMethodAsync(DirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken); + Task InvokeMethodAsync(EdgeModuleDirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken); // Sas token validity Task RefreshSasTokenAsync(CancellationToken cancellationToken); diff --git a/iothub/device/src/Pipeline/RetryDelegatingHandler.cs b/iothub/device/src/Pipeline/RetryDelegatingHandler.cs index b68699866d..f9e728afeb 100644 --- a/iothub/device/src/Pipeline/RetryDelegatingHandler.cs +++ b/iothub/device/src/Pipeline/RetryDelegatingHandler.cs @@ -483,7 +483,7 @@ await _internalRetryHandler } } - public override async Task InvokeMethodAsync(DirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) + public override async Task InvokeMethodAsync(EdgeModuleDirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) { if (Logging.IsEnabled) Logging.Enter(this, methodInvokeRequest.RequestId, uri, cancellationToken, nameof(InvokeMethodAsync)); diff --git a/iothub/device/src/Transport/Http/HttpTransportHandler.cs b/iothub/device/src/Transport/Http/HttpTransportHandler.cs index 04bb9c28ed..877dd9784e 100644 --- a/iothub/device/src/Transport/Http/HttpTransportHandler.cs +++ b/iothub/device/src/Transport/Http/HttpTransportHandler.cs @@ -74,7 +74,7 @@ await _httpClientHelper // This is for invoking methods from an edge module to another edge device or edge module. public override async Task InvokeMethodAsync( - DirectMethodRequest methodInvokeRequest, + EdgeModuleDirectMethodRequest methodInvokeRequest, Uri uri, CancellationToken cancellationToken) { @@ -89,7 +89,7 @@ public override async Task InvokeMethodAsync( }; return await _httpClientHelper - .PostAsync( + .PostAsync( uri, methodInvokeRequest, customHeaders, diff --git a/iothub/device/tests/IotHubModuleClientDisposeTests.cs b/iothub/device/tests/IotHubModuleClientDisposeTests.cs index 5c32b5cda6..b860a67758 100644 --- a/iothub/device/tests/IotHubModuleClientDisposeTests.cs +++ b/iothub/device/tests/IotHubModuleClientDisposeTests.cs @@ -143,7 +143,7 @@ public async Task IotHubModuleClient_SendMessagesToRouteAsync_ThrowsWhenClientIs public async Task IotHubModuleClient_InvokeMethodAsync_ThrowsWhenClientIsDisposed() { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); - Func op = async () => await s_client.InvokeMethodAsync("deviceId", new DirectMethodRequest(), cts.Token).ConfigureAwait(false); + Func op = async () => await s_client.InvokeMethodAsync("deviceId", new EdgeModuleDirectMethodRequest("fakeMethodName"), cts.Token).ConfigureAwait(false); await op.Should().ThrowAsync().ConfigureAwait(false); } @@ -151,7 +151,7 @@ public async Task IotHubModuleClient_InvokeMethodAsync_ThrowsWhenClientIsDispose public async Task IotHubModuleClient_InvokeMethodAsync_ToModule_ThrowsWhenClientIsDisposed() { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); - Func op = async () => await s_client.InvokeMethodAsync("deviceId", "moduleId", new DirectMethodRequest(), cts.Token).ConfigureAwait(false); + Func op = async () => await s_client.InvokeMethodAsync("deviceId", "moduleId", new EdgeModuleDirectMethodRequest("fakeMethodName"), cts.Token).ConfigureAwait(false); await op.Should().ThrowAsync().ConfigureAwait(false); } } diff --git a/iothub/device/tests/IotHubModuleClientTests.cs b/iothub/device/tests/IotHubModuleClientTests.cs index 71dc429d68..160c522972 100644 --- a/iothub/device/tests/IotHubModuleClientTests.cs +++ b/iothub/device/tests/IotHubModuleClientTests.cs @@ -194,7 +194,7 @@ public async Task IotHubModuleClient_InvokeMethodAsync_EdgeDevice_NullMethodRequ { // arrange await using var moduleClient = new IotHubModuleClient(s_fakeConnectionString); - var DirectMethodRequest = new DirectMethodRequest("TestMethodName") + var DirectMethodRequest = new EdgeModuleDirectMethodRequest("TestMethodName") { PayloadConvention = DefaultPayloadConvention.Instance, }; @@ -211,7 +211,7 @@ public async Task IotHubModuleClient_InvokeMethodAsync_EdgeModule_NullMethodRequ { // arrange await using var moduleClient = new IotHubModuleClient(s_fakeConnectionString); - var DirectMethodRequest = new DirectMethodRequest("TestMethodName") + var DirectMethodRequest = new EdgeModuleDirectMethodRequest("TestMethodName") { PayloadConvention = DefaultPayloadConvention.Instance, }; @@ -228,7 +228,7 @@ public async Task IotHubModuleClient_InvokeMethodAsync_WithoutExplicitOpenAsync_ { // arrange await using var moduleClient = new IotHubModuleClient(s_fakeConnectionString); - var DirectMethodRequest = new DirectMethodRequest("TestMethodName") + var DirectMethodRequest = new EdgeModuleDirectMethodRequest("TestMethodName") { PayloadConvention = DefaultPayloadConvention.Instance, };