Jay Malli
Posted on December 19, 2023
Hello Devs! Today, we'll delve into the implementation of G Suite Chat Service in .NET using C#. Our primary focus will be on the service implementation rather than the application itself. Feel free to choose any application type based on your specific requirements. For the purpose of this guide, I'll be using a .NET Maui app to demonstrate the service implementation. Let's get started on incorporating G Suite Chat functionality into your .NET projects!
Table Of Contents
Step - 1 : Initial Setup
1.1 : Get Client Id & Secret as well as access & refresh token.
=> Before we start coding, create an API key and credentials for your application in the GCP console. And after that get access_token & refresh_token by authorizing user using Oauth service. Check out this blog for step-by-step instructions: blog reference.
=> Follow steps 1 to 3 outlined in the above-mentioned blog to create a client ID and client secret.
=> Follow steps 4 to 7 outlined in the above-mentioned blog to get the access_token & refresh_token.
1.2 : Add scopes in Admin Console
=> Add the following scopes in the Admin Console under Security >> Access And Data Control >> API controls >> Domain-Wide delegation.
Note : If you encounter a '400 Invalid Scope' error, resolve it by removing the scope 'https://www.googleapis.com/auth/chat.bot' from both the Admin Console settings and any corresponding sections within your code.
=> For detailed steps on adding scopes in the Admin Console, check out this blog.
Step - 2 : Configure Our App & Services
2.1 : Add necessary NuGet packages
=> Install the NuGet package from the this website
- Google.Apis.HangoutsChat.v1 (Recommended version: 1.64.0.3230)
- Google.Apis.PeopleService.v1 (Recommended version: 1.64.0.3093)
- Google.Apis (Recommended version: 1.64.0)
- Google.Apis.Core (Recommended version: 1.64.0)
- Google.Apis.Auth (Recommended version : 1.64.0)
Note : Keep in mind that if you'll use pacakge 1.60 or below that then you'll getting this error in future : "userChatService.Spaces.List()" method is not found in given namespace , so you have to use latest version & if there are other google packages with version 1.60 or below which was creating version conflicting issue then upgrade all google pacakges with its latest version.
2.2 : Enable the required APIs
=> Enable the following Google APIs from the Google Cloud Console under APIs & Services >> Library section.
- People API
- Google Chat API
Note: To address the error, 'The service chat has thrown an exception. HttpStatusCode is NotFound. Google Chat app not found. To create a Chat app, you must turn on the Chat API and configure the app in the Google Cloud console,' configure the app in the Chat API section of the Google Cloud Console.
=> Navigate to the CONFIGURATION tab in the Google Chat API.
=> Complete the necessary details, including App name, Avatar URL, Description, and App URL in the CONFIGURATION tab of the Google Chat API. Save the changes by clicking the save button.
Step - 3 : Let's do some code
3.1 : Get User Credentials
=> Generate user credentials from the access_token to gain access to different G Suite Chat and People services for that user. Following this, initialize the user's chat service and people service.
ChatService.cs :
using Google;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.HangoutsChat.v1;
using Google.Apis.HangoutsChat.v1.Data;
using Google.Apis.PeopleService.v1;
using Google.Apis.PeopleService.v1.Data;
using Google.Apis.Services;
namespace YOUR_APP.services
{
public class ChatService
{
public HangoutsChatService _hangoutsChatService { get; set; }
public PeopleServiceService _peopleService { get; set; }
public ChatService(string access_token, string refresh_token)
{
UserCredential userCredential = GenerateCredentialFromAccessToken(access_token, refresh_token);
_peopleService = new PeopleServiceService(new BaseClientService.Initializer()
{
HttpClientInitializer = userCredential,
ApplicationName = "YOUR_APP_NAME",
});
_hangoutsChatService = new HangoutsChatService(new BaseClientService.Initializer() { HttpClientInitializer = userCredential, ApplicationName = "YOUR_APP_NAME" });
}
private UserCredential GenerateCredentialFromAccessToken(string accessToken, string refreshToken)
{
UserCredential credential;
string[] Scopes = { PeopleServiceService.Scope.Contacts, PeopleServiceService.Scope.ContactsOtherReadonly, HangoutsChatService.Scope.ChatSpaces, HangoutsChatService.Scope.ChatMessages };
TokenResponse tokenResponse = new TokenResponse
{
AccessToken = accessToken,
RefreshToken = refreshToken
};
var initializer = new GoogleAuthorizationCodeFlow.Initializer
{
// get from gcp console under API & Services >> Credentials section
ClientSecrets = new ClientSecrets
{
ClientId = "your_app_client_id",
ClientSecret = "your_app_client_secret"
},
Scopes = Scopes,
};
credential = new UserCredential(new GoogleAuthorizationCodeFlow(initializer), userId: "user", tokenResponse);
return credential;
}
3.2 : Retrive Spaces
=> Retrieve all spaces for a user, encompassing chats between two individuals, group conversations, or discussions involving multiple members within a space.
=> Identify individual user spaces with the type 'DIRECT_MESSAGE' and spaces containing multiple members with the type 'SPACE'.
ChatService.cs :
...
// other code
...
private List<Dictionary<string, string>> GetAllSpaces()
{
List<Dictionary<string, string>> spaces = new List<Dictionary<string, string>>();
try
{
SpacesResource.ListRequest req = _hangoutsChatService.Spaces.List();
req.Fields = "spaces(name,displayName,spaceType)";
ListSpacesResponse res = req.Execute();
if (res.Spaces.Count > 0)
{
foreach (Space space in res.Spaces)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("id", space.Name);
dict.Add("displayName", space.DisplayName);
dict.Add("type", space.SpaceType);
spaces.Add(dict);
}
}
}
catch (GoogleApiException ex)
{
Console.WriteLine(ex.Message);
}
return spaces;
}
3.2 : Retrive Chats
=> Retrieve chats from each space, including sender information and thread details.
ChatService.cs :
...
// other code
...
public List<Dictionary<string, string>> GetChatsOfSpace(string spaceId)
{
List<Dictionary<string, string>> chats = new List<Dictionary<string, string>>();
try
{
SpacesResource.MessagesResource.ListRequest req = _hangoutsChatService.Spaces.Messages.List(spaceId);
req.Fields = "messages(sender,text,name,thread)";
ListMessagesResponse res = req.Execute();
if (res.Messages != null)
{
foreach (Message msg in res.Messages)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("threadId", msg.Thread.Name);
dict.Add("text", msg.Text);
string senderName = GetSenderOfChat(msg.Sender.Name);
dict.Add("senderName", senderName);
chats.Add(dict);
}
}
return chats;
}
catch (GoogleApiException ex)
{
Console.WriteLine(ex.Message);
return chats;
}
}
private string GetSenderOfChat(string senderId)
{
string resourceName = senderId.Replace("users/", "people/");
PeopleResource.GetRequest req = _peopleService.People.Get(resourceName);
req.PersonFields = "names";
Person person = req.Execute();
if (person?.Names != null && person.Names.Count > 0)
{
return person.Names[0].DisplayName;
}
return "Unknown User";
}
=> If you want to explore more about the Google Chat API, including available methods, required scopes, and the request-response body of different methods, refer to this resource : Google Chat API
=> You can also refer to this documentation for the Google People API. Google People API
=> The example above demonstrates how to implement google chat/hangout service in .NET MAUI using c#, you can find the necessary code in the repository mentioned below.
Thank you for joining me on this journey of discovery and learning. If you found this blog post valuable and would like to connect further, I'd love to connect with you on LinkedIn. You can find me at LinkedIn
If you have thoughts, questions, or experiences related to this topic, please drop a comment below.
Posted on December 19, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.