Create a Windows module for React Native with asynchronous code in C#
Published: 2023-10-31 10:11:24

---
title: Create a Windows module for React Native with asynchronous code in C#
published: true
date: 2020-06-08 15:39:51 UTC
tags: 
canonical_url: 
---

[We have already explored on this blog](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/building-a-react-native-module-for-windows/ba-p/1067893) the opportunity to create native Windows modules for React Native. Thanks to these modules, you are able to surface native Windows APIs to JavaScript, so that you can leverage them from a React Native application running on Windows. Native modules are one of the many ways supported by React Native to build truly native applications. Despite you're using web technologies, you are able to get access to native features of the underlying platform, like notifications, storage, geolocation, etc.

 

[In the previous post](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/building-a-react-native-module-for-windows/ba-p/1067893) we have learned the basics on how to create a module in C# and how to register it in the main application, so that the C# functions are exposed as JavaScript functions. As such, in this post I won't go again into the details on how to build a module and how to register it in the Windows implementation of the React Native app. However, recently, I came across a blocker while working on a customer's project related to this scenario. My post (like the [official documentation](https://microsoft.github.io/react-native-windows/docs/native-modules)) was leveraging synchronous methods. In my scenario, instead, I needed to use the Geolocation APIs provided by Windows 10, which are asynchronous and based on the async / await pattern.

 

As such, I've started to build my module using the standard async / await pattern:

 

```
namespace GeolocationModule
{
    [ReactModule]
    class GeolocationModule
    {
        [ReactMethod("getCoordinates")]
        public async Task<string> GetCoordinates()
        {
            Geolocator geolocator = new Geolocator();
            var position = await geolocator.GetGeopositionAsync();

            string result = $"Latitude: {position.Coordinate.Point.Position.Latitude} - Longitude: {position.Coordinate.Point.Position.Longitude}";

            return result;
        }
    }
}

```

This is the traditional implementation of this pattern:

