Intro
This time, I will try communicating with SignalR from Unity applications.
For server side, I will use the application what I created last time.
Environments
- Unity ver.2020.2.1f1
- Microsoft.AspNetCore.SignalR.Client ver.5.0.4
- nuget.exe ver.5.8.1
AspNetCore.SignalR.Client
I can connect SignalR hub by AspNetCore.SignalR.Client.
I used JavaScript(TypeScript) version last time.
This time, I use C# version.
Though this library is named "AspNetCore", it complies .NET Standard.
So I can use it from WPF, Unity, and so on like the article above.
Use AspNetCore.SignalR.Client from Unity
How to install?
One important problem is I can't use NuGet for Unity applications.
So I must put dlls into the Assets/Plugins folder manually.
First, I tried installing AspNetCore.SignalR.Client in a .NET 5 console application, and copying dlls.
But the dlls were complied .NET Standard 2.1.
Because Unity applications only could use .NET Standard 2.0.
So I used NuGet of commandline version.
I just installed nuget.exe and executed "./nuget install Microsoft.AspNetCore.SignalR.Client".
Copy dlls
After installing, I could get packages.
And there were some dlls for several platforms.
So I copied netstandard2.0 one.
First, I copied "Microsoft.AspNetCore.SignalR.Client.Core.dll" and got errors.
It was because lacking of dependencies. So I copied them.
When I couldn't get .NET Standard2.0 packages, I copied older one.
Copied dlls
- Microsoft.AspNetCore.Http.Connections.Client.dll
- Microsoft.AspNetCore.Http.Connections.Common.dll
- Microsoft.AspNetCore.Http.Features.dll
- Microsoft.AspNetCore.SignalR.Client.Core.dll
- Microsoft.AspNetCore.SignalR.Client.dll
- Microsoft.AspNetCore.SignalR.Common.dll
- Microsoft.AspNetCore.SignalR.Protocols.Json.dll
- Microsoft.Bcl.AsyncInterfaces.dll
- Microsoft.Extensions.DependencyInjection.Abstractions.dll
- Microsoft.Extensions.DependencyInjection.dll
- Microsoft.Extensions.Logging.Abstractions.dll
- Microsoft.Extensions.Logging.dll
- Microsoft.Extensions.Options.dll
- Microsoft.Extensions.Primitives.dll
- System.Buffers.dll
- System.Diagnostics.DiagnosticSource.dll
- System.IO.Pipelines.dll
- System.Memory.dll
- System.Runtime.CompilerServices.Unsafe.dll
- System.Text.Encodings.Web.dll
- System.Text.Json.dll
- System.Threading.Channels.dll
System.Threading.Tasks.Extensions.dll
Communicate with SignalR
MainPage.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using Microsoft.AspNetCore.SignalR.Client;
public class MainPage : MonoBehaviour
{
public Text ReceivedText;
public InputField MessageInput;
public Button SendButton;
private SignalRConnector connector;
public async Task Start()
{
connector = new SignalRConnector();
connector.OnMessageReceived += UpdateReceivedMessages;
await connector.InitAsync();
SendButton.onClick.AddListener(SendMessage);
}
private void UpdateReceivedMessages(Message newMessage)
{
var lastMessages = this.ReceivedText.text;
if(string.IsNullOrEmpty(lastMessages) == false)
{
lastMessages += "\n";
}
lastMessages += $"User:{newMessage.UserName} Message:{newMessage.Text}";
this.ReceivedText.text = lastMessages;
}
private async void SendMessage()
{
await connector.SendMessageAsync(new Message
{
UserName = "Example",
Text = MessageInput.text,
});
}
}
Message.cs
public class Message
{
public string UserName { get; set; }
public string Text { get; set; }
}
SignalRConnector.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using Microsoft.AspNetCore.SignalR.Client;
public class SignalRConnector
{
public Action<Message> OnMessageReceived;
private HubConnection connection;
public async Task InitAsync()
{
connection = new HubConnectionBuilder()
.WithUrl("http://localhost:5000/chatHub")
.Build();
connection.On<string, string>("ReceiveMessage", (user, message) =>
{
OnMessageReceived?.Invoke(new Message
{
UserName = user,
Text = message,
});
});
await StartConnectionAsync();
}
public async Task SendMessageAsync(Message message)
{
try
{
await connection.InvokeAsync("SendMessage",
message.UserName, message.Text);
}
catch (Exception ex)
{
UnityEngine.Debug.LogError($"Error {ex.Message}");
}
}
private async Task StartConnectionAsync()
{
try
{
await connection.StartAsync();
}
catch (Exception ex)
{
UnityEngine.Debug.LogError($"Error {ex.Message}");
}
}
}
--- 2021-04-01 Update ---
IL2CPP
When I set "Scripting Backent" to "IL2CPP", I will get error.
Because some classes are removed.
For avoiding this problem, I add "link.xml" into the Assets folder.
link.xml
<linker>
<assembly fullname="Microsoft.AspNetCore.Connections.Abstractions" preserve="all"/>
<assembly fullname="Microsoft.AspNetCore.Http.Connections.Client" preserve="all"/>
<assembly fullname="Microsoft.AspNetCore.Http.Connections.Common" preserve="all"/>
<assembly fullname="Microsoft.AspNetCore.Http.Features" preserve="all"/>
<assembly fullname="Microsoft.AspNetCore.SignalR.Client.Core" preserve="all"/>
<assembly fullname="Microsoft.AspNetCore.SignalR.Client" preserve="all"/>
<assembly fullname="Microsoft.AspNetCore.SignalR.Common" preserve="all"/>
<assembly fullname="Microsoft.AspNetCore.SignalR.Protocols.Json" preserve="all"/>
<assembly fullname="Microsoft.Bcl.AsyncInterfaces" preserve="all"/>
<assembly fullname="Microsoft.Extensions.DependencyInjection.Abstractions" preserve="all"/>
<assembly fullname="Microsoft.Extensions.DependencyInjection" preserve="all"/>
<assembly fullname="Microsoft.Extensions.Logging.Abstractions" preserve="all"/>
<assembly fullname="Microsoft.Extensions.Logging" preserve="all"/>
<assembly fullname="Microsoft.Extensions.Options" preserve="all"/>
<assembly fullname="Microsoft.Extensions.Primitives" preserve="all"/>
<assembly fullname="System.Buffers" preserve="all"/>
<assembly fullname="System.Diagnostics.DiagnosticSource" preserve="all"/>
<assembly fullname="System.IO.Pipelines" preserve="all"/>
<assembly fullname="System.Memory" preserve="all"/>
<assembly fullname="System.Runtime.CompilerServices.Unsafe" preserve="all"/>
<assembly fullname="System.Text.Encodings.Web" preserve="all"/>
<assembly fullname="System.Text.Json" preserve="all"/>
<assembly fullname="System.Threading.Channels" preserve="all"/>
<assembly fullname="System.Threading.Tasks.Extensions" preserve="all"/>
</linker>