Firebase Cloud Messaging with ASP.NET Core

Cedric Gabrang
5 min readAug 4, 2023

As a Senior Developer at XAM Consulting, I have previously explored how to enable a .NET MAUI application to receive push notifications from the Firebase Console. This approach is ideal for developer testing as it provides a quick and simple way to verify that push notifications are working as intended. I’ve written a blog for it; you check it out.

In this blog, I will be going to demonstrate how to implement a backend service to send push notifications to the client applications with ASP.NET Core.

The Need for a Backend Service

Scalability

Sending push notifications manually through the Firebase Console is suitable for limited testing and small-scale applications, but for applications with a large user base, a backend service can automate the process.

A backend service can expose an API endpoint that accepts notification request parameters from the client applications. These parameters may include the notification content, the target device tokens, and other relevant details.

Personalization

Notifications often need to be tailored to specific users or groups based on their preferences and interactions. A backend service can process user data and deliver personalized notifications accordingly.

There are many ways to implement a backend service to handle Firebase Cloud Messaging. However, in this post, we’ll focus on utilizing ASP.NET Core to create a backend service.

Let’s get started.

Generate private key

To establish a connection between our ASP.NET Core backend service and the Firebase Cloud Messaging (FCM) service, we need a private key.

Navigate to Firebase Console page and either create a new project or select an existing project you want to work with.

Go to the Project settings then switch to the Service accounts tab.

Click the Generate new private key then save the generated JSON file.

Create a project

Create a new ASP.NET Core Web API project and install the NuGet package FirebaseAdmin.

dotnet add package FirebaseAdmin --version 2.4.0

Next, let’s include the JSON file we have downloaded from Firebase. Copy it to the root folder of the project.

To make sure that it is copied next to the compiled binary, set its Copy to Output Directory to Copy if newer or Always copy.

In the Program class, create a new instance of FirebaseApp with the provided configuration options:

FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "mauifirebasedemo-firebase-adminsdk.json")),
});

Also, don’t forget to bring in FirebaseAdmin and Google.Apis.Auth.OAuth2 namespaces.

Add a controller

To facilitate the communication between the client applications and the backend service, you’ll need to create an API endpoint. This will serve as the bridge through which client applications can trigger the sending of push notifications.

Under the Controllers folder, create a new class called MessageController, then add a method called SendMessageAsync:

[ApiController]
[Route("[controller]")]
public class MessageController : ControllerBase
{
[HttpPost]
public async Task<IActionResult> SendMessageAsync()
{
// Implementation will be added here to handle sending push notifications
return Ok("Push notification sent successfully!");
}
}

Create a model

Create a class called MessageRequest to represent the message request parameter sent by the client applications:

public class MessageRequest
{
public string Title { get; set; }
public string Body { get; set; }
public string DeviceToken { get; set; }
// Add more properties as needed based on your notification requirements
}

Then, modify the SendMessageAsync method:

[HttpPost]
public async Task<IActionResult> SendMessageAsync([FromBody] MessageRequest request)
{
// Implementation will be added here to handle sending push notifications
return Ok("Message sent successfully!");
}

The [FromBody] attribute automatically deserializes the incoming JSON request data and bind it to the MessageRequest class.

Message Payload Types

To send push notifications, you need to construct a message payload. To create the message payload, you’ll utilize the Message class from the FirebaseAdmin SDK.

There are two primary types of message payloads you can include in an FCM request: Notification and Data.

The Notification payload is designed for displaying user-visible notifications on the device's notification tray. It typically includes the notification title, body, and other visual properties:

var message = new Message()
{
Notification = new Notification
{
Title = "Message Title",
Body = "Message Body"
},
Token = "TARGET_DEVICE_TOKEN" // Replace with the actual device token of the target device
};

The Data payload, on the other hand, is intended for sending custom data to the client application. It allows you to include key-value pairs containing any additional information you want to pass to your app:

var message = new Message()
{
Data = new Dictionary<string, string>()
{
["CustomData"] = "Custom Data"
},
Token = "TARGET_DEVICE_TOKEN" // Replace with the actual device token of the target device
};

You have the flexibility to use either payload type independently or combine them together in a single message:

var message = new Message()
{
Notification = new Notification
{
Title = "Message Title",
Body = "Message Body"
},
Data = new Dictionary<string, string>()
{
["CustomData"] = "Custom Data"
},
Token = "TARGET_DEVICE_TOKEN" // Replace with the actual device token of the target device
};

Sending a message

With the message payload constructed, it’s time to send the push notification:

var messaging = FirebaseMessaging.DefaultInstance;
var result = await messaging.SendAsync(message);

Make sure to import FirebaseAdmin.Messaging namespace.

The SendAsync method returns a string value that contains an FCM message ID if the message was sent successfully:

if (!string.IsNullOrEmpty(result))
{
// Message was sent successfully
Console.WriteLine("Message sent successfully!");
}
else
{
// There was an error sending the message
Console.WriteLine("Error sending the message.");
}

Here’s a reference for how your SendMessageAsync method should look like:

[HttpPost]
public async Task<IActionResult> SendMessageAsync([FromBody] MessageRequest request)
{
var message = new Message()
{
Notification = new Notification
{
Title = request.Title,
Body = request.Body,
},
Data = new Dictionary<string, string>()
{
["FirstName"] = "John",
["LastName"] = "Doe"
},
Token = request.DeviceToken
};

var messaging = FirebaseMessaging.DefaultInstance;
var result = await messaging.SendAsync(message);

if (!string.IsNullOrEmpty(result))
{
// Message was sent successfully
return Ok("Message sent successfully!");
}
else
{
// There was an error sending the message
throw new Exception("Error sending the message.");
}
}

That’s all you need to set up your ASP.NET Core backend service! To try it out and ensure everything is working as expected, you have a couple of options:

Consume the Endpoint

If you have a client application, you can consume the /Message endpoint you’ve set up and provide the necessary parameters, such as the Title, Body, and DeviceToken.

Try It on Postman

If you prefer a quick way to test your backend service without the need for a client application, you can use Postman. Create a new request, enter the endpoint URL, and provide the required parameters in the request body as JSON data.

Conclusion

One of the key advantages of having a backend service for push notifications is the flexibility it provides. With a backend service in place, you can integrate push notifications with other services and platforms, extending the functionality of your application.

You can check out the full source in my GitHub repo.

Happy coding!

--

--

Cedric Gabrang

Senior Developer @XAMConsulting | Xamarin, .NET MAUI, C# Developer | React Native | Twitter: @cedric_gabrang