Broadcast to all clients outside of hub class in SignalR - javascript

I have an ASP.NET Web API that exposes some REST methods. The client browser authenticates with the API using a Login screen. I would like to broadcast a message (javascript alert) to all clients when another client authenticates with the API. No need for the client to invoke a method on the server, just the server calling a single method on the client to display a Javascript Alert.
My Hub class:
public class MyHub : Hub
{
public void BroadcastMessage(string userName)
{
Clients.All.notify(userName);
}
}
Inside my CustomOAuthProvider classs where user authentication takes place:
if (userAuthenticated)
{
var signalRContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
signalRContext.Clients.All.notify(context.UserName);
}
Here is my index.html file with the relevant scripts:
<script src="scripts/jquery-2.2.2.min.js"></script>
<script src="scripts/jquery.signalR-2.2.0.js"></script>
<script src="http://localhost:49834/signalr/hubs"></script>
<script>
(function ($) {
$(function () {
var hubProxy = $.connection.myHub;
hubProxy.client.notify = function (username) {
alert(username + ' has logged in');
};
$.connection.hub.start();
});
})(jQuery);
</script>
Note that the path to the dynamically generated SignalR Hubs script has localhost:49834. This is the url to my web api. I included this because the client is running in a Node.js http-server and is not part of the ASP.NET Web Api project.
When I run this I get no errors on the console and no alerts. I login with one user then open a separate browser and login with a second user. I am not sure why I am not getting a Javascript Alert with the authenticated username.

Related

Callback on client side does not get get triggered from signalR back end

