3

I am currently trying to develop simple web application for my IoT school project. As for now it should only call direct methods from my Raspberry. I am using Azure SDK for C#.

This is how code looks like:

Controller:

    public ActionResult changeState(int? id, bool enable)
    {
        string conn_str = (from u in db.Users join h in db.Hubs on
                u.Hub.HubId equals h.HubId
                where u.UserName == User.Identity.Name select h.connection_str).First();

        Cloud2Device c2d = new Cloud2Device(conn_str);

        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        Rp rp = db.Rps.SingleOrDefault(r => r.RpId == id);
        if (rp == null)
        {
            return HttpNotFound();
        }
        //IoT stuff
        try
        {
           c2d.EnableRaspberry("myDeviceId").Wait();
        }
        catch(Exception ex)
        {
           //do something
        }
        rp.is_enabled = enable;
        db.SaveChanges();
        return RedirectToAction("Index");
    }

IoT utils:

public class Cloud2Device
{
    private ServiceClient s_serviceClient;

    public Cloud2Device(string conn_str)
    {
        s_serviceClient = ServiceClient.CreateFromConnectionString(conn_str);
    }

    public async Task EnableRaspberry(string deviceId)
    {
        var methodInvocation = new CloudToDeviceMethod("EnableRaspberry") { ResponseTimeout = TimeSpan.FromSeconds(2) };

         var response = await s_serviceClient.InvokeDeviceMethodAsync(deviceId, methodInvocation);
        Debug.WriteLine(response.GetPayloadAsJson());
    }
}

The problem is that from the debug output I can see that exception Microsoft.Azure.Devices.Common.Exceptions.DeviceNotFoundException was thrown however it is not handled by try-catch block.

console output

    Application Insights Telemetry (unconfigured): "name":"Microsoft.ApplicationInsights.Dev.RemoteDependency","time":"2018-05-29T12:04:59.4748528Z","tags":{"ai.internal.sdkVersion":"rddf:2.2.0-738","ai.internal.nodeName":"5CG6455YJ4.ericsson.se","ai.cloud.roleInstance":"5CG6455YJ4.ericsson.se"},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"/twins/myDeviceId/methods","id":"8/ZMgqG4iNc=","data":"https://utiliothub.azure-devices.net/twins/myDeviceId/methods?api-version=2017-10-15","duration":"00:00:01.2380000","resultCode":"404","success":false,"type":"Http","target":"utiliothub.azure-devices.net","properties":{"DeveloperMode":"true"}}}}
    Exception thrown:'Microsoft.Azure.Devices.Common.Exceptions.DeviceNotFoundException' in Microsoft.Azure.Devices.dll
    Exception thrown:'Microsoft.Azure.Devices.Common.Exceptions.DeviceNotFoundException' in mscorlib.dll
    The thread 0x3834 has exited with code 0 (0x0).

Can anyone advise how I can catch and handle this exception in my application ? Thanks in advance for answer.

arek
  • 45
  • 4
  • Is that ok now ? – arek May 29 '18 at 12:31
  • I'm not familiar with that libraries, but it seems that exception happening outside of you `try/catch` block. For example: what does your `ServiceClient.CreateFromConnectionString(conn_str);`? – SᴇM May 29 '18 at 12:33
  • 2
    Don't use `c2d.EnableRaspberry("myDeviceId").Wait();`. Make the action asynchronous, ie change the signature to `public async Task changeState` and use `await c2d.EnableRaspberry("myDeviceId");`. Right now the code blocks one thread and runs the call on another – Panagiotis Kanavos May 29 '18 at 12:37
  • BTW `.Wait()` always throws an `AggregateException` which wraps the actual exceptions. If you don't see that in your exception message it means the error was raised by something else. You *still* haven't posted the exception text though, only the type of the Exception. Perhaps the error doesn't even come from that action? – Panagiotis Kanavos May 29 '18 at 12:39
  • Opens connection between app and IoT Hub, however it is not this line that throws exception. – arek May 29 '18 at 12:41
  • Where do you log the exception? What hides behind `//do something` ? Could it be that what you posted is only a trace message from Azure and you don't actually log the contents of the exception? – Panagiotis Kanavos May 29 '18 at 12:42
  • @PanagiotisKanavos i have tried your solution, I made action asynchronous and it helped. Thank you very much for your help ! – arek May 29 '18 at 12:50
  • @PanagiotisKanavos - How would we handle a similar scenario in WebForms? We are calling a library from aspx. The library method is async. We are using `Task.Run(()=>method()).Result;` inside WebForms and want to catch exception in WebForms. We have no try-catch in library. – Jatin Aug 24 '23 at 12:11
  • That's not async and not helpful. HTTP requests are always processed by separate threads, so what this does is freeze the current thread, use another one to do what the current one could do and only then return the results. Instead of releasing the request thread, it consumes *another* thread – Panagiotis Kanavos Aug 24 '23 at 12:16
  • If `method` itself is async, ie if it returns `Task`, the only way to not block is to use `await method()` in your code, without extra `Task.Run()`s. You can't just use async event handlers though, [you need to tell WebForms the page is async and register the tasks](https://learn.microsoft.com/en-us/aspnet/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45#CreatingAsynchGizmos). If you do that, WebForms will release the executing thread while waiting for the async work and complete the response only once the task completes – Panagiotis Kanavos Aug 24 '23 at 12:22

1 Answers1

3

I'm not sure that error output is actually an exception being thrown up to your code. It could be ApplicationInsights just logging. However, I think the code is frozen due to calling Wait and blocking the return from the async method.

Make the controller method return type Task<ActionResult>, make that method async, then use await c2d.EnableRaspberry("myDeviceId"); to call that method.

See if doing that results in an exception (or success).

TheSoftwareJedi
  • 34,421
  • 21
  • 109
  • 151