I am new to SignalR and having a bit of difficulty using a SignalR hub in a self hosted scenario.
At the moment (just for testing) I have the simplest hub possible:
public class NotificationsHub : Hub
{
public void Hello(string name)
{
Clients.All.hello("Hello " + name);
}
}
This hub class is in a Class Library project which is referenced in a Windows Service application. I've added all the nuget packages to the Windows Service app and added the OWIN Startup class which looks like this:
public class Startup
{
public void Configuration(IAppBuilder app)
{
AppDomain.CurrentDomain.Load(typeof(NotificationsHub).Assembly.FullName); // as selfhosting doesn't scan referenced libraries for Hubs
app.Map("/signalr", map => {
map.UseCors(CorsOptions.AllowAll);
var hubConfig = new HubConfiguration {
EnableDetailedErrors = true,
EnableJSONP = true
};
map.RunSignalR(hubConfig);
});
}
}
In the Windows Service OnStart method I host the signalR using:
SignalR = WebApp.Start<Startup>("http://*:9191/");
In the ASP.NET MVC app which should interact with SignalR I have the following code:
<script src="Scripts/jquery.signalR-2.1.1.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="http://localhost:9191/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
$.connection.hub.url = "http://localhost:9191/signalr";
var notif = $.connection.notificationsHub;
notif.client.hello = function (msg)
{
alert(msg);
}
$.connection.hub.start().done(function () {
$("#sayHello").click(function () {
notif.server.hello($("#myName").val());
});
});
});
</script>
The problem is this doesn't work in my correct setup... in the browser console I have no errors, the ~/signalr/hubs js looks fine...
If I do more or less the same configuration, but host the SignalR in the ASP.NET MVC app, everything works as expected.
UPDATE: following #halter73 's suggestion to enable the client side logging for the hub, I've got the following error message which I still can't fix:
SignalR: notificationshub.Hello failed to execute. Error: Method not
found: 'Microsoft.AspNet.SignalR.Hubs.IHubCallerConnectionContext
Microsoft.AspNet.SignalR.Hub.get_Clients()'.
Could somebody please let me know what I am missing?
Thank you in advance!
Andrei
Since 2.1.0, get_Clients should return a IHubCallerConnectionContext<dynamic> instead of IHubCallerConnectionContext.
The error you are seeing could happen if you compile your application against SignalR <= 2.03 but loading SignalR >= 2.10 at runtime.
Related
I use ASP.Net framework to host the socket server. I created a Hub using SignalR, i ran it and then tried to connect to it from my angular app but recieved this error:
Failed to start the connection: TypeError: Cannot read properties of undefined (reading 'length')
There are no more details.
I Enabled CORS with this code:
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR("/Art", new HubConfiguration());
}
and in the hub:
[EnableCors(origins: "http://localhost:4200", headers: "*", methods: "*")]
public class ArtHub : Hub
{
....
}
I will highly appreciate any help
In configuration of your server use this to see detailed error info:
builder.Services.AddSignalR(o =>
{
o.EnableDetailedErrors = true;
});
Use SignalR Hub endpoint like this:
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ArtHub>("/art");
});
I am developing a real time application based on signal R . I am using .NET framework 4 , Signal R version 1.2.2 in VS 2010.I am getting a Hub reference error stating
Uncaught Error: SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/hubs'></script>.
I got a solution to add the Hub reference in global file. But since i am using DNN framework it contains multiple projects and have a common global file.
RouteTable.Routes.MapHubs("/myhubs", new HubConfiguration());
i tried adding this piece of code there, but it too didn't works..
my hub class
public class ChatHub : Hub
{
public void Send(string message)
{
Clients.Others.receive(message);
}
}
And start up class is
[assembly: OwinStartup(typeof(DotNetNuke.Modules.VideoChat.Startup))]
namespace DotNetNuke.Modules.VideoChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapHubs();
}
}
}
i am using jquery on client side.
var chat = $.connection.chatHub;
$.connection.hub.start().done(function () {}
Can anyone suggest a way around
You need to follow these steps:
Create a Hub class on the server that inherits the Hub class from SignalR
Create client proxy for the Hub class (using .NET class or javascript code)
Startup the Hub on the server using MapHubs() (obsolete)
Your question does not give enought information. Is it a web application? Are you using javascript or .NET on the client side?
See this post: SignalR hubclass in classlibrary
EDIT
Here is what you should have in your Startup class now that I see that you are using OWIN:
[assembly: OwinStartup("StartupConfiguration", typeof(DotNetNuke.Modules.VideoChat.Startup))]
namespace DotNetNuke.Modules.VideoChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// SignalR Hub Startup
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = true;
hubConfiguration.EnableJSONP = false;
app.MapSignalR(hubConfiguration);
}
}
}
In your web.config, add these lines:
<appSettings>
<add key="owin:appStartup" value="StartupConfiguration" />
<add key="owin:AutomaticAppStartup " value="true" />
</appSettings>
We use SignalR library in our ASP.NET web application. The code looks as following:
Server:
[HubName("ticketsCounterHub")]
public class MassivePrintHub : Hub
{
public void PostTicketsCount(long count)
{
Clients.All.Send(count);
}
}
public class HubFactory
{
private HubFactory() {}
public static readonly HubFactory Current = new HubFactory();
public IHubProxy GetMassivePrintHubProxy()
{
var hubConnection = new HubConnection(ConfigUtils.GetRequiredSettingValue("adminPath"));
var hubProxy = hubConnection.CreateHubProxy("ticketsCounterHub");
hubConnection.Start().Wait();
return hubProxy;
}
}
Client (JavaScript):
MassivePrintApp.controller("ListController", function ($scope, Dates) {
var hubManager = (function () {
var massivePrintHub = $.connection.ticketsCounterHub;
$.connection.hub.start();
return { massivePrintHub: massivePrintHub };
} ());
hubManager.massivePrintHub.client.Send = function (ticketsCount) {
$scope.action.Quantity = ticketsCount;
$scope.$digest();
};
});
The key part of code is in MVC controller:
public FileResult PrintAction(int actionId, int count, DateTime actionDate, bool isThermo=false)
{
var ticketsCount = _ticketService.GetTicketsInStatusCount(actionId, actionDate, TicketStatusEnum.ToPrint);
HubFactory.Current.GetMassivePrintHubProxy().Invoke("PostTicketsCount", ticketsCount);
var stream = new MemoryStream();
xmlResponse.Save(stream);
stream.Flush();
stream.Position = 0;
return File(stream,ContentTypeEnum.XML.ToString(),String.Format("массовая {0} мероприятия {1} {2}шт.xml", isThermo?"термопечать":"печать", action.Artist,count));
}
As you can see, we have this line:
HubFactory.Current.GetMassivePrintHubProxy().Invoke("PostTicketsCount", ticketsCount);
And that causes the issue, that is whenever we call it one more instance of hub was added to "Requests" section on IIS.
I understand we already started hub in JavaScript code, but I'm not sure how can I use the existing connection or how to get rid of HubFactory or delete created hub instance.
And I don't understand why hub hangs on IIS.
Starting from a more simple example will help you a lot I guess. After that you can look into hosting your SignalR server differently (Console App or Windows Service) the basics won't change
(First installed SignalR: NuGet: install-package Microsoft.AspNet.SignalR)
I made a simple web-app example. The project has a Hub class:
using Microsoft.AspNet.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SRTest
{
public class MassivePrintHub : Hub
{
private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MassivePrintHub>();
// Can be called from your Javascript code
public void PostTicketsCount(long count)
{
Clients.All.Send(count);
}
// Can be called from your c# code
public static void Static_PostTicketsCount(long count)
{
hubContext.Clients.All.Send(count);
}
}
}
An Owin startup class:
using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(SRTest.Startup))]
namespace SRTest
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
app.MapSignalR(hubConfiguration);
}
}
}
Page (Razor just to be able to call a simulator which calls a c# class to post message from backend):
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>TEST PAGE</title>
<!--Reference the jQuery library. -->
<script src='Scripts/jquery-1.6.4.js'></script>
<!--Reference the SignalR library. -->
<script src='Scripts/jquery.signalR-2.2.0.js'></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="signalr/hubs"></script>
</head>
<body>
THIS IS A TEST PAGE
<!-- Call simulator (trigger event every 5 seconds) -->
#{SRTest.SendFromBackEnd.SimulateSend();}
<script>
$(function () {
var printHub = $.connection.massivePrintHub;
// when send event happens
printHub.client.send = function (count) {
console.log("Send " + count + " tickets");
};
$.connection.hub.start().done(function () {
console.log("Connected");
});
$.connection.hub.logging = true;
});
</script>
</body>
</html>
And I added a dummy class which triggers the event through hubcontext every 5 seconds.
using System.Threading;
using System.Web;
namespace SRTest
{
public class SendFromBackEnd
{
public static void SimulateSend()
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
while (true)
{
MassivePrintHub.Static_PostTicketsCount(2);
Thread.Sleep(5000);
}
}).Start();
}
}
}
I added some loggings to the SignalR, add some debug points, it will help you understand the basics, then it will be much easier to build what you are planning to build.
EDIT
About the hanging request: As long as you have a client connected to your SignalR server with SSE or AJAX Long-Polling, you will have an ongoing request, which never finishes. (In case of AJAX Long-polling, it finishes for very short times and comes back). In the apps where I use only Javascript clients, I only see the request if a page is open where I am listening to events. If no page or static page open then no request.
In the apps where I am using .NET clients, as long as the two apps are running, and both Sartup classes executed, the request will always be there, even if no page open. (Since the .NET client is still listening to events.)
For more info: http://hanselminutes.com/291/damian-edwards-explains-the-realtime-web-for-aspnet-with-signalr
This is a Threading related issue. Try like this
Task.Run(() => connection.Start().ContinueWith(task =>
{
.....
})).Wait();
I'm using the latest version of SignalR (1.0.1). I am trying to broadcast from my controller to the hub and having a few issues:
My client does not seem to be getting messages.
It doesn't seem that my hub context even has an 'addMessage' defined:
My hub:
public class SignalRPriceHub : Hub
{
public void sndMessage(string msg)
{
Clients.All.addMessage(msg + "****");
}
}
Javascript client:
<script src="#Url.Content("~/Scripts/jquery.signalR-1.0.1.min.js")"></script>
<script src="~/signalr/hubs"></script>
.....
var myHub = $.connection.signalRPriceHub;
myHub.client.addMessage = function (message) {
alert(message);
};
Controller:
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRPriceHub>();
context.Clients.All.addMessage("TestOutsideMessage!!!");
A few things I noticed:
1. My hub context doesn't seem to have an 'addMessage'
{"'Microsoft.AspNet.SignalR.Hubs.ClientProxy' does not contain a definition for 'addMessage'"} System.Exception {Microsoft.CSharp.RuntimeBinder.RuntimeBinderException}
If I run the following code from the same file as my client code above, I do get a message.
var myHub = $.connection.signalRPriceHub;
$.connection.hub.start(function () {
myHub.server.sndMessage("Hello World!");
});
Can anyone shed some light as to what might be happening? Thanks all!
I'll go over the faults in your initial application which shed light to why your second bullet point makes it all work.
In your javascript client you must start the connection:
$.connection.hub.start();
You must then request the message on your hub by calling the sndMessage command:
$.connection.hub.start().done(function() {
myHub.server.sndMessage("Hello world");
});
The reason why you do not see an addMessage function on your hub context is because the hub context .Clients.All is dynamic.
One last note, in order to make the sample work you also need to make sure that in your Application_Start you have RouteTable.Routes.MapHubs(); . I assume you already have this since once you add the connection start that everything works.
I added SignalR to an existing ASP.Net 4 Web Forms application. Created a new folder called Hubs and added a Hub like so:
[HubName("UpdatesHub")]
public class UpdatesHub : Hub
{
public void DownloadUpdates()
{
// Code Removed
}
}
Added the RouteTable.Routes.MapHubs(); to Application_Start and added the following to the page:
<script src="/Scripts/jquery-1.9.1.js"></script>
<script src="/Scripts/jquery.signalR-1.0.1.js"></script>
<script src="/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var upd = $.connection.UpdatesHub;
// Code Removed
// Start the connection.
$.connection.hub.start().done(function () {
$('#btnDownload').click(function () {
upd.server.DownloadUpdates();
});
});
});
</script>
But whenever I click the button I just get "Uncaught TypeError: Object # has no method 'DownloadUpdates'". I have tried removing and readding signalr via NuGet but can't seem to get this to work, help!
SignalR camelCases the method names on the server. Try checking if downloadUpdates() exists.