I'm having trouble with the server side not communicating with the client side. I receive data on the back end once it's sent from the client, however, it will not work vice versa (when the data is sent back to the client).
My project setup:
Created an empty ASP.NET application with framework 4.6.2
Installed nuget package 'Microsoft.AspNet.SignalR' v2.4.0
Using jQuery 3.3.1
Added a startup class and inserted 'app.MapSignalR();' into the
configuration method
Added a hub with one method for communicating back and forth with the
client
Added a js file for starting up the hub and communicating with the
server
I have tried the following with no success:
Using framework 4.5
Using an older version of jQuery
Logging data on
back end (which I do receive data from the client)
Tried sending back the message to ALL clients (Clients.All) opposed to just the caller
Re-creating a new
project for signalR
Made sure that there were NO JS errors
Ran locally in MULTIPLE browsers (Chrome & Edge)
index.aspx:
<script src="/js/third_party/jquery-3.3.1.min.js"></script>
<script src="/js/third_party/jquery-ui.min.js"></script>
<script src="/js/third_party/jquery.signalR-2.4.0.min.js"></script>
<script src='/signalr/js'></script>
<script src="/js/client.js"></script>
client.js:
var conn = null;
$(function () {
$.connection.hub.stateChanged(connectionStateChanged);
$.connection.hub.start({ waitForPageLoad: false });
conn = $.connection.login;
function connectionStateChanged(state) {
switch (state.newState) {
case 1: // Connected
conn.server.announce('This is an announcement.'); // Works fine and sends the message
break;
}
}
// I'm using '.client', so there is no reason why this should not be triggered
conn.client.onAnnounce = function (message) {
alert(message); // Does NOT receive the message back
debugger;
}
Login.cs:
public class Login : Hub
{
public void Announce(string message)
{
// I receive the data here from the client... but it does not get sent back to the client
Clients.Caller.onAnnounce(message);
}
}
Startup.cs:
[assembly: OwinStartup(typeof(AutoPlayer.Startup))]
namespace SignalRTest
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
I expect the server to receive a message, the server to send that same message back to the client, and for the client to alert the message.
After hours of trying different things, it was due to this line of code:
$.connection.hub.start({ **waitForPageLoad: false** });
Removing the 'waitForPageLoad' setting, or by setting it to true fixed it.
"waitForPageLoad - Determines if SignalR should wait until the page is entirely loaded to start the connection (defaults to true)."
I assume this was due to the client JS file not being loaded fully, by the time the server was calling back to the client (where 'conn.client.onAnnounce' did not exist yet). Figured I'd see a JS error in the console if this really is the case... but I guess not.

Accessing a Web API from JavaScript after being authenticated against Azure AD B2C

I am developing a .Net Web App where after authenticating against Azure AD B2C through the Azure AD Connect protocol the controller in my app gets an access token through the MSAL library (C# code) to access a backed Web API. That works all fine.
Now from the same web app I need to use JavaScript to access the same backed Web API. My question is how can I leverage the access token obtained through my server side C# code to get my client side JavaScript to access the Web API without being prompted to sign-in.
I used the sample code on GitHub to get me started.
Below is my JavaScript code. When I run it I get the following error "user_login_error:User login is required"
if (!clientApplication) {
clientApplication = new Msal.UserAgentApplication(window.config.clientID, window.config.authority, authCallback);
clientApplication.redirectUri = window.config.redirectUri;
}
function ReloadInfo(type, language, location) {
clientApplication.acquireTokenSilent(window.config.b2cScopes).then(function (accessToken) {
ReadResource(accessToken, type, language, location);
}, function (error) {
clientApplication.acquireTokenPopup(window.config.b2cScopes).then(function (accessToken) {
ReadResource(accessToken, type, language, location);
}, function (error) {
debugger
logMessage("Error acquiring the access token to call the Web api:\n" + error);
});
})
}
Thanks!
A simple solution for this scenario is that you can create a corresponding controller to call the web API.
And in the JavaScript, you can call your web app instead of the web API directly. Since you have sign-in, the JavaScript can call the controller successfully. And in this sencario, there is no need to use MSAL library for JavaScript.
Update
<script src="https://code.jquery.com/jquery-3.2.1.js"
integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE="
crossorigin="anonymous"></script>
<script>
$(document).ready(function () {
$("#Location").change(function () {
$.ajax({
url: "data.html",//modify the path HTTP request you wanted
}).done(function (data) {
console.log(data);// handle the result data here
});
});
})
</script>
You can refer here about full jQuery document.

Angular Js and SignalR not working when called from WebAPI and Hub

I am working on signalR implementation with Angular JS. When i tried to call SignalR event from API or Hub to ui client side.. it is not working as expected.
WebAPI Call
I am not getting any response in browser for SignalR request.
ServiceCreated for SignalR
[Resposne On Event at client side][3]
I am not getting any resposne in test event for SignalR(Working some times in chrome).
Thanks for advance. Really Appreciate you quick answer.
You have to start the connection, additional to that you have to write your the "test" - function on the client which the server calls.
Here you see a sample:
Client Code:
<script>
$(function () {
var connection = $.hubConnection("http://localhost:27709/signalr");
var chatHubProxy = connection.createHubProxy('chatHub');
chatHubProxy.on('newMessageAdded', function (name, message) {
$("#messages").append("<li>" + name + message + "</li>");
console.log(name + ' ' + message);
});
connection.start({ transport: 'longPolling' }).done(function () {
$('#btnSend').click(function () {
chatHubProxy.invoke('newMessage', "Stephan", $('#msg').val());
$('#msg').val('').focus();
});
});
});
</script>
Server:
public class ChatHub : Hub
{
public void NewMessage(string name, string message)
{
Clients.All.newMessageAdded(name, message);
}
}
It's important that the you write the methode/function on server and client side same (no spelling mistakes).
Attention on Pascal and Camelcase of hubs, methods, ...:
- On the client the proxy name is a camel-cased version of the Hub class name.
By the way: Why you're not using the generated proxy?

How to call function on javascript page from ASP.NET 5 WebAPI

Okay, maybe I'm doing this all wrong, but here goes:
I have a ASP.NET 5 WebAPI project running on dnxcore50. It has one very simple controller, which only implements the Get() method:
public class Data : Controller {
public JsonResult Get(){
return Json(/*some data from EF*/);
}
}
Additionally, I have index.html and myscripts.js files which host a very simple webpage.
When running the project, it opens on http://localhost:5000, I can browse to index.html and can call
$.getJSON('/api/Data', function(data){
/*do stuff*/
});
All of this works, on all OSX and Windows. So far so good!
Now, what I want: when the API is called (for example a POST by another client), it should send a message to the javascript to display an event.
What have I tried:
setting a flag in the API and polling from the javascript. This seems sub-optimal, but works.
playing around with socket.io, but I cannot find a dnxcore50 compatible way to communicate with it from the controller.
playing around with HTML5 WebSockets, but can't seem to establish communication from the controller.
How can I communicate from ASP.NET 5 (dnxcore50) to a javascript page?
OK after some research, I got it working using SignalR, as #Liam suggested.
This is how I got SignalR working with ASP.NET Core 1.0.
In Nuget.config in project root, add repository for SignalR:
<add key="AspNetVNext" value="https://www.myget.org/F/aspnetmaster/api/v3/index.json" />
In project.json add reference for SignalR:
"dependencies":{
...
"Microsoft.AspNet.SignalR.Server": "3.0.0-*"
}
In Startup.cs, register SignalR:
public void ConfigureServices(IServiceCollection services)
{
/* ...other services...*/
services.AddSignalR(options =>
{
options.Hubs.EnableDetailedErrors = true;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
/*...other configs...*/
app.UseSignalR();
}
Create a new Hub class:
public class EventHub : Hub { }
From for example a controller, call the hub:
private readonly IHubContext hub;
public ProjectQualityController(IConnectionManager connectionManager)
{
hub = connectionManager.GetHubContext<EventHub>();
}
public void SendMessage(string value)
{
hub.Clients.All.sendMessage(value);
}
In the javascript file, register to the sendMessage event:
<script src="scripts/jquery.signalR.js"></script>
<script src="signalr/hubs"></script>
<script type="text/javascript">
$(function () {
var chat = $.connection.eventHub;
chat.client.sendMessage = function (message) {
var encodedMsg = $('<div />').text(message).html();
alert(encodedMsg)
};
// Start the connection.
$.connection.hub.logging = true;
$.connection.hub.start()
.done(function(){ console.log('Now connected, connection ID=' + $.connection.hub.id); })
.fail(function(){ console.log('Could not Connect!'); });
});
</script>
Hope this helps someone!

signalR connection failing when trying to connect with cross domain hosted signalr service

I am trying to consume signalR on a website. SignalR is a self hosted service.
SignalR url: http://localhost8080:/signalr
Website is running # http://localhost:31775/
I am getting error on browser console
GET
http://localhost:31775/signalr/negotiate?connectionData=%5B%5D&clientProtocol=1.3&_=1442784297380
404 (Not Found)
This error tells me that proxy that the code below is trying to generate is using website url i.e. relative path. However I want to use absolute path where my signalR service is hosted.
AngularJS Factory
app.factory("signalRService", ['$', '$rootScope', function ($, $rootScope) {
var proxy;
var connection;
return {
connect: function () {
connection = $.hubConnection();
proxy = connection.createHubProxy('myHub');
connection.start();
proxy.on('addMessage', function (tags) {
$rootScope.$broadcast('addMessage', tags);
});
},
send: function () {
proxy.invoke('send');
},
};
}]);
I also added javascript reference for this.
<script src="js/jquery.signalR-2.0.3.min.js"></script>
To validate if my self hosting is running file. I checked http://localhost:8080/signalr/hub on browser
What you are missing is a bit of configuration of the proxy:
connection = $.hubConnection('http://localhost:8080/signalr');
How to generalize on that piece of code (the url could be an argument of your connect method, or whatever fits your Angular strategy) is up to you.

Categories

Resources