- The `GetCoordinates()` method is marked with the `async` keyword
- The `GetCoordinates()` method returns `Task<T>`, where `T` is the type of the result we want to return (in our case, its' a `string`)
- When we call an asynchronous API in the body (the `GetGeopositionAsync()` method exposed by the `Geolocator` object), we add the `await` prefix.

Then, in the React Native portion, I've created a wrapper for this module using the `NativeModules` APIs, exactly like I did in my previous sample:

 

```
export const getCoordinates = () => {
  return new Promise((resolve, reject) => {
    NativeModules.GeolocationModule.getCoordinates(function(result, error) {
      if (error) {
        reject(error);
      }
      else {
        resolve(result);
      }
    })
  })
}

```

Once I've connected all the dots and launched the React Native application, however, I was greeted with an unpleasant surprise. As soon as I hit the button which was invoking the `getCoordinates()` function, the application was crashing.

 

Thanks to a chat with [Vladimir Morozov](https://www.linkedin.com/in/vmoroz/) from the React Native team, it turned out that React Native doesn't support methods which return a `Task<T>`. In order to work properly, they must return `void`. How is it possible to achieve this goal and, at the same time, being able to keep calling asynchronous APIs, like the ones exposed by the `Geolocator` class? Thanks to Vladimir who put me on the right track, the solution is easy. Let's explore the options we have.

### Use promises

When it comes to JavaScript, I'm a big fan of [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) since they enable a syntax which is very similar to the C# one. When an asynchronous method returns a Promise, you can simply mark the function with the `async` keyword and add the `await` prefix before calling the asynchronous function, like in the following sample:

 

```
const getData = async () => {
    var result = await fetch ('this-is-a-url');
    //do something with the result
}

```

Let's start to see how we can build our module so that it can return a promise. It's easy, thanks to the `IReactPromise` interface included in the React Native implementation for Windows. Let's see some code first:

 

```
using Microsoft.ReactNative.Managed;
using System;
using Windows.Devices.Geolocation;

namespace GeolocationModule
{
    [ReactModule]
    class GeolocationModule
    {
        [ReactMethod("getCoordinatesWithPromise")]
        public async void GetCoordinatesWithPromise(IReactPromise<string> promise)
        {
            try
            {
                Geolocator geolocator = new Geolocator();
                var position = await geolocator.GetGeopositionAsync();

                string result = $"Latitude: {position.Coordinate.Point.Position.Latitude} - Longitude: {position.Coordinate.Point.Position.Longitude}";

                promise.Resolve(result);
            }
            catch (Exception e)
            {
                promise.Reject(new ReactError { Exception = e });
            }
        }
    }
}

```

As first step, we need to declare the method as `async void`, in order to be compliant with the React Native requirements. To handle the asynchronous nature of the method, the key component is the requested parameter, which type is `IReactPromise<T>`, where `T` is the type of the value we want to return. In my scenario I want to return a string with the full coordinates, so I'm using the `IReactPromise<string>` type.

 

Inside the method we can start writing our code like we would do in a traditional Windows application. Since we have marked the method with the `async` keyword, we can just call any asynchronous API (like the `GetGeopositionAsync()` one exposed by the `Geolocator` class) by adding the `await` prefix.

 

Once we have completed the work and we have obtained the result we want to return, we need to pass it to the `Resolve()` method exposed by the `IReactPromise` parameter. The method expects a value which type is equal to `T`. In my case, for example, we would get an error if we try to pass anything but a string.

 

In case something goes wrong, instead, we can use the `Reject()` method to surface the error to the React Native application, by creating a new `ReactError` object. You can customize it with different parameters, like `Code`, `Message` and `UserInfo`. In my case, I just want to raise the whole exception, so I simply set the `Exception` property exposed by my `try / catch` block.

 

That's it! Now we can easily define a function in our React Native code that, by using the `NativeModules` API and a Promise, can invoke the C# method we have just created, as in the following sample:

 

```
const getCoordinatesWithPromise = async () => {
  var coordinates = await NativeModules.GeolocationModule.getCoordinatesWithPromise();
  console.log(coordinates);
}

```

Since we're using a Promise, the syntax is the same we have seen in the previous sample. We mark the function with the `async` keyword and we call the `getCoordinatesWithPromise()` method with the `await` prefix. Thanks to the Promise we can be sure that, when we invoke the `console.log()` function, the `coordinates` property has been properly set. The native module is exposed through the `NativeModules` APIs and the `GeolocationModule` object, which is the name of the C# class we have created (if you remember, we have marked it with the `[ReactModule]` attribute).

 

### Use callbacks

I really much prefer the syntax offered by Promises but if, by any chance, you prefer to use callbacks, we got you covered! You can use, in fact, a slightly different syntax, based on the `Action<T>` object, to expose your native C# method as a callback. Let's see the implementation:

 

```
using Microsoft.ReactNative.Managed;
using System;
using Windows.Devices.Geolocation;

namespace GeolocationModule
{
    [ReactModule]
    class GeolocationModule
    {
        [ReactMethod("getCoordinatesWithCallback")]
        public async void GetCoordinatesWithCallback(Action<string> resolve, Action<string> reject)
        {
            try
            {
                Geolocator geolocator = new Geolocator();
                var position = await geolocator.GetGeopositionAsync();

                string result = $"Latitude: {position.Coordinate.Point.Position.Latitude} - Longitude: {position.Coordinate.Point.Position.Longitude}";

                resolve(result);
            }
            catch (Exception e)
            {
                reject(e.Message);
            }
        }
    }
}

```

In this case, as parameters of the method, we are passing two objects which type is `Action<T>`. The first one will be used when the method completes successfully, the second one when instead something goes wrong. In this case, `T` is a `string` in both cases. In case of success, we want to return the usual string with the full coordinates; in case of failure, we want to return the message of the exception.

 

The rest of the code is similar to the one we have written before. The only difference is that, when we have achieved our result, we just pass it to the `resolve()` function; when something goes wrong, instead, we call the `reject()` function. The main difference compared to the previous approach is that `Action<T>` isn't a structured object like the `IReactNative<T>` interface. As such, it doesn't support to pass the full exception but, in this case, we choose to pass only the `Message` property of the exception.

 

That's if from the C# side. Let's move to the JavaScript one. In this case, being a callback, we can't use anymore the `async` and `await` keywords, but we need to pass to the method two functions: one will be called when the operation is successful, one when we get an error.

 

```
const getCoordinatesWithCallback = () => {
  NativeModules.GeolocationModule.getCoordinatesWithCallback( (result) => { console.log(result); }, (error) => console.log(error));
}
```

 

### Passing parameters

In both scenarios, if we need to pass any parameter from the JavaScript code to the C# one we can just add them before the `IReactPromise<T>` or the `Action<T>` ones. For example, let's say we want to set the desired accuracy of the `Geolocator` object with a value in meters, passed from the React Native app. We can just define the method like this:

 

```
[ReactMethod("getCoordinatesWithPromise")]
public async void GetCoordinatesWithPromise(uint meters, IReactPromise <string> promise)
{
    try
    {
        Geolocator geolocator = new Geolocator();
        geolocator.DesiredAccuracyInMeters = meters;
        
       var position = await geolocator.GetGeopositionAsync();

        string result = $"Latitude: {position.Coordinate.Point.Position.Latitude} - Longitude: {position.Coordinate.Point.Position.Longitude}";

        promise.Resolve(result);
    }
    catch (Exception e)
    {
        promise.Reject(new ReactError { Exception = e });
    }
}

```

Then, from JavaScript, we just need to pass the value of the parameter when we invoke the `getCoordinatesWithPromise()` function:

 

```
const getCoordinatesWithPromise = async () => {
  var coordinates = await NativeModules.GeolocationModule.getCoordinatesWithPromise(15);
  console.log(coordinates);
}

```

Of course, you can use the same pattern if you prefer to leverage the callback approach.

 

### Wrapping up

On this blog [we have already learned](https://techcommunity.microsoft.com/t5/windows-dev-appconsult/building-a-react-native-module-for-windows/ba-p/1067893) how to build native C# modules for React Native so that, as a developer, you can access native Windows APIs from JavaScript. However, in that sample we leveraged only synchronous APIs. The reality, however, is that most of the Windows 10 APIs are implemented with the asynchronous pattern. Unfortunately, as soon as you start using them, you will face errors and crashes, since React Native isn't able to properly understand the traditional async / await pattern, based on the Task object. Thanks to the React Native team I've been pointed into the right direction, by leveraging the `IReactNative` interface (in case you want to enable asynchronous APIs with promises) or the `Action` object (in case you want to leverage the more traditional callback approach).

 

Regardless of the approach you prefer, you'll be able to achieve your goal of leveraging asynchronous Windows 10 APIs from your React Native application running on Windows:

 

![FinalApp.png](https://gxcuf89792.i.lithium.com/t5/image/serverpage/image-id/197301i6D55AC3AC86BD3EC/image-size/large?v=1.0&px=999 "FinalApp.png")