SignalR - cross application use - asp.net

I have a WPF app which is going to be deployed to multiple users on a LAN. The users of this app will be factory workers in a manufacturing company, who will be using the app to update their progress on each order.
The customer also has an ASP.NET webforms app which is used for entering orders among other things. What I want to build in this ASP.NET app is a screen that will give live updates of the progress of the factory workers. I've been looking at SignalR for this, but I'm unsure about whether it'll let me send updates from a separate application (I.e WPF to the WebForms app). Is this possible? If so are there any examples of cross application SignalR use online?
Thanks!

There is a SignalR client which is part of the standard set of SignalR bits that lets you build signalr support straight into .net desktop apps.
See http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-net-client
You can use this in combination with JavaScript web-page clients without problem.

If both the WPF and WebForms apps connect to the same server then this is simple to implement.
Setup a SignalR Hub:
public class ProgressHub : Hub {
}
When loading the WebForms app load/show the current progress in an ordinary manner. Setup SignalR to get live updates to the progress:
var appHubProxy = $.connection.appHub;
appHubProxy.client.progress = function (orderId, percent) {
console.log(orderId + ': ' + percent);
};
$.connection.hub.start()
The WPF app calls the server to update the progress (using e.g WebAPI), in this handler call the signalr clients progress method:
public class ProgressController : ApiController {
public void Post(string orderId, int percent) {
// <Save progress to DB, etc>
// Get instance of the SignalR ProgressHub context
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
// Invoke the progress method on all connected clients.
// You probably want to use Groups to only send customers
// events for its own orders
hubContext.Clients.All.progress(orderId, percent);
}
}
Or you could have WPF use the .NET SignalR API to call a method in the Hub instead:
public class ProgressHub : Hub {
public void Progress(string orderId, int percent) {
// <Save progress to DB, etc>
// Invoke the progress method on all connected clients.
// You probably want to use Groups to only send customers
// events for its own orders
Clients.All.progress(orderId, percent);
}
}

Related

SignalR simple gateway

I have a web application composed of a gateway and several back-end services.
The gateway is a self-hosted OWIN application, and covers concerns like authentication, authorization, and routing of api calls to the backend.
I'm interested in using SignalR in one of my backend services to push data to the client. E.g. the user starts a long running query, and data is fed back to the client as it becomes available.
I managed to use the backplane from the scale-out article as a messaging mechanism (though it seems it wasn't designed for such messaging)
SignalR scaleout explanation
"Gateway" Hub code: (The logic is only for testing purposes)
public override async Task OnConnected()
{
HttpClient client = new HttpClient()
{
BaseAddress = new Uri("http://localhost:8888/other/")
};
var result = await client.PostAsJsonAsync("signin", Context.ConnectionId);
await base.OnConnected();
}
Backend controller code
[HttpPost]
[Route("signin")]
public void PostSignin([FromBody]string id)
{
StartPing(id);
}
public async Task StartPing(string id)
{
var context = GlobalHost.ConnectionManager.GetHubContext<FrontendHub>();
int i = 0;
while (true)
{
i++;
context.Clients.Client(id).showMessage("num " + i);
await Task.Delay(1000);
}
}
However, this is a big enterprise application, and I don't want the gateway to have any dependency on the actual code of the backend services. But the example only works if a hub with the same name is defined in both the gateway and the backend service.
On one hand, I'm trying to avoid the need to place such specialized code in the gateway, on the other hand, I'd like to leverage the ability to use actual function names and parameters. I don't want a "master hub" with a single function.
Is there a way to do it?
Didn't end up doing it all, but the solution discovered later was to indeed use a "Master hub", but it doesn't actually need to have any functions at all.
The contract is between the backend service and the client application. Since everything in SignalR is loosely typed, it's enough that the client define some function on the hub, and the backend service invoke the same function on the hub. The hub doesn't actually need this function in its own code.

ASP.NET Core Restful API Communication Using Synchronous HTTP

I have multiple restful API components implemented using ASP.NET Core. I am not using Event Driven Design or any messaging broker service.
I want to keep it simple, so
Let's say I have 3 restful independent components (with independent ASP.NET Core Projects) that are published to the same IIS in addition to the Identity server provider:
Navigation: that retrieve menus from its own database
Authorization: that deals with the permissions and security
Notifications
Identity Server: provides Jwt access tokens for authenticated users to authorize him access the apis.
Apart from the external communication from the client to the Apis where an API Gateway should handle all client requests. There are some sort of communication that is done internally. A good example is getting menus for the user:
The user gets an access token after successful log in
Then he requests the menus he can view, so a request is forwarded to Navigation API
Navigation API issues an internal request to Authorization API in order to check what permissions the user has to limit his access to certain menus.
Right Now, I am managing the communication by a common library called Service Proxies, which has all the api urls hard coded in cs file (which is just for trying the concept)
public static class Config
{
public static class ServiceURLs
{
public const string AuthorizationAPI ="http://localhost:port/api/Authorization/" ;
}
}
public class AuthorizationServiceProxy : IAuthorizationServiceProxy
{
//ServiceProxy is a custom class that issue http requests in order to get responses
private ServiceProxy _serviceProxy;
public AuthorizationServiceProxy(string accessToken)
{
_serviceProxy = new ServiceProxy(Config.ServiceURLs.AuthorizationAPI, accessToken);
}
public async Task<List<Permission>> GetUserPermissions()
{
var route = "GetUserPermissions";
var result = await
_serviceProxy.GetHttpResponseContentAsType<List<Permission>>(route);
return result;
}
AuthorizationProxy and all proxies will be just to issue a request from an API to another one.
How would an interprocess communication would be handled in my case?

WCF Service with SignalR

I have a web application which has few charts on dashboard. The data for charts is fetched on document.ready function at client side invoking a WCF service method.
What i want is now to use SignalR in my application. I am really new to SignalR. How can i call WCF methods from SignalR Hub or what you can say is that instead of pulling data from server i want the WCF service to push data to client every one minute.
Is there a way of communication between signalR and WCF service.
Also another approach can be to force client to ask for data from WCF Service every minute.
Any help will be really appreciated.
I have done following as of yet.
Client Side Function on my Dashboard page
<script src="Scripts/jquery.signalR-2.0.3.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="/signalr/hubs"></script>
<a id="refresh">Refresh</a>
$(function() {
var dashboardHubProxy = $.connection.dashboardHub;
$.connection.hub.start().done(function() {
// dashboardHubProxy.server.refreshClient(parameters);
$("#refresh").click(function() {
dashboardHubProxy.server.refreshClient(parameters);
});
});
dashboardHubProxy.client.refreshChart = function (chartData) {
debugger;
DrawChart(chartData, 'Hourly Call Count For Last ' + Duration + ' Days', '#chartHourly', 'StackedAreaChart');
};
});
and my Dashboard Hub class is as follows
public class DashboardHub : Hub
{
private readonly ReportService ReportService = new ReportService();
public void RefreshClient(string parameters)
{
var chartData = ReportService.GenerateHourlyCallsTrendGraphicalReport(parameters);
Clients.All.refreshChart(chartData);
}
}
My SignalR startup class is as follows
[assembly: OwinStartup(typeof(CallsPortalWeb.Startup), "Configuration")]
namespace CallsPortalWeb
{
public static class Startup
{
public static void Configuration(IAppBuilder app)
{
ConfigureSignalR(app);
}
public static void ConfigureSignalR(IAppBuilder app)
{
app.MapSignalR();
}
}
}
When i click on refresh button and a debugger on RefreshClient method on hub the debugger doesn't get to the method which means i am unable to call server side method of SignalR.
Is there anything needs to be done in web.config?
I agree with AD.Net's comment. To elaborate slightly more though, the SignalR hubs can be hosted directly in your web project kinda the same way controllers are used. There is also a package out there so you can host the SignalR library on its own so it can act as a service all on its own. Either way you will need to hit the SignalR hub first as that is how it communicates then you would call your WCF service methods from within the hubs.
Brief explanation
Your HUB will have methods used by both your USER Client and your WCF Client. You may use something like UserConnected() for the user to call in and setup your logging of the connection. Then the WCF service may call your HUB with an UpdateUserStats(Guid connnectionId, UserStats stats) which would in turn call the USER client directly and provide the stats passed in like so Clients.Client(connectionId).updateStats(stats) which in turn would have a method on the USERS client named updateStats() that would handle the received information.
Initial page landing
What AD.Net provided is basic code that will be called when the user lands on the page. At this point you would want to log the ConnectionId related to that user so you can directly contact them back.
First contact with your hub touching WCF
From your Hub, you could call your WCF service as you normally would inside any normal C# code to fetch your data or perform action and return it to your user.
Method of updating the user periodically
SignalR removes the need for your client code to have to continually poll the server for updates. It is meant to allow you to push data out to the client with out them asking for it directly. This is where the persistence of the connections come into play.
You will probably want to create a wrapper to easily send messages to the hub from your application, since you are using WCF I would assume you have your business logic behind this layer so you will want the WCF service reaching out to your Hub whenever action X happens. You can do that by utilizing the Client side C# code as in this case your client is actually the user and the WCF service. With a chat application the other user is basically doing what you want your WCF service to do, which is send a message to the other client.
Usage example
You are running an online store. The dashboard displays how many orders there have been for the day. So you would wire up a call to the hub to send a message out to update the products ordered when a user places a new order. You can do this by sending it to the admin group you have configured and any admins on the dashboard would get the message. Though if these stats are very user specific, you will more then likely instead reach into the database, find the ConnectionId that the user has connected with and send the update message directly to that connectionid.
WCF Client Code Example
Just incase you want some code, this is directly from MS site on connecting with a .net client. You would use this in your WCF service, or wherever in your code you plan on connecting and then sending an update to your user.
var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await hubConnection.Start();
Here is a link directly to the .Net Client section: http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-net-client
I am sure you have seen this link but it really holds all the good information you need to get started. http://www.asp.net/signalr
Here is a more direct link that goes into usages with code for you. http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server
ADDED: Here is a blog specific to Dashboards with SignalR and their polling.
http://solomon-t.blogspot.com/2012/12/signalr-and-interval-polling-for.html
ADDED: Here is a page on managing users signalR connections.
http://www.asp.net/signalr/overview/signalr-20/hubs-api/mapping-users-to-connections
Update for your code update
The .Net Client library (in NuGet) gives your .net code access to the hub. Since you are a client you will need to connect to the hub just like the User who is also a client. Your hub would act as the server for this. So with the .Net Client I am assuming you would setup a windows service that would internally poll, or something event based that would call the .Net Client code portion of it which would reach out to your hub. Your hub would take the information provided, more than likely a ConnectionId or GroupId and broad cast the User (which is perhaps on a website so it would be the JS client) a method that would update the front end for the user client. Basically what I mention under "Brief Explanation".
Now, to directly respond to the code you posted. That is Javascript, I would expect a connect like you have done. Updating the chart on initial connection is fine as well. If this is all the code signalR wise though you are missing a client side method to handle the refresh. Technically, instead of calling Clients.Caller.RefreshChart() you could just return that data and use it, which is what your javascript is doing right now. You are returning void but it is expecting a your date.
Now, I would actually say correct your javascript instead of correcting the hub code. Why? Because having a method in JS on your client that is called "refreshChart()" can be reused for when you are having your server reach out and update the client.
So I would recommend, dropping anything that is related to updating the dashboard in your JS done statement. If you want to do a notification or something to the user that is fine but dont update the grid.
Now create a JS client function called "refreshChart", note the lower case R, you can call it with a big R in c# but the js library will lowercase it so when you make the function have it will receive your dashboard information.
Now, on the server polling, or executing on some action, your WCF would call a method on the hub that would be say "UpdateDashboar(connectionId,dashInfo)" and that method would then inside of it call the "refreshChart" just like you are doing in your RefreshClient method, accept instead of doing Clients.Caller you would use Clients.Client(connectionId).refreshChart(chartInfo).
Directly the reason your code is not working is because you need to turn that Void into the type you expect to be returned. If the rest is coded right you will have it update once. You will need to implement the other logic I mentioned if you want it constantly updating. Which is again why I asked about how you are persisting your connections. I added a link to help you with that if you are not sure what I am talking about.
You should use the SignalR Hub to push data to the client. Your hub can consume a WCF service (the same way your client can) to get the data.
from client:
hub.VisitingDashBoard();
on the hub in the VisitingDashBoard method:
var data = wcfClient.GetDashboardData()//may be pass the user id from the context
Clients.Caller.UpdateDashboard(data)
Of course your client will have a handler for UpdateDashboard call

SignalR Chat App in WinForm With Remote Clients

i am new in signalR , i have tried and learn from different web sites like github and etc etc
But i couldn't find the solution for my problem.... and now i am getting confused...
My problem is:
I have developed a Chat app in Winform with Web Services and Centralized Database and it is working fine in different countries as in different branches of one organization.
But i want to convert that Chat App into SignalR to achieve more efficiency but i couldn't understand , how to do it in SignalR. because All tutorials of SignalR on Web in one Solution.
like Web , Console or WinRT communicated with each other but they are in one solution but in my scenerio i cannot put the service or Web Page in WinForm application.
Please please help me out in this manner.
What you need to do is use the SignalR for .NET clients. Bring that into your project using NuGet assuming you are using Visual Studio.
You will need to import the following generally:
using Microsoft.AspNet.SignalR.Client;
using Microsoft.AspNet.SignalR.Client.Hubs;
Assuming you are following most of the tutorials on the web you can need the following to connect:
public IHubProxy Proxy { get; set; }
public HubConnection Connection { get; set; }
Also you will need to set the connection like so:
public string Host = "http://YourSignalRChatAppLocationOnAzureOrLocally.cloudapp.net/";
Connection = new HubConnection(Host);
//Assuming your SignalR hub is also called ChatHub (If you followed most tutorials it will be)
Proxy = Connection.CreateHubProxy("ChatHub");
This part will need to be in an async function:
//If you are passing an object back and fourth otherwise String is fine
Proxy.On<ChatMessage>("Send", hello => OnSendData("Recieved send " + hello.Username + " " + hello.Content));
await Connection.Start();
More material fro the link below, this guy has it running on Console app, WPF app, and web clients so you can see the difference.
Standard tutorial on how to make the web server.
SIGNALR MESSAGING WITH CONSOLE SERVER AND CLIENT, WEB CLIENT, WPF CLIENT

ASP.NET MVC - Real time updates using Web Service

I'm trying to find examples on how to get real time updates using a web service in ASP.NET MVC (Version doesn't matter) and posting it back to a specific user's browser window.
A perfect example would be a type of chat system like that of facebooks' where responses are send to the appropriate browser(client) whenever a message has been posted instead of creating a javascript timer on the page that checks for new messages every 5 seconds. I've heard tons of times about types of sync programs out there, but i'm looking for this in code, not using a third party software.
What i'm looking to do specifically:
I'm trying to create a web browser chat client that is SQL and Web Service based in ASP.NET MVC. When you have 2-4 different usernames logged into the system they chat and send messages to each other that is saved in an SQL database, then when there has been a new entry (or someone sent a new message) the Web Service see's this change and then shows the receiving user the new updated message. E.G Full Chat Synced Chat using a Web Service.
The thing that really stomps me in general is I have no idea how to detect if something new is added to an SQL table, and also I have no idea how to send information from SQL to a specific user's web browser. So if there are people userA, userB, userC all on the website, i don't know how to only show a message to userC if they are all under the username "guest". I would love to know hot to do this feature not only for what i'm trying to create now, but for future projects as well.
Can anyone point me into the right direction please? I know SQL pretty well, and web services i'm intermediate with.
You can use SignalR for this task.
Via Scott Hanselman:
Create Asp.net mvc empty application
install nuget package of SignalR
Add new Controller (as example HomeController):
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
Create view Index with javascript references:
#Url.Content("~/Scripts/jquery-1.6.4.min.js")"
"#Url.Content("~/Scripts/jquery.signalR.js")"
and function:
$(function () {
var hub = $.connection.chatHub;
hub.AddMessage = function (msg) {
$('#messages').append('<li>' + msg + '</li>');
};
$.connection.hub.start().done(function() {
$('#send').click(function() {
hub.send($('#msg').val());
});
});
});
Create class ChatHub:
public class ChatHub:Hub
{
public void Send(string message)
{
Clients.AddMessage(message);
}
}

Resources