I have setup a small project composed by a Console Application (my messages Hub) and a Web Application (my messages receiver).
The idea is that the Console Application listen to a RabbitMQ queue and every time a message is received, it broadcast the message to all SignalR Clients connected.
I initialize the Console App in this way:
// start Mass Transit Bus
var busControl = BuildBus();
busControl.Start();
// Start SignalR
string url = "http://localhost:9090";
using (WebApp.Start(url))
{
Console.WriteLine("SignalR Server running on {0}", url);
Console.ReadLine();
}
Then I have my Startup class and my Hub Class as following:
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
}
Now is where I get lost.
Question 1
I want from my Web Application to receive messages, so I initialize the proxy and then?
<script type="text/javascript">
$(function () {
//Set the hubs URL for the connection
$.connection.hub.url = "http://localhost:9090/signalr";
// Declare a proxy to reference the hub.
var chat = $.connection.myHub;
// Declare a Message handler
});
</script>
Question 2
From the Console Application, how do I broadcast a message to all Clients?
Answer 1 You should define client methods as chat.client.someMethod = function(someParams). In your case this client method is chat.client.addMessage = function (name, message) {}.
Answer 2 If you want broadcast some message without connection to your hub from .NET application, then you can do this in this way: GlobalHost.ConnectionManager.GetHubContext<MyHub>().Clients.All.addMessage(/*method params*/).
Related
I'm looking at incorporating Azure SignalR functionality into my .net core Blazor web application. To this end i've been following this tutorial - Azure Signalr Serverless. This is working fine - i have a project running the Azure functions app and can start up two browsers and have a chat session. What i'm trying to do is add the ability to receive these message notifications from the Azure signalR hub that's been configured into my Blazor app. I've added the following code in Index.razor.cs that mimics the javascript code in the example client:
public class IndexComponent : ComponentBase
{
private HubConnection _connection;
public string Message;
protected override Task OnInitializedAsync()
{
_connection = new HubConnectionBuilder()
.WithUrl("http://localhost:7071/api")
.Build();
_connection.On<string, string>("ReceiveMessage", (user, message) =>
{
Message = $"Got message {message} from user {user}";
this.StateHasChanged();
});
_connection.StartAsync();
return base.OnInitializedAsync();
}
}
The example javascript code btw is:
const connection = new signalR.HubConnectionBuilder()
.withUrl(`${apiBaseUrl}/api`)
.configureLogging(signalR.LogLevel.Information)
.build();
connection.on('newMessage', newMessage);
connection.onclose(() => console.log('disconnected'));
console.log('connecting...');
connection.start()
.then(() => data.ready = true)
.catch(console.error);
So the problem is that my Blazor app never receives any message notifications sent from the javascript chat clients (so the _connection.On handler is never hit). What am i missing in my Blazor code ?
Ok so this is what i needed to do to get it to work in my Blazor app:
_connection.On<object>("newMessage", update =>
{
Console.WriteLine(update);
//Message = update;
});
I needed to subscribe to the 'newMessage' target (since that's the JS is sending on) and also the type that's being posted isn't a string but a JObject type which i would need to deserialize to the correct type.
I have a WebSite integrated with SignalR. It functions well, and it has a button which sends popup notification to all clients who are online. It works well when I click on the button.
My API is in another project but in the same Solution. I want to send the above notification by calling from the API side. Basically, a mobile app will send a request to API and then API will send a notification to all online web clients.
Below code runs and not gives the notification nor any error.
Is this fundamentally correct? Appreciate your help
API code (at WebAPI project)
[HttpGet]
public IEnumerable<string> WatchMe(int record_id)
{
GMapChatHub sendmsg = new GMapChatHub();
sendmsg.sendHelpMessage(record_id.ToString());
return "Done";
}
C# code (at Web project)
namespace GMapChat
{
public class GMapChatHub : Hub
{
public void sendHelpMessage(string token)
{
var context = GlobalHost.ConnectionManager.GetHubContext<GMapChatHub>();
context.Clients.All.helpMessageReceived(token, "Test help message");
}
}
}
Home.aspx file (at Web project)
var chat = $.connection.gMapChatHub;
$(document).ready(function () {
chat.client.helpMessageReceived = function (token,msg) {
console.log("helpMessageReceived: " + msg);
$('#helpMessageBody').html(msg)
$('#helpModal').modal('toggle');
};
}
You can not call that hub directly. Firs you need to install the .net client for SignalR from nuget. Then you need to initialize it like this :
[HttpGet]
public IEnumerable<string> WatchMe(int record_id)
{
using (var hubConnection = new HubConnection("your local host address"))
{
IHubProxy proxy= hubConnection.CreateHubProxy("GMapChatHub");
await hubConnection.Start();
proxy.Invoke("sendHelpMessage",record_id.ToString()); // invoke server method
}
// return sth. IEnumerable<string>
}
And opening a new connection per request may not be good idea you may make it per session (if you use) or static or time fashioned.
I am trying to create simple SignalR hub between MVC server side and WinForms client side.
I have created NotificationHub class, specified as this:
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
namespace PF.Timesheet.Service
{
public class NotificationHub : Hub
{
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
public override Task OnConnected()
{
return base.OnConnected();
}
}
}
While code on client side is this:
var hubConnection = new HubConnection("http://localhost:30341/singalr");
var chat = hubConnection.CreateHubProxy("NotificationHub");
string message2 = string.Empty;
chat.On<string, string>("broadcastMessage", (name, message) => { message2 = message; });
chat.On<string, string>("broadcastMessage", (name, message) =>
this.Invoke((Action)(() =>
RichTextBoxConsole.AppendText(String.Format("{0}: {1}" + Environment.NewLine, name, message)));
hubConnection.Start().Wait();
I was trying to get message from broadcastMessage on any possible way, both by assigning it to some string variable 'message2' or by appending text to rich textbox control on UI.
If I make call like this:
hubConnection.Start().Wait();
I will get 401 Unauthorized response from localhost where signalr is selfhosted. (local host is running in parallel as different solution within same project as client WinForms app).
What I am trying to do on server side is to push message to hub from code like this:
var context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
context.Clients.All.broadcastMessage("NAM", "New entry created.");
If I remove Wait() from: hubConnection.Start(); I won't get Unauthorized 401 error, but I wouldn't get message value as well.
Does anybody sees what I am doing wrongly here?
Things I've tried so far:
Trying to set up EnableDetailedErrors and EnableJSONP properties to true. I have read somewhere that SignalR hub has [Authorized] attribute by default and that this configuration should help.
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
DependencyConfig.Initialize(config);
Loging.Initialize();
app.UseWebApi(config);
app.MapSignalR(new HubConfiguration
{
EnableDetailedErrors = true,
EnableJSONP = true
});
}
}
Trying to set WindowsAuth and AnonymousAuth properties for Server project to Enabled.
Checking if message was actually pushed to hub when using:
context.Clients.All.broadcastMessage("NAM", "New entry created.");
Message was there.
Did anybody passed issue with being Unauthorized and was able to read messages from MVC Server SignalR hub to WinForms client?
I managed to solve this on my own. Issue was that server (that was already setup before and not by me) had basic authentication with username and password.
This wasn't visible at all with any [Authorization] attribute or anything, but it was still there.
I solved it by setting up Credentials property on hubConfiguration:
hubConnection.Credentials = new NetworkCredential("user.name", "password");
Authentication and connection to hub was successful and message was returned from server to client.
This is my HTML:
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.khaosHub;
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (message) {
// Html encode display name and message.
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li>' + encodedMsg + '</li>');
};
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
console.log("sending");
// Call the Send method on the hub.
chat.server.send("something");
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
});
</script>
My Hub:
public class KhaosHub : Hub
{
public void Send(string message)
{
Clients.All.broadcastMessage(message);
}
}
When I click #sendmessage my Send method in KhaosHub is triggered which I have verified using a breakpoint and my message does get sent to the div via broadcastMessage.
Note: I've not included my call to app.MapSignalR in the example above as I know it's working from the client side.
The issue I have is when I call broadcastMessage from some back end code it doesn't work. I am calling it via:
var context = GlobalHost.ConnectionManager.GetHubContext<KhaosHub>();
context.Clients.All.broadcastMessage("some message");
When I debug the Clients.All property, I can't see any clients (I don't know if I should be able to but thought I'd add that information.
Any ideas?
EDIT: This is my startup class for the hub:
[assembly: OwinStartup(typeof (Startup))]
namespace CC.Web
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
Thanks for the question. Following up on the comments I have tracked my own problem down also to not getting the correct hubcontext from the GlobalHost.ConnectionManager.
To solve this I specifically set a DependencyResolver on the GlobalHost and passing this Resolver to the HubConfiguration used to MapSignalR.
In code that is:
Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver =
New Microsoft.AspNet.SignalR.DefaultDependencyResolver
app.MapSignalR(
New Microsoft.AspNet.SignalR.HubConfiguration With
{.Resolver = Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver})
You may want to convert this VB.Net code to C#.
I have implemented SignalR for my Windows Azure project. I have two clients - Javascript/HTML client in my web role and a console application in my project. And Web role is my SignalR server. When i put the web role and the console application as the start up projects, the messages i send from the HTML client are sent to the console application. But when i put the Cloud project and the console application as the start up projects, the messages from the HTML client are not being sent to the console application. Its really weird, i dont know what could be the difference between the two which is causing the problem.
And if i put a background thread in my web role which will send messages to connected clients periodically, it works on both occasions, i mean the console app and the HTML client are receiving messages irrespective of the start up projects.
Please let me know if you have any idea what the problem is
My Hub:
public class BroadcastHub : Hub
{
public void Send(PersistedAudioRecord record)
{
// Call the BroadcastAudio method to update clients.
Clients.All.BroadcastAudio(record);
}
}
My HTML/Javascript client:
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var broadcast = $.connection.broadcastHub;
// Create a function that the hub can call to broadcast messages.
broadcast.client.broadcastAudio = function (record) {
// Html encode user name, channel and title.
var encodedName = $('<div />').text(record.Username).html();
var encodedChannel = $('<div />').text(record.Channel).html();
var encodedTitle = $('<div />').text(record.Title).html();
// Add the broadcast to the page.
$('#broadcasts').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedChannel + '</strong>: ' + encodedTitle + '</li>');
};
// Get the user name.
$('#displayname').val(prompt('Enter your name:', ''));
// Get the Channel name to which you want to broadcast.
$('#channelname').val(prompt('Enter Channel:', ''));
// Set initial focus to message input box.
$('#title').focus();
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendbroadcast').click(function () {
// Call the Send method on the hub.
var broadcastMessage = {}
broadcastMessage.Username = $('#displayname').val();
broadcastMessage.Channel = $('#channelname').val();
broadcastMessage.Title = $('#title').val();
broadcast.server.send(broadcastMessage);
// Clear text box and reset focus for next broadcast.
$('#title').val('').focus();
});
});
});
</script>
My Console app client:
class Program
{
static void Main(string[] args)
{
HubConnection connection = new HubConnection("http://localhost:35540/");
IHubProxy proxy = connection.CreateHubProxy("BroadcastHub");
proxy.On<AudioRecord>("BroadcastAudio", BroadcastAudio);
connection.Start().Wait();
Console.ReadLine();
}
static void BroadcastAudio(AudioRecord record)
{
Console.WriteLine("Broadcast: {0} {1} {2}", record.Username, record.Channel, record.Title);
}
}
Background Thread:
public class BackgroundThread
{
private static Random _random = new Random();
public static void Start()
{
ThreadPool.QueueUserWorkItem(_ =>
{
IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<BroadcastHub>();
while (true)
{
PersistedAudioRecord record = new PersistedAudioRecord();
record.Channel = _random.Next(10).ToString();
record.Username = new string('a', Convert.ToInt32(record.Channel));
record.Title = new string('b', Convert.ToInt32(record.Channel));
try
{
hubContext.Clients.All.BroadcastAudio(record);
}
catch (Exception ex)
{
System.Diagnostics.Trace.TraceError("SignalR error thrown: {0}", ex);
}
Thread.Sleep(TimeSpan.FromSeconds(2));
}
});
}
}
I tried this scenario with my application and I was able to send messages from a webrole to a console application. Is it possible to zip your project and send it to see if this reproes...