SignalR: How to call .Net client method from server? - signalr

I want to send data to my console application wich have a connection to my "someHub". I tried to do as described in example from a link but got no result.
Server side code:
[HubName("somehub")]
public class SomeHub : Hub
{
public override Task OnConnected()
{
//Here I want to send "hello" on my sonsole application
Clients.Caller.sendSomeData("hello");
return base.OnConnected();
}
}
Clien side code:
public class Provider
{
protected HubConnection Connection;
private IHubProxy _someHub;
public Provider()
{
Connection = new HubConnection("http://localhost:4702/");
_someHub = Connection.CreateHubProxy("somehub");
Init();
}
private void Init()
{
_someHub.On<string>("sendSomeData", s =>
{
//This code is not reachable
Console.WriteLine("Some data from server({0})", s);
});
Connection.Start().Wait();
}
}
What is the best solution for implementing this and what is the reason why i am not able to invoke the client method?

Are you trying to talk to clients outside of Hub? If yes then you will have to get a HubContext outside of Hub. And then you can talk all the clients.
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
SignalR Server using Owin Self Host
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:8081/";
using (WebApplication.Start<Startup>(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(3000);
context.Clients.All.addMessage("Current integer value : " + i.ToString());
}
Console.ReadLine();
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
// Turn cross domain on
var config = new HubConfiguration { EnableCrossDomain = true };
config.EnableJavaScriptProxies = true;
// This will map out to http://localhost:8081/signalr by default
app.MapHubs(config);
}
}
[HubName("MyHub")]
public class MyHub : Hub
{
public void Chatter(string message)
{
Clients.All.addMessage(message);
}
}
Signalr Client Console Application consuming Signalr Hubs.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://localhost:8081/");
var myHub = connection.CreateHubProxy("MyHub");
connection.Start().Wait();
// Static type
myHub.On<string>("addMessage", myString =>
{
Console.WriteLine("This is client getting messages from server :{0}", myString);
});
myHub.Invoke("Chatter",System.DateTime.Now.ToString()).Wait();
Console.Read();
}
}
To run this code, create two separate applications, then first run server application and then client console application, then just hit key on server console and it will start sending messages to the client.

Related

Best way to pass configuration to Topshelf.HostFactory.Run in .Net core

I'm trying to develop/convert current .Net framework code of Task Consumer to Top shelf and .NET core 3.1 . I want to read the config data from json file and use those in start as well as in consume methods.
What is the best and simplest way to pass config data to Task Consumer service and other end points
Any suggestion/comments are helpful.
Thanks in advance .
My current code is
static void Main(string[] args)
{
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", true,true).Build();
var test2 = configuration.GetSection("RabbitMQSettings");
Console.WriteLine(HostFactory.Run(cfg => cfg.Service<TaskConsumerService>()));
}
ConsumerService code
public class TaskConsumerService : ServiceControl
{
IBusControl _bus;
IConfiguration _configuration;
public bool Start(HostControl hostControl)
{
_bus = ConfigureBus();
_bus.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
_bus?.Stop(TimeSpan.FromSeconds(30));
return true;
}
IBusControl ConfigureBus()
{
return Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var rabbitMQUrl = ConfigurationManager.AppSettings["RabbitMQSettings:RabbitMQHostUrl"];
cfg.Host(new Uri(rabbitMQUrl) , h =>
{
h.Username(ConfigurationManager.AppSettings["RabbitMQSettings:username"]);
h.Password(ConfigurationManager.AppSettings["RabbitMQSettings:pwd"]);
});
var queue0 = ConfigurationManager.AppSettings["QueName"];
cfg.ReceiveEndpoint(queue0 , e =>
{
e.Consumer<TransformConsumer>();
});
});
}
}
Consumer code
public class TransformConsumer : IConsumer<IExecuteTransform>
{
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
string address = string.Empty;
const string json = "application/json";
public async Task Consume(ConsumeContext<IExecuteTransform> context)
{
m_log.Info(" Transform started.");
// Processing
try
{
address = string.Concat(ConfigurationManager.AppSettings["RabbitMQSettings:RabbitMQHost"] , ConfigurationManager.AppSettings["RabbitMQSettings:queName"]);
IExecuteTransform message = await ConsumeSendEndPoint(context , address);
m_log.Info(" Transform Process completed.");
}
catch ( Exception e )
{
m_log.Error("Transform failed");
throw e;
}
}
}
I'd recommend moving from Topshelf to the .NET Core Generic Host, which is used in the console service sample. It uses the standard .NET Core extension packages for configuration, dependency injection, etc.

Publish on .NET Core 2.2 SignalR Hub as EXE not working on Self-Host but works in Visual Studio

I have a Hub that works inside Visual Studio Community 2017 for ASP.Net Core & SignalR. Everything works beautifully as long as it runs under VS. I read what is available & am not getting any luck. I have a HostedService that on StartAsync kicks off a thread with the Background prop set to true. This thread reads from a socket & then calls SendMessage on the Hub. I'm not sure what I'm doing wrong. It publishes an exe, but it is not working.
I have read all that I can find. I added a Hosted Service that is added under Startup.
// STARTUP
public class cRioHubStartup {
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddMvc();
services.AddHostedService<cRioHubHostService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
string virtDir = cRioHubGlobals.getHubUrl().VirtualDirectory;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
//app.UseHsts();
}
app.UseDefaultFiles();
app.UseStaticFiles();
//app.UseCors(CorsOptions.AllowAll);
app.UseSignalR(routes =>
{
routes.MapHub<cRioHub>(virtDir);
});
app.UseMvc();
app.Run(async (context) =>
{
await context.Response.WriteAsync("cRioHub Started!");
});
}
/*
var hubContext = provider.GetService<IHubContext<cRioHub>>();
services.AddSingleton(provider =>
{
var hubContext = provider.GetService<IHubContext<cRioHub>>();
var update = new Update(hubContext);
return update;
});
*/
}
// HUB HOSTED SERVICE which kicks off background thread
public class cRioHubHostService : IHostedService, IDisposable
{
private static Thread _t = null;
public Thread thread
{
get { return _t; }
}
// Summary: Triggered when the application host is ready to start the service.
public Task StartAsync(CancellationToken cancellationToken)
{
_t = LaunchHub();
return Task.CompletedTask;
}
// Summary: Triggered when the application host is performing a graceful shutdown.
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public void Dispose()
{
_t = null;
}
public static Thread LaunchHub()
{
Object orfu = new object(); // saved for fut. use if needed
// set up hub
cRioHubConnection hub = new cRioHubConnection(cRioHubGlobals.getHubUrl(), cRioHubGlobals.getHubUrl().Name);
cRioHubGlobals.setHubConnection(new cRioHubConnection(hub));
//Globals.HubCnxn.SendMessage("Take2!");
// call thread to start TCP client wh. writes back to the hub on cRio msg. arrival
Thread t = new Thread(cRioHubTcpClient.cRioRunClient);
t.IsBackground = true;
t.Start(orfu);
return t;
}
public static void cRioRunClient(Object orfu)
{
string consMsg = "";
string urlHub = cRioHubGlobals.getHubUrl().makeUrl();
string urlCRio = cRioHubGlobals.getCRioUrl().makeUrl();
string fmtHubUrl = "Hub URL={0}" ;
string fmtCRioUrl = "cRio URL={0}";
consMsg = String.Format(fmtHubUrl, urlHub);
Console.WriteLine(consMsg);
consMsg = String.Format(fmtCRioUrl, urlCRio);
Console.WriteLine(consMsg);
cRioHubGlobals.setCRioTcpClient(new cRioHubTcpClient(orfu)); // gets its connection info from cRioHubGlobals
cRioHubGlobals.getCRioTcpClient().Message += (s, a) => Console.WriteLine("Client: " + a.Message);
Task clientTask = cRioHubGlobals.getCRioTcpClient().RunAsync();
Console.WriteLine("Program: Hit any char to stop.");
ConsoleEx.ReadChar();
cRioHubGlobals.getCRioTcpClient().Stop = true;
cRioHubGlobals.getCRioTcpClient().Dispose();
clientTask = null;
}
public static Task cRioStopClient()
{
Task tskHub = null;
cRioHubTcpClient client = cRioHubGlobals.getCRioTcpClient();
if (client != null)
{
client.Stop = true;
client.Dispose();
tskHub = cRioHubGlobals.getHubConnection().Stop();
}
Console.WriteLine("Stopping service!");
return tskHub;
}
The problem is the publisher with the appsettings & launch. If you choose a port other than the default 5000, it is not working. If you choose 5000, it works. This appears to be a bug.

Asp.Net SignalR second tab does not fire onConnected event

I just created a sample project with signalR. I am just trying to test managing multiple connection. Everything works as expected when I open the first browser and load the page. It is going to fire the OnConnected event on the hub. But when I open another browser or different tab and load the page, it doesn't fire OnConnected event anymore. It shows $.connection.hub.id though.
Here is the hub
[HubName("genie")]
public class Genie : Microsoft.AspNet.SignalR.Hub
{
private static ConnectionManager _manager = new ConnectionManager();
[HubMethodName("AdminCommand")]
public void AdminCommand(string command, string message = "")
{
var connetions = _manager.GetConnections();
connetions.Remove(Context.ConnectionId);
Clients.Clients(connetions).onAdminCommand(command, message);
}
public override Task OnConnected()
{
_manager.AddConnection(Context.ConnectionId);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
_manager.RemoveConnection(Context.ConnectionId);
return base.OnDisconnected(stopCalled);
}
}
And here is the javascript code:
var proxy = $.connection.genie;
$.connection.hub.start()
.done(function (state) {
console.log($.connection.hub.id);
});
proxy.on('onAdminCommand', function (command, message) {
if (command == "HappyGenie") {
$scope.goTo("happy/");
} else if (command == "SadGenie") {
$scope.goTo("sad/");
} else if (command == "CustomAnnouncement") {
dataService.setDataByKey("Announcement", message);
$scope.goTo("customannouncement/");
}
});
I establish a connection with the generated proxy.
Is there something I am doing wrong?
Thanks

Configuring WCF Services in Code WCF 4.5

Hi, I am trying to configure wcf using code behind, below is the code:
public static void Configure(ServiceConfiguration config)
{
string configPath = ConfigurationManager.AppSettings["wcfconfigDBPath"];
// Enable “Add Service Reference” support
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
// set up support for http, https, net.tcp, net.pipe
if (isEnabled(configPath, "enablehttp"))
config.EnableProtocol(new BasicHttpBinding());
if (isEnabled(configPath, "enablenettcp"))
config.EnableProtocol(new NetTcpBinding());
if (isEnabled(configPath, "enablepipe"))
config.EnableProtocol(new NetNamedPipeBinding());
}
private static bool isEnabled(string path, string elementName)
{
try
{
string elementValue = string.Empty;
bool returnVal = false;
using (XmlTextReader reader = new XmlTextReader(path))
{
reader.ReadToFollowing(elementName);
if (reader.Read())
elementValue = reader.Value;
}
if (!string.IsNullOrEmpty(elementValue))
{
bool.TryParse(elementValue, out returnVal);
}
return returnVal;
}
catch (Exception ex)
{
return false;
}
}
The above code is not working. I am not sure when the "static void Configure" gets fired.
My question is, is there any way to enable/disable the protocol based on DB/xml configuration without bringing down the service?
New feature in .NET 4.5 which probably can be used in your case:
Note: The configure method is called by WCF before the service host is opened.
The Configure method takes a ServiceConfiguration instance that enables the developer to add endpoints and behaviors. This method is called by WCF before the service host is opened. When defined, any service configuration settings specified in an app.config or web.config file will be ignored.
The following code snippet illustrates how to define the Configure method and add a service endpoint, an endpoint behavior and service behaviors:
public class Service1 : IService1
{
public static void Configure(ServiceConfiguration config)
{
ServiceEndpoint se = new ServiceEndpoint(new ContractDescription("IService1"), new BasicHttpBinding(), new EndpointAddress("basic"));
se.Behaviors.Add(new MyEndpointBehavior());
config.AddServiceEndpoint(se);
config.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
config.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
}
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Refer for complete example to:https://msdn.microsoft.com/en-us/library/hh205277(v=vs.110).aspx

SignalR client in asp.net

I created a server hub in an asp.net application like below
public class Calc : Hub
{
public void CalculateSomething(int a, int b)
{
// start working in a new thread
var task = Task.Factory.StartNew(() => DoCalculate(a, b));
// attach a continuation task to notify
// the client when the work is done
task.ContinueWith(t =>
{
System.Threading.Thread.Sleep(2000);
Clients.addMessage(t.Result);
Caller.notifyCalculateResult(t.Result);
System.Threading.Thread.Sleep(2000);
Caller.notifyCalculateResult("Completed");
Clients.addMessage("Completed");
});
}
private int DoCalculate(int p1, int p2)
{
// do some slow work on the input,
// e.g. call webservice or I/O.
int result = p1 + p2;
//int result = DoSlowWork(p1, p2);
return result;
}
}
Now in another asp.net application I created a client using SiganlR client. But it's not working correctly. I am looking to get data from server as it pushes to client
using System.Threading.Tasks;
using SignalR;
using SignalR.Client;
using SignalR.Client.Hubs;
namespace WebApplication2
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Connect to the service
var hubConnection = new HubConnection("http://localhost:3119/");
// Create a proxy to the chat service
var chat = hubConnection.CreateProxy("Calc");
// Print the message when it comes in
chat.On("addMessage", message =>Print(message));
// Start the connection
hubConnection.Start().Wait();
// Send a message to the server
chat.Invoke("CalculateSomething", 1, 2).Wait();
}
private async void Print(object message)
{
Response.Write(message);
}
}
}
The console client application works fine. The main problem is with asp.net beacause it fails to the handle call back from server.
Looks like you calling the server side method wrongly, try this
chat.Invoke("CalculateSomething", 1, 2).ContinueWith(task =>
{
Console.WriteLine("Value from server {0}", task.Result);
});

Resources