Learn Technologies
Xamarin Forms - ChatApp SignalR

Xamarin Forms – Live Chat – SignalR

In this new tutorial, we will see together how to develop a Xamarin Forms chat application using SignalR for real-time communication.

What can you do with ASP.NET and SignalR?

While chat is often used as an example, you can do a whole lot more. Any time a user refreshes a web page to see new data, or the page implements Ajax long polling to retrieve new data, it’s candidate for using SignalR. SignalR also enables completely new types of applications that require high-frequency updates from the server, such as real-time gaming. For more details you can see the official link.

You can find the source code on GitHub.

Create ASP.NET Core project

So the asp.net Core project will host the SignalR hub, in which we’ll define the different methods to make communication between clients.

If you are beginner with Asp.net Core, you can check my tutorials on this link.

In general, the communication can be between client-server or server-server.

Let’s begin by creation new project in visual studio ASP.NET Core for Web API 5.0.

Installing the package “Microsoft.AspNetCore.SignalR.Core” from NuGet.

After that, add new folder called Hubs, in which we can define one or more signal Hub like (SyncHub, ChatHub….). Do not forget that signaling has limits, by default the message size is limited for performance raisons, you can find more details you can see SignalR performance on Microsoft documentation.

Now, add a new class called ChatHub inside the folder created previously. Your code will look like:

public class ChatHub: Hub
{
  public async Task SendMessage(string userId, string message)
  {
        await Clients.Others.SendAsync("ReceiveMessage", userId, message);
  }
}

So, the method SendMessage take 2 params the sender id and the message contant. In our case here, we ‘ill send the message to all clients subscribe to the ChatHub, that’s why, we have Clients.Others.SendAsync.

SendAsync method take 3 args, the first one represent the callback to be invoked at the subscribed clients. The 2 others are the sender id and the message.

In our case, we don’t manage the user friends list. In fact, we ‘ll make Chat Room application, every one has the url of SignalR hub, can join the chat room.

Obviously, we can manage the list of connected users and send message to group, or a dedicated friend and finally, save it in the database. More details in this link.

Now, let’s move to the Startup.cs file, and add the SignalR service in ConfigureServices method.

 public void ConfigureServices(IServiceCollection services)
 {
       services.AddControllers();
       services.AddSignalR();
       services.AddSwaggerGen(c =>
       {
               c.SwaggerDoc("v1", new OpenApiInfo { Title = "ChatApp.WebAPI", Version = "v1" });
          });
 }
  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
 {
    //.......
    //.....    
     app.UseHttpsRedirection();
     app.UseRouting();
     app.UseAuthorization();
     app.UseEndpoints(endpoints =>
     {
            endpoints.MapHub<ChatHub>("chathub");
     });
}

Xamarin Forms App

Let’s move now to the client application, create a new Xamarin Forms Prism app.

First of all, we need to add in the Main Page an entry field where user can put his name and a button to join the chat room. Bind the button with NavigateToChatPageCommand. So you Xaml code will look like:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ChatApp.Mobile.Views.MainPage"
             Title="Login ">
    <Grid RowDefinitions="*,*,*">
        <StackLayout Grid.Row="1"
                     Margin="20,0">
            <Entry Text="{Binding UserName}" Placeholder="Name"></Entry>

            <Frame Style="{StaticResource ButtonFrameStyle}" >
                <Button Style="{StaticResource ButtonStyle}"
                        Text="Join"
                        Command="{Binding NavigateToChatPageCommand}"/>
            </Frame>
        </StackLayout>
            </Grid>
</ContentPage>

And you MainPageViewModel:

public class MainPageViewModel : ViewModelBase
{
        private string userName;
        public string UserName
        {
            get => userName;
            set => SetProperty(ref userName, value);
        }
        public ICommand NavigateToChatPageCommand { get; private set; }

        public MainPageViewModel(INavigationService navigationService)
            : base(navigationService)
        {
            NavigateToChatPageCommand = new DelegateCommand(NavigateToChatPage);
        }

        private void NavigateToChatPage()
        {
            var param = new NavigationParameters { { "UserNameId", UserName } };
            NavigationService.NavigateAsync($"NavigationPage/{nameof(ChatRoomPage)}", param);
        }
}

After that, create a new Page called ChatRoomPage in which , we insert a ListView. It represents the discussion history like facebook. And Entry field where user can enter a text message.

So if the user send a message, we’ll show this message à the right with blue color else this a received message, so we show it at the left with gray color.

When user, tap send button, we use SignalR to communicate the message to server Hub, and the server dispatch the message to the subscribed clients.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="http://prismlibrary.com"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="ChatApp.Mobile.Views.ChatRoomPage"
             NavigationPage.HasNavigationBar="false">
    <Grid RowDefinitions="*, auto"
          Margin="10">
        <ListView ItemsSource="{Binding MessagesList}"
                  SeparatorVisibility="None"
                  HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid RowDefinitions="auto, auto">
                            <Grid ColumnDefinitions="40, *" IsVisible="{Binding IsOwnerMessage}">
                                <!--<Label Text="{Binding UserName}"/>-->
                                <Frame CornerRadius="30"
                                       Grid.Column="1"
                                       HorizontalOptions="End"
                                       HasShadow="True"
                                       Margin="0"
                                       BackgroundColor="{StaticResource PrimaryColor}"
                                       Padding="10">
                                    <Label Text="{Binding Message}"
                                           Margin="10"
                                           TextColor="{StaticResource WhiteColor}"
                                           LineBreakMode="WordWrap"/>
                                </Frame>
                            </Grid>
                            <Grid ColumnDefinitions="*, 40"
                                  Grid.Row="1"
                                  IsVisible="{Binding IsOwnerMessage, Converter={StaticResource  BooleanToVisibility}, ConverterParameter=Inverse}">
                                <!--<Label Text="{Binding UserName}"/>-->
                                <Frame CornerRadius="30"
                                       HasShadow="True"
                                       Margin="0"
                                       BackgroundColor="{StaticResource ElegantDarkColor}"
                                       Padding="10">
                                    <Label Text="{Binding Message}"
                                           Margin="10"
                                           TextColor="{StaticResource WhiteColor}"
                                           LineBreakMode="WordWrap"/>
                                </Frame>
                            </Grid>
                            <!--<Grid RowDefinitions="auto, auto"  >
                                <Label Text="{Binding UserName}"/>
                                <Label Text="{Binding Message}"/>
                            </Grid>-->
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <StackLayout Grid.Row="1"
                     Orientation="Horizontal">
            <Entry Text="{Binding Message}"
                   
                   HorizontalOptions="FillAndExpand"></Entry>
            <Button Text="Send" Command="{Binding SendMsgCommand}"/>
        </StackLayout>
    </Grid>

</ContentPage>
using ChatApp.Mobile.Models;
using ChatApp.Mobile.Services.Interfaces;
using Prism.Commands;
using Prism.Navigation;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;

namespace ChatApp.Mobile.ViewModels
{
    public class ChatRoomPageViewModel : ViewModelBase
    {
        private readonly IChatService chatService;

        private string userName;
        public string UserName
        {
            get => userName;
            set => SetProperty(ref userName, value);
        }

        private string message;
        public string Message
        {
            get => message;
            set => SetProperty(ref message, value);
        }


        private IEnumerable<MessageModel> messageList;
        public IEnumerable<MessageModel> MessagesList 
        { 
            get => messageList;
            set => SetProperty(ref messageList, value); 
        }
        public ICommand SendMsgCommand { get; private set; }


        public ChatRoomPageViewModel(
            INavigationService navigationService,
            IChatService chatService)
            : base(navigationService)
        {
            this.chatService = chatService;
            SendMsgCommand = new DelegateCommand(SendMsg);
        }

        public override async void Initialize(INavigationParameters parameters)
        {
            UserName = parameters.GetValue<string>("UserNameId");
            MessagesList = new List<MessageModel>();
            try
            {
                chatService.ReceiveMessage(GetMessage);
                await chatService.Connect();
            }
            catch (System.Exception exp)
            {
                throw;
            }

        }

        private void SendMsg()
        {
            chatService.SendMessage(UserName, Message);
            AddMessage(UserName, Message, true);
        }

        private void GetMessage(string userName, string message)
        {
            AddMessage(userName, message, false);
        }


        private void AddMessage(string userName, string message, bool isOwner)
        {
            var tempList = MessagesList.ToList();
            tempList.Add(new MessageModel { IsOwnerMessage = isOwner, Message = message, UseName = userName });
            MessagesList = new List<MessageModel>(tempList);
            Message = string.Empty;
        }

     
    }
}

SignalR Service

Add new folder called Services, in which you add ChatService. Define 4 methods:

  • Connect method is used to subscribe to the ChatHub.
  • Disconnect method.
  • SendMessage method is used to send the given message to the subscribed clients.
  • ReceiveMessage method is used to get the message from ChatHub sent by others clients.
using ChatApp.Mobile.Services.Interfaces;
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace ChatApp.Mobile.Services.Core
{
    public class ChatService: IChatService
    {
        private readonly HubConnection hubConnection;
        public ChatService()
        {
            hubConnection = new HubConnectionBuilder().WithUrl("http://10.0.2.2:2777/chathub").Build();
        }

        public async Task Connect()
        {
            await hubConnection.StartAsync();
        }

        public async Task Disconnect()
        {
            await hubConnection.StopAsync();
        }

        public async Task SendMessage(string userId, string message)
        {
            await hubConnection.InvokeAsync("SendMessage", userId, message);
        }

        public void ReceiveMessage(Action<string, string> GetMessageAndUser)
        {
            hubConnection.On("ReceiveMessage", GetMessageAndUser); 
        }
    }
}

Finally, deploy the application on 2 Android simulators and launch the application.

Chat App- SignalR

Chat App - SignalR

Follow Me For Updates

Subscribe to my YouTube channel or follow me on Twitter or GitHub to be notified when I post new content.

5 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x