Firebase notification(FCM) in .NET 8 with GraphQL and Rest API

Aditya Sharma - Sep 1 - - Dev Community

Introduction

Are you trying to integrate push notification in your existing backend app(web/mobile) written in dotNet?

Choosing a notification provider can be overwhelming, but if you're only targeting a mobile app, I strongly recommend opting for Firebase Cloud Messaging (FCM).

Why FCM?

It's straightforward—easy to integrate, easy to scale, and backed by Google. Firebase Cloud Messaging allows you to send real-time push notifications effortlessly.

How do we integrate it?

We can use Firebase packages to setup the notification in our backend:

Setup:

Step 1:

We need the private key before get going.
We can go to Firebase console > Either create a new project or choose an existing project. > Go to project settings > Switch to Service Accounts tab

Firebase dashboard

Click on Generate new private key
A JSON file will be downloaded which will contains all the required firebase credentials for our next move.

Step 2:

Create a new project in .NET using your favorite IDE. I prefer using Visual Studio 2022. After initialization of your new project, you need to download FirebaseAdmin nuget package. I have installed version 3.0.0

Extra: Suppose if you have different environment, (dev/qa/prod) you will generate 3 firebase json credentials and make sure to keep those files in the same directory as program.cs. We will now access these files and use it based on the environment.

Step 3:

Make sure that you use FirebaseAdmin and Google.Apis.Auth.OAuth2 namespaces.

For Production environment(Program.cs):

//The code will pick the json file based on environment.
//This block will run only in production environment.
if (app.Environment.IsProduction())
{
    FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.FromFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "xyzProjectProduction-adminsdk-abcdef.json")),
});
}
//For local development environment.
else if(app.Environment.IsDevelopment())
{
    Credential = GoogleCredential.FromFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "xyzProjectForLocal-adminsdk-abcdef.json")),
});
}
//Maybe for QA or any other environment.
else
{
    Credential = GoogleCredential.FromFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "xyzProjectQA-adminsdk-abcdef.json")),
});
}


Enter fullscreen mode Exit fullscreen mode

Note: You might be get error if you place the wrong json file name in the wrong environment. Pls make sure that you put correct file name in the correct environment.

Once your Program.cs setup is done, we are good to go ahead.

In my project, I have used graphql (Hot Chocolate) library instead of REST APIs but don't worry, I will show you both the methods. In both the methods, there will be a subtle change in the controller. Also, I have written the sample code using the repository pattern.

Using Graphql

Your AccountMutation.cs file will look something like:

[PublicAPI] //JetBrains.Annotations
[ExtendObjectType(OperationTypeNames.Mutation)] //HotChocolate.Types declaration.

public class AccountMutation
{
   //[Service] attribute is from HotChocolate.ServiceAttribute
   public async Task<bool> CreatePushNotificationAsync([Service] ICreateAccountMutationRepository repository, NotificationModel input, CancellationToken cancellationToken)
   {
       return await repository.CreateAccountNotification(input, cancellationToken);
   }
}
Enter fullscreen mode Exit fullscreen mode

Using REST APIs

Your AccountController.cs will look something like:

[ApiController]
[Route("[controller]")]
public class AccountController : ControllerBase
{
    [HttpPost]
    // Here repository will be injected through constructor
    public async Task<IActionResult> CreatePushNotificationAsync(NotificationModel input, CancellationToken cancellationToken) 
    {
        return await repository.CreateAccountNotification(input, cancellationToken);
    }
}
Enter fullscreen mode Exit fullscreen mode

Model creation:

If you want to send same notification to N devices, then you can create a model something like:

 public class MessageModel
 {
     public string Title { get; set; }
     public string Body { get; set; }
     public List<string> DeviceToken { get; set; }
     public string JsonDataString { get; set; } //In Database it is stored as Jsonb column

 }
Enter fullscreen mode Exit fullscreen mode

Hint: This messaging model has capabilities of sending message of different types. You can use an Enum to make different types of notification. We can get a list of device token and iterate to send notifications.

My SendNotificationToDeviceAsync class looks something like:


public async Task<bool> SendNotificationToDeviceAsync(MessageModel input)
{
   if (input.DeviceToken == null || input.JsonDataString == null)
   {
       return false;
   }
   foreach (var token in input.DeviceToken)
{
    try
    {
        var message = new Message()
        {
            Notification = new FirebaseAdmin.Messaging.Notification
            {
                Title = input.Title, //Title of the notification
                Body = input.Body, //Body of the notification
            },
            Data = new Dictionary<string, string>() //Extra data for the notification message. Onlick notification, we can use this data to perform various task in frontend.
            {
                ["JsonData"] = input.JsonDataString
            },
            Token = token,
            Android = new AndroidConfig()
            {
                Notification = new AndroidNotification()
                {
                    Title = input.Title,
                    Body = input.Body,
                    Sound = "Default"
                }
            }
        };

        FirebaseMessaging messaging = FirebaseMessaging.DefaultInstance; //Creating an instance

        string result = await messaging.SendAsync(message);//This SendAsync method sends your message via FCM

        if (string.IsNullOrEmpty(result))
        {
            this.logger.LogError($"{token} Device Token caused an error {result}");
        }
    }
    catch (Exception ex)
    {
        this.logger.LogError($"Error while creating notification {ex}");
    }
}
return true;
}
Enter fullscreen mode Exit fullscreen mode

We have implemented try catch block in the loop because an expired device token returns an exception and if there is an exception, we log that exception via logger services.

Conclusion

This was the demonstration of how we can implement FCM in .NET in either graphql or RestAPIs. I hope you are now able to enjoy the notification in your project. If you have any feedback, suggestions or question you can ask me out!

github, linkedIn

. . . . . . .
Terabox Video Player