I'm trying to hit my MVC5 SignalR Hub via a separate, tiny client application, to no avail.
Some background:
I have a regular ASP.NET application using SingalR 1.10, that I can hit with my client. Code:
ASP.NET Hub:
namespace SignalrTest
{
public class ScanHub : Hub
{
public void SendScan(string data, string xmlData)
{
Clients.All.broadcastMessage(data, xmlData);
}
}
}
Client:
connection = new HubConnection("http://localhost:2446/");
hubProxy = connection.CreateHubProxy("ScanHub");
connection.Start();
........
private static async Task RunAsync()
{
object[] param = new object[2];
param[0] = _Data;
param[1] = _xmlData;
await hubProxy.Invoke("SendScan", param);
}
and again, that's working fine. My MVC Hub is identical to the other (I've made sure to change the client HubConnection address), and I have my Startup.cs as:
[assembly: OwinStartupAttribute(typeof(SignalrTest.Startup))]
namespace SignalrTest
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
running my client, it fires off with no errors, but I get no response or any indication that anything has occurred on the MVC side.
Can anyone see where I'm going wrong with the MVC app? I'm unclear on whether I need to alter the routing. I'm happy to post any other code that would help resolve my issue. Thankyou in advance.
Are you really using SignalR 1.1? SignalR 1.1 doesn't use OWIN startup classes, and the MapSignalR method shouldn't even compile.
Try throwing your connection on the .NET client into an async method like so and doing a quick test if your connection is good or not.
private async void Connect()
{
connection = new HubConnection("http://localhost:2446/");
hubProxy = connection.CreateHubProxy("ScanHub");
await connection.Start();
//If using WPF you can test like so if not use whatever output method you prefer to see if it connects
if (Connection.State == Microsoft.AspNet.SignalR.Client.ConnectionState.Connected)
{
MessageBox.Show("Connected!");
}
else
{
MessageBox.Show("Fail!");
}
}
Related
I am using .NET nanoFramework with this sample as a base project to make a REST API that reads and serve my sensors data from ESP32.
using (WebServer server = new WebServer(80, HttpProtocol.Http, new Type[] { typeof(DHTController) }))
{
Debug.WriteLine("Iniciando server...");
var temp = server.Start();
var nis = NetworkInterface.GetAllNetworkInterfaces();
foreach (var ni in nis)
{
Debug.WriteLine("Seu endereço de IP é: " + ni.IPv4Address.ToString());
}
Thread.Sleep(Timeout.Infinite);
}
Everything works fine until i decide to use dependency injection solution for nanoCRL.
The dependency injection seems to work properly but i notice that the constructor Controller dont get called when a request from postman is done. The route responds as spected, but the constructor dont get called and the dependency is not injected as i expected.
private readonly IDHTService service;
public DHTController(IDHTService service)
{
this.service = service;
}
[Route("dht")]
[Method("GET")]
public void Get(WebServerEventArgs e)
{
try
{
var result = service.GetTemperatura();
e.Context.Response.ContentType = "text/plain";
WebServer.OutPutStream(e.Context.Response, result.ToString());
}
catch (Exception)
{
WebServer.OutputHttpCode(e.Context.Response, HttpStatusCode.BadRequest);
}
}
When i make a call from postman, the constructor breakpoint is skiped by the code and the route breakpoint gets called. But without the dependency injected the route dont work properly too.
constructor breakpoint skiped
Can someone help me to understand what is happening in the code? If it is something expected, or a bug. And help me to use dependency injection with nanoFramework, if has another solution.
Seems that you're running into two separate issues.
From your code above it's not obvious what could be the root cause...
Know that work it's underway to offer an official DI library for nanoFramework.
Until that happens you're better raising an issue on the github of the DI library.
I had the same issue. Fortunatly, I found the answer in the nanoframework WebServer sample called "WebServer.DI". (As you stated previously, the simple sample does not allow Dependency Injection because it does not create an instance of the controller)
https://github.com/nanoframework/Samples/tree/main/samples/Webserver/WebServer.DI
You first have to create a class that inherit from the WebServer class and use the IServiceProvider as follow:
internal class WebServerDi : WebServer
{
private readonly IServiceProvider _serviceProvider;
public WebServerDi(int port, HttpProtocol protocol, Type[] controllers, IServiceProvider serviceProvider) : base(port, protocol, controllers)
{
_serviceProvider = serviceProvider;
}
protected override void InvokeRoute(CallbackRoutes route, HttpListenerContext context)
{
route.Callback.Invoke(ActivatorUtilities.CreateInstance(_serviceProvider, route.Callback.DeclaringType), new object[] { new WebServerEventArgs(context) });
}
}
Then, when creating your Web Server, create it using your new class instead of "WebServer":
using (var webServer = new WebServerDi(80, HttpProtocol.Http, new Type[] { typeof(ControllerTest) }, serviceProvider))
{
webServer.Start();
Thread.Sleep(Timeout.Infinite);
}
Now, the instance of the controller will be created using the service provider, allowing some dependency injection magic in your constructor, as we are used to when using the real .Net Framework:
public class ControllerTest
{
private readonly ITextService _textService;
private readonly ITextServiceSingleton _textServiceSingleton;
public ControllerTest(ITextService textService, ITextServiceSingleton textServiceSingleton)
{
_textService = textService;
_textServiceSingleton = textServiceSingleton;
}
[Route("test")]
[Method("GET")]
public void RoutePostTest(WebServerEventArgs e)
{
var content = $"Response from {nameof(ITextService)}: {_textService.GetText()}. Response from {nameof(ITextServiceSingleton)}: {_textServiceSingleton.GetText()}";
e.Context.Response.ContentType = "text/plain";
WebServer.OutPutStream(e.Context.Response, content);
}
}
I am working on a SignalR Clinet-Server connection. My server is WebApi Core 2.1 and my client is WPF .NET Framework 4.7.2.
On the client side I have a singleton hub service with one Instance to recive messages from server:
using System.Collections.ObjectModel;
using Microsoft.AspNetCore.SignalR.Client;
public class HubService
{
//singleton
public static HubService Instance { get; } = new HubService();
public ObservableCollection<string> Notifications { get; set; }
public async void Initialize()
{
this.Notifications = new ObservableCollection<string>();
var hubConnection = new HubConnectionBuilder()
.WithUrl(UrlBuilder.BuildEndpoint("Notifications"))
.Build();
hubConnection.On<string>("ReciveServerUpdate", update =>
{
//todo
});
await hubConnection.StartAsync();
}
}
i initialize it as singleton:
public MainWindowViewModel()
{
HubService.Instance.Initialize();
}
While I'm debugging, on MainWindowViewModel im hitting that HubService.
On Server side its look like this.
Hub:
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
public class NotificationsHub : Hub
{
public async Task GetUpdateForServer(string call)
{
await this.Clients.Caller.SendAsync("ReciveServerUpdate", call);
}
}
Im trigering send message in this way in my controller's methods:
[HttpPost]
public async Task<IActionResult> PostTask([FromBody] Task task)
{
if (!this.ModelState.IsValid)
{
return this.BadRequest(this.ModelState);
}
this.taskService.Add(task);
//here im calling sending message. When im debugging
//i see one connection from my WPF with unique ConnectionId
await this.notificationsHub.Clients.All.SendAsync("ReciveServerUpdate", "New Task in database!");
return this.Ok(task);
}
As I wrote before, while I'm debugging my WebApi, in Clients I have exactly one connection from my WPF. When I turn off WPF, connection count = 0 so connections works perfectly.
But when I call SendAsync(), I'm not reciving any information in WPF in hubConnection.On. Funny thing, yesterday it works perfectly.
So, is my thinking about making HubService as static singleton is right? If its, why i cant recive messages from WebApi by SignalR when my WPF is connected to it?
I asked something similiar yesterday but i found a solution for it. Yesterday, my methods works, i could hit hubConnection.On when i get any message from WebApi. My question from yestarday.
EDIT
Injection of HUb to controller:
private readonly ITaskService taskService;
private readonly IHubContext<NotificationsHub> notificationsHub;
public TaskController(ITaskService taskService, IHubContext<NotificationsHub> notificationsHub)
{
this.taskService = taskService;
this.notificationsHub = notificationsHub;
}
And Startup.cs only SignalR things (i deleted other things not related to signal):
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseSignalR(routes => routes.MapHub<NotificationsHub>("/Notifications"));
}
EDIT2
Here is connection that i can get it, when my client WPF will register his connection:
I tried your code with all kinds of clients (wpf/console/even with a browser), it always works fine for me. The hubConnection.On<string>("ReciveServerUpdate", update => {//todo}); always be invoked when I send a request to PostTask.
I'm not sure why (sometimes) it doesn't work for you somehow . However, when SignalR client has connected to server but gets no message from server, there're possible two reasons:
Your PostTask([FromBody] Task task) action method is not executed. Let's say this is an ApiController method, if the browser posts a request with a Content-Type of application/www-x-form-urlencoded by accident, the invocation of Clients.All.SendAsync(..., ...); won't be executed at all.
The handler of SigalR client (hubConnection.On<>(method,handler)) must has exactly the same argument list as the invocation in order to receive messages. We must be very careful when dealing with this.
Finally, it's better to add a reference to Microsoft.Extensions.Logging.Console
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.*" />
so that we could enable logging to troubleshoot :
var hubConnection = new HubConnectionBuilder()
.WithUrl(UrlBuilder.BuildEndpoint("Notifications"))
.ConfigureLogging(logging =>{
logging.AddConsole(); // enable logging
})
.Build();
I am Developing a Sample Application in SignalR. My Requirement is i need to receive datas from server to client.But i didn't any pass values from client to server.
Is it possible to use the signalr only for receiving data from server to Client and i did correct?
This is myHubClass:-
public class NameHub : Hub
{
public void send(string Item,string Info)
{
//var name = GlobalHost.ConnectionManager.GetHubContext<NameHub>();
Clients.All.broadcastMessage(Item,Info);
}
}
I need to use the HubClass outside the class.so i created a object for that hub class ,used in my solution.
Sample:-
using (NameHub n = new NameHub())
{
n.Clients.All.broadcastMessage(datePicker, IsLoad);
}
This is my Owin StartupClass:-
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
MyClientSide Code:-
$(function () {
var data = $.connection.NameHub;
data.client.broadcastMessage = function (Item,Info) {
$('div.container').append('<p><strong>'+Item+"="
+ Info + '</strong></p>');
};
Could Anyone Provide me an solution to solve this?
Please ensure i did correctly or wrong?
To get Hub instance outside pipeline:
How to use SignalR hub instance outside of the hubpipleline
Don't forget start client side connection: $.connection.hub.start()
I am learning about signalR security in c#. For signalR there is lot for samples and documents available in google. using this i can understand the signalR concepts. i am trying to create console chat app using authorize. Without authorize attribute i can able to send and receive messages. while using "[authorize]" i am getting below error.
Error: InnerException: System.InvalidOperationException
HResult=-2146233079
Message=There was an error invoking Hub method 'Test.DetermineLength'.
Server Program:
public class Program
{
static void Main(string[] args)
{
string url = #"http://localhost:8080/";
using (WebApp.Start<StartUp>(url))
{
Console.WriteLine(string.Format("Server running at {0}", url));
Console.ReadLine();
}
}
public class StartUp
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
[HubName("Test")]
public class TestHub : Hub
{
[Authorize]
public void DetermineLength(string message)
{
Console.WriteLine(message);
string newMessage = string.Format(#"{0} has a length of: {1}", message, message.Length);
Clients.All.ReceiveLength(newMessage);
}
}
}
Client Program:
public class Program
{
static void Main(string[] args)
{
IHubProxy _hub;
string url = #"http://localhost:8080/";
var connection = new HubConnection(url);
_hub = connection.CreateHubProxy("Test");
connection.Start().Wait();
string line = null;
while ((line = System.Console.ReadLine()) != null)
{
_hub.Invoke("DetermineLength", line).Wait();
_hub.On("ReceiveLength", x => Console.WriteLine(x));
}
}
}
How to perform authorized communications between client and server using siganlR in c#. Help me!
From the SignalR official documentation:
SignalR provides the Authorize attribute to specify which users or roles have access to a hub or method. This attribute is located in the Microsoft.AspNet.SignalR namespace. You apply the Authorize attribute to either a hub or particular methods in a hub. When you apply the Authorize attribute to a hub class, the specified authorization requirement is applied to all of the methods in the hub. This topic provides examples of the different types of authorization requirements that you can apply. Without the Authorize attribute, a connected client can access any public method on the hub.
http://www.asp.net/signalr/overview/security/hub-authorization
Who do you want to authorize that method for? Do you have user defined roles?
You cannot use the method with the Authorize attribute because you don't have any users in your application.
Try defining some roles and see if it works.
Good luck!
I am playing around with signalR. First it worked fine, but when I moved the code where I call the client to another class (using IHubContext) no message is triggered at the client anymore.
For example I made a simple hub:
public class EventHub : Hub
{
public EventHub()
{
Do();
}
private async Task Do()
{
while (true)
{
await Task.Delay(2000);
await Clients.All.foo2("BAR2");
}
}
}
But I try the same in another class it is not working anymore.
public class EventHubTester
{
private readonly Lazy<IHubContext> context = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<EventHub>());
public EventHubTester()
{
Do();
}
private async Task Do()
{
while (true)
{
await Task.Delay(2000);
await context.Value.Clients.All.foo("BAR");
}
}
}
I see in the browser log, that foo2 is triggered, foo is not. Any ideas? I am using signalR 2.2.
Regards,
Sebastian
EDIT:
I found the problem. I made a very small example and tested both codes from the post. Then I recognized that it is working fine. So I removed all code from my application step by step until I found the solution:
I use unity for dependency injection and tried two approaches:
DOESNT WORK
HubConfiguration configuration = new HubConfiguration
{
Resolver = new UnitySignalRDependencyResolver(UnityContainer)
};
app.MapSignalR(configuration);
WORKS
GlobalHost.DependencyResolver = new UnitySignalRDependencyResolver(UnityContainer);
app.MapSignalR(configuration);
If somebody can explain me the reason, I would be really happy.