I want to implement chats in my .NET Core MVC app and I have successfully implemented sending messages using the FirebaseAdmin
package, however when trying to setup receiving messages using JS a few problems occur.
- I can not use
importScripts
in the firebase-messaging-sw.js service worker I think is neccessary. - Registering the service worker in the site.js file does not work.
- I Have to use
CDNs
because importing firebase packages into the JS normally does not work - Even when I have imported and setup everything I can not retrieve the
Firebase Token
Here is some of my code:
site.js
file inwwwroot/site.js
:
if ('serviceWorker' in navigator && 'PushManager' in window) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/firebase-messaging-sw.js')
.then(registration => {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(error => {
console.log('ServiceWorker registration failed:', error);
});
});
}
- Chats view:
@model List<ContactViewModel>
@using Market.Services.Chats
@inject IChatsService _chatsService
@{
ViewData["Title"] = "Chats";
}
<section class="chats-section">
<div class="contacts-container">
@foreach(ContactViewModel contact in Model)
{
<partial name="_ContactPartial" model="contact" />
}
</div>
<div class="chat-container">
<div id="chat-contact-info-container" class="hidden">
<h2 id="info-email"></h2>
<div class="row">
<h1 id="info-name"></h1>
<div class="contact-profile-picture">
<img id="info-picture" alt="contact-picture" />
</div>
</div>
</div>
<form class="chat-form">
<input class="chat-input" id="chat-form-input" placeholder="Type here..."/>
<button class="chat-button" id="chat-form-button" type="submit">Send</button>
</form>
</div>
</section>
<script type="module">
import { initializeApp } from 'https://www.gstatic.com/firebasejs/11.1.0/firebase-app.js';
import { getMessaging, getToken, onMessage } from 'https://www.gstatic.com/firebasejs/11.1.0/firebase-messaging.js';
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
// Request permission to receive notifications
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
console.log("Notification permission granted.");
// Get the FCM token
getToken(messaging).then((currentToken) => {
if (currentToken) {
console.log("FCM Token:", currentToken);
// You can send this token to your server for later use
} else {
console.log("No registration token available. Request permission to generate one.");
}
}).catch((err) => {
console.log("An error occurred while retrieving the token. ", err);
});
} else {
console.log("Notification permission denied.");
}
});
// Handle incoming messages (foreground)
onMessage(messaging, (payload) => {
console.log("Message received: ", payload);
});
// Handle background messages
//messaging.onBackgroundMessage((payload) => {});
</script>
<script>
let contactsData = @Html.Raw(Json.Serialize(Model));
let contacts = document.getElementsByClassName("contact-container");
let info = document.getElementById("chat-contact-info-container");
let infoEmail = document.getElementById("info-email");
let infoName = document.getElementById("info-name");
let infoPicture = document.getElementById("info-picture");
let selected = null;
Array.from(contacts).forEach(contact => {
contact.addEventListener("click", function () {
let attribute = contact.getAttribute("data-id");
info.classList.remove("hidden");
if (selected != attribute) {
selected = attribute;
// Find the selected contact using JavaScript
let selectedContact = contactsData.find(c => c.id == selected);
if (selectedContact) {
//Load profile picture
// Display the selected contact details
infoEmail.innerHTML = selectedContact.email;
infoName.innerHTML = `${selectedContact.firstName} ${selectedContact.lastName}`;
infoPicture.src = selectedContact.profilePictureURL;
console.log("Selected contact:", selectedContact);
}
}
});
});
//Sending message logic
let input = document.getElementById("chat-form-input");
let button = document.getElementById("chat-form-button");
button.addEventListener("click", async (e) => {
//Send message using service
e.preventDefault();
let selectedContact = contactsData.find(c => c.id == selected);
// Validate input
if (!input.value || !selectedContact || !selectedContact.deviceToken) {
alert("Please select a contact and enter a message.");
return;
}
const payload = {
DeviceToken: selectedContact.deviceToken, // Replace with actual token
Title: "New Message",
Body: input.value,
Id: selectedContact.id, // Replace with actual contact ID
Status: "unread" // Example status
};
console.log(payload);
try {
const response = await fetch("/Chats/Send", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
if (response.ok) {
const result = await response.json();
console.log(result.message);
alert("Message sent successfully.");
input.value = ""; // Clear the input field
} else {
console.error("Failed to send message.");
alert("Failed to send message. Please try again.");
}
} catch (error) {
console.error("Error sending message:", error);
alert("An error occurred while sending the message.");
}
});
</script>
firebase-messaging-sw.js
inwwwroot/firebase-messaging-sw.js
:
importScripts('https://www.gstatic.com/firebasejs/11.1.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/11.1.0/firebase-messaging-compat.js');
// Initialize Firebase
const firebaseConfig = {};
const messaging = firebase.messaging();
// Background message handler (commented out for now)
messaging.onBackgroundMessage(function (payload) {
console.log("Received background message ", payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: payload.notification.icon,
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
The whole project can be found here:
https://github.com/gabigoranov/farmers-market/tree/main/MarketPortal