我正在使用Azure IoT Edge运行时,该运行时在Windows主机OS上运行Linux容器。 我有两个模块,即ModuleA和ModuleB。 ModuleA具有注册的直接方法称为“ MethodA”,而ModuleB具有注册的直接方法称为“ MethodB”。
当我调用MethodA时,我希望该方法调用位于另一个模块(但在同一IoT Edge运行时中运行)的MethodB。
我正在将Azure IoT SDK用于c#和 在ModuleA的Init()函数中,我有:
await ioTHubModuleClient.SetMethodHandlerAsync("MethodA", MethodA, ioTHubModuleClient);
在ModuleB的Init()函数中,我有:
await ioTHubModuleClient.SetMethodHandlerAsync("MethodB", MethodB, null);
MethodA(类似于代理方法):
static async Task<MethodResponse> MethodA(MethodRequest methodRequest, object moduleClient)
{
try
{
ModuleClient ioTHubModuleClient = (ModuleClient)moduleClient;
// Get deviced id of this device, exposed as a system variable by the iot edge runtime
var deviceId = System.Environment.GetEnvironmentVariable("IOTEDGE_DEVICEID");
// Create the request
MethodRequest request = new MethodRequest("MethodB", Encoding.UTF8.GetBytes("{ \"Message\": \"Hello\" }"));
// Execute request
var resp = await ioTHubModuleClient.InvokeMethodAsync(deviceId, "ModuleB", request);
return resp;
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
return await Task.FromResult(new MethodResponse(500));
}
}
我尝试从MethodA调用的MethodB:
private static Task<MethodResponse> MethodB(MethodRequest methodRequest, object userContext)
{
Console.WriteLine("MethodB has been called");
// Get data but we do not do anything with it
var data = Encoding.UTF8.GetString(methodRequest.Data);
Console.WriteLine("Received data: " + data.ToString());
var methodResponse = new MethodResponse(Encoding.UTF8.GetBytes("{\"status\": \"ok\"}"), 200);
return Task.FromResult(methodResponse);
}
请注意,我可以从azure门户或使用Azure SDK for C#-> ServiceClient类单独调用这两种方法。
我的程序在行上崩溃
var resp = await ioTHubModuleClient.InvokeMethodAsync(deviceId, "ModuleB", request);
在MethodA和VS Code调试器中,我得到了异常
抛出异常:System.Private.CoreLib.dll中的'Microsoft.Azure.Devices.Client.Exceptions.IotHubCommunicationException'
当我查看日志的Message / StackTrace-print时,我得到:
发送请求时发生错误。 在Microsoft.Azure.Devices.Client.Transport.HttpClientHelper.d__21.MoveNext() ---从之前引发异常的位置开始的堆栈结束跟踪--- 在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在Microsoft.Azure.Devices.Client.Transport.HttpClientHelper.d__172.MoveNext() ---从之前引发异常的位置开始的堆栈结束跟踪--- 在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在Microsoft.Azure.Devices.Client.ModuleClient.d__57.MoveNext() ---从之前引发异常的位置开始的堆栈结束跟踪--- 在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在System.Runtime.CompilerServices.TaskAwaiter1.GetResult() 在/app/Program.cs:第92行的OrderGateway.Program.d__3.MoveNext()中
我尝试使用带有TCP / WebSocket_Only的Amqp以及带有TCP / WebSocket_Only的Mqtt来初始化ModuleClient。 我还尝试在Ubuntu 18.04 VM上使用这些模块运行IoT Edge运行时,但没有成功。
即使当我尝试使用ioTHubModuleClient.InvokeMethodAsync()调用位于同一模块中的方法时,也会得到相同的异常/ stacktrace ...
我还尝试从ModuleA的Init()函数调用MethodB,以尝试在回调的上下文中不调用直接方法,但是我确实得到了相同的异常。
在github上有一个未解决的问题,您可以在这里找到:https://github.com/Azure/iotedge/issues/204
但是它感觉有点停滞了,我没有得到任何帮助。
以我的理解,这应该可行,但我不知道自己缺少什么?
答案 0 :(得分:2)
我只是使这种情况起作用,但这与您的描述有些不同。
所以,这是我所做的: 1个创建的2个模块,即ModuleA和ModuleB; 2-在模块A上添加了方法A,在模块B上添加了方法B; 3-在模块B(不是模块A)上,我添加了以下代码:
while(true)
{
try
{
Console.WriteLine($"Invoking method On moduleA");
var deviceId = System.Environment.GetEnvironmentVariable("IOTEDGE_DEVICEID");
MethodRequest request = new MethodRequest("MethodA", Encoding.UTF8.GetBytes("{ \"Message\": \"Hello\" }"));
var response = await ioTHubModuleClient.InvokeMethodAsync(deviceId, "ModuleA", request).ConfigureAwait(false);
Console.WriteLine($"Received response with status {response.Status}");
}
catch (Exception ex)
{
Console.WriteLine($"Error invoking method {ex}");
}
await Task.Delay(TimeSpan.FromSeconds(20)).ConfigureAwait(false);
}
就是这样。在开始时,您会遇到类似这样的异常:
错误调用方法Microsoft.Azure.Devices.Client.Exceptions.DeviceNotFoundException:设备{“ message”:“找不到客户端angelodTransparentGateway / ModuleA”,“ exceptionMessage”:“”,“ status”:0,“ payload”: null}未注册
在Microsoft.Azure.Devices.Client.Transport.HttpClientHelper.ExecuteAsync(HttpMethod httpMethod,Uri requestUri,Func 3 modifyRequestMessageAsync, Func
2成功,Func 3 processResponseMessageAsync, IDictionary
2 errorMappingOverrides,CancellationToken cancelledToken)处
在Microsoft.Azure.Devices.Client.Transport.HttpClientHelper.PostAsync [T1,T2](Uri requestUri,T1实体,IDictionary 2 errorMappingOverrides, IDictionary
2 customHeaders,CancellationToken cancelledToken)
在Microsoft.Azure.Devices.Client.ModuleClient.InvokeMethodAsync(Uri uri,MethodRequest methodRequest,CancellationToken cancelleToken)
在/app/Program.cs:第74行的ModuleB.Program.Init()中
但这是设计使然,这只是因为部署后需要花费一些时间来创建模块,但是不到一分钟,我就能获得成功的结果:
MethodA已被调用 收到的数据:{“消息”:“你好”}
如果从ModuleA调用MethodB,则不会调用MethodA。但是为了确保它能正常工作,我还测试了模块A调用模块B的代码。
while(true)
{
try
{
Console.WriteLine($"Invoking method On moduleB");
var deviceId = System.Environment.GetEnvironmentVariable("IOTEDGE_DEVICEID");
MethodRequest request = new MethodRequest("MethodB", Encoding.UTF8.GetBytes("{ \"Message\": \"Hello\" }"));
var response = await ioTHubModuleClient.InvokeMethodAsync(deviceId, "ModuleB", request).ConfigureAwait(false);
Console.WriteLine($"Received response with status {response.Status}");
}
catch (Exception ex)
{
Console.WriteLine($"Error invoking method {ex}");
}
await Task.Delay(TimeSpan.FromSeconds(20)).ConfigureAwait(false);
}
都工作。 不要忘记使用.NET 2.1版(在dockerfile上更新它)。