I new to SignalR.I am developing a Project using signalR
Service side i am using WCF and SignalR.And for Client Side,i am using ASP.NET MVC 4.
I followed the steps in below website:-
Getting Started With SignalR and MVC 5
for my service side,i am installed the package called
Install-Package Microsoft.AspNet.SignalR
And also i am created my owin startup class and SignalR Hub Class in WCF Service.
Owin StartupClass:-
[assembly: OwinStartup(typeof(WCF3.Startup))]
namespace WCF3
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
SignalR HubClass:-
public class ConvHub : Hub
{
public void send(string user)
{
Clients.All.broadcastMesage(user);
}
}
and My WCF Service:-
public class Service1 : IService1
{
public string GetValue(string username)
{
string name = "username ="+username;
Console.WriteLine("u=" + name);
return name;
}
}
My Service side Configuration is Completed.
But i don't know,which package i need to install for ASP.NET MVC ,while Considering MVC as separate Client.
Could Anyone Tell me the package name ,need to install in MVC Client?
you need to install Microsoft.AspNet.SignalR.Client to your wcf service.
configure your start up in wcf service
var connection = new HubConnection("{enter your hub url}");
var myHub = connection.CreateHubProxy("ConvHub");
myHub.Invoke("send", "your username").ContinueWith(task => {
if (task.IsFaulted)
{
Console.WriteLine("There was an error calling send: {0}", task.Exception.GetBaseException());
}
else
{
Console.WriteLine("Send Complete.");
}
});
Related
I'm trying to make a connection between my ASP.NET Core 3.0 Blazor (server-side) application and the Azure SignalR Service. I'll end up injecting my SignalR client (service) in to a few Blazor components so they'll update my UI/DOM in realtime.
My issue is that I'm receiving the following message when I call my .StartAsync() method on the hub connection:
Response status code does not indicate success: 404 (Not Found).
BootstrapSignalRClient.cs
This file loads my configuration for the SignalR Service including the URL, connection string, key, method name, and hub name. These settings are captured in the static class SignalRServiceConfiguration and used later.
public static class BootstrapSignalRClient
{
public static IServiceCollection AddSignalRServiceClient(this IServiceCollection services, IConfiguration configuration)
{
SignalRServiceConfiguration signalRServiceConfiguration = new SignalRServiceConfiguration();
configuration.Bind(nameof(SignalRServiceConfiguration), signalRServiceConfiguration);
services.AddSingleton(signalRServiceConfiguration);
services.AddSingleton<ISignalRClient, SignalRClient>();
return services;
}
}
SignalRServiceConfiguration.cs
public class SignalRServiceConfiguration
{
public string ConnectionString { get; set; }
public string Url { get; set; }
public string MethodName { get; set; }
public string Key { get; set; }
public string HubName { get; set; }
}
SignalRClient.cs
public class SignalRClient : ISignalRClient
{
public delegate void ReceiveMessage(string message);
public event ReceiveMessage ReceiveMessageEvent;
private HubConnection hubConnection;
public SignalRClient(SignalRServiceConfiguration signalRConfig)
{
hubConnection = new HubConnectionBuilder()
.WithUrl(signalRConfig.Url + signalRConfig.HubName)
.Build();
}
public async Task<string> StartListening(string id)
{
// Register listener for a specific id
hubConnection.On<string>(id, (message) =>
{
if (ReceiveMessageEvent != null)
{
ReceiveMessageEvent.Invoke(message);
}
});
try
{
// Start the SignalR Service connection
await hubConnection.StartAsync(); //<---I get an exception here
return hubConnection.State.ToString();
}
catch (Exception ex)
{
return ex.Message;
}
}
private void ReceiveMessage(string message)
{
response = JsonConvert.DeserializeObject<dynamic>(message);
}
}
I have experience using SignalR with .NET Core where you add it so the Startup.cs file using .AddSignalR().AddAzureSignalR() and map a hub in the app config and doing it this way requires certain 'configuration' parameters to be established (i.e. connection string).
Given my situation, where does HubConnectionBuilder get the connection string or a key to authenticate to the SignalR Service?
Is it possible the 404 message is a result of the missing key/connection string?
Okay so it turns out the documentation is lacking a key piece of information here. If you're using the .NET SignalR Client connecting to the Azure SignalR Service, you need to request a JWT token and present it when creating the hub connection.
If you need to authenticate on behalf of a user you can use this example.
Otherwise, you can set up a "/negotiate" endpoint using a web API such as an Azure Function to retrive a JWT token and client URL for you; this is what I ended up doing for my use case. Information about creating an Azure Function to get your JWT token and URL can be found here.
I created a class to hold these two values as such:
SignalRConnectionInfo.cs
public class SignalRConnectionInfo
{
[JsonProperty(PropertyName = "url")]
public string Url { get; set; }
[JsonProperty(PropertyName = "accessToken")]
public string AccessToken { get; set; }
}
I also created a method inside my SignalRService to handle the interaction with the web API's "/negotiate" endpoint in Azure, the instantiation of the hub connection, and the use of an event + delegate for receiving messages as follows:
SignalRClient.cs
public async Task InitializeAsync()
{
SignalRConnectionInfo signalRConnectionInfo;
signalRConnectionInfo = await functionsClient.GetDataAsync<SignalRConnectionInfo>(FunctionsClientConstants.SignalR);
hubConnection = new HubConnectionBuilder()
.WithUrl(signalRConnectionInfo.Url, options =>
{
options.AccessTokenProvider = () => Task.FromResult(signalRConnectionInfo.AccessToken);
})
.Build();
}
The functionsClient is simply a strongly typed HttpClient pre-configured with a base URL and the FunctionsClientConstants.SignalR is a static class with the "/negotiate" path which is appended to the base URL.
Once I had this all set up I called the await hubConnection.StartAsync(); and it "connected"!
After all this I set up a static ReceiveMessage event and a delegate as follows (in the same SignalRClient.cs):
public delegate void ReceiveMessage(string message);
public static event ReceiveMessage ReceiveMessageEvent;
Lastly, I implemented the ReceiveMessage delegate:
await signalRClient.InitializeAsync(); //<---called from another method
private async Task StartReceiving()
{
SignalRStatus = await signalRClient.ReceiveReservationResponse(Response.ReservationId);
logger.LogInformation($"SignalR Status is: {SignalRStatus}");
// Register event handler for static delegate
SignalRClient.ReceiveMessageEvent += signalRClient_receiveMessageEvent;
}
private async void signalRClient_receiveMessageEvent(string response)
{
logger.LogInformation($"Received SignalR mesage: {response}");
signalRReservationResponse = JsonConvert.DeserializeObject<SignalRReservationResponse>(response);
await InvokeAsync(StateHasChanged); //<---used by Blazor (server-side)
}
I've provided documentation updates back to the Azure SignalR Service team and sure hope this helps someone else!
Update: the sample with the serverless sample is deprecated for the management SDK (sample). The management SDK uses a negotiation server.
I create a ASP.NET WebApi project, it use [Authorize] attribute to authorize controllers, such as:
[System.Web.Http.Authorize(Roles="Users, Admins")]
public ValueController : ApiController
{
[HttpGet]
public string GetValue()
{
return "Hello World !";
}
}
now I want to add Signalr to this project. This is what I did:
In App_Start/Startup.Auth.cs, add following codes in ConfigureAuth() function to start SignalR.
app.Map(signalr, map =
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
};
hubConfiguration.EnableDetailedErrors = true;
map.RunSignalR(hubConfiguration);
});
Then I add a MessageHub, trying to allow authorized user to send messages to all clients:
[Microsoft.AspNet.SignalR.Authorize]
public class MessageHub : Hub
{
public void SendMessage(string message)
{
Clients.All.SendMessage(message);
}
}
if I start this project, type http://localhost:4000/signalr/hubs in browser, I can receive a hubs js.
Q1 - For me that means SignalR is working on my WebApi project, right?
now I need to test SendMessage, first thing I did is login through http://localhost:4000/Token, then get an access_token. In webApi I usually put this token in Header:
Authorization : Bearer access_token
to access APIs.
Q2 - now what should I do with this token to access MessageHub?
I have Web Api which serves to CRUD Posts from Web App, Android App and Desktop.
I want to add SignalR to the Web Api, every time when Action Create in Controller gets called I want to notify all users that Post is created.
Problem is, I can't find any implementation in only Web Api, all implementations are in Web App with Web Api or something like that. I read all MSDN documentation about it. I'm strugling for 3-4 days now.
I managed to get to the point where I implemented SignalR, and my server isn't created any signalr/hubs file that I need to call from Web App script. It's only created when I run app locally - if I publish it on Azure that file isn't created.
Anyone have concrete steps for Implementation only in Web Api?
I tried this blog, it has Web Api stuff but have js in project and local html added. It's not standalone REST api.
This is not about not creating signalr/hubs file. It's about creating standalone Web Api with SignalR.
I have startup:
public void Configuration(IAppBuilder app) {
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
app.MapSignalR("/signalr", new Microsoft.AspNet.SignalR.HubConfiguration());
}
My Hub:
public class ServiceStatusHub : Hub {
private static IHubContext hubContext =
GlobalHost.ConnectionManager.GetHubContext<ServiceStatusHub>();
public static void SetStatus(string message) {
hubContext.Clients.All.acknowledgeMessage(message);
}
}
And in my Api Controler I call:
ServiceStatusHub.SetStatus("Status changed!");
I made console application to test Api, added Signal R client and class:
class SignalRMasterClient {
public string Url { get; set; }
public HubConnection Connection { get; set; }
public IHubProxy Hub { get; set; }
public SignalRMasterClient(string url) {
Url = url;
Connection = new HubConnection(url, useDefaultUrl: false);
Hub = Connection.CreateHubProxy("ServiceStatusHub");
Connection.Start().Wait();
Hub.On<string>("acknowledgeMessage", (message) =>
{
Console.WriteLine("Message received: " + message);
/// TODO: Check status of the LDAP
/// and update status to Web API.
});
}
public void SayHello(string message) {
Hub.Invoke("hello", message);
Console.WriteLine("hello method is called!");
}
public void Stop() {
Connection.Stop();
}
}
program.cs:
var client = new SignalRMasterClient("myUrl.com/signalr");
// Send message to server.
client.SayHello("Message from client to Server!");
I getting 500 Internal Server Error.
How can I test is my Web Api signalR works for sure?
I see some problems:
1) You do not need the hubContext field in your hub. You inherit from Hub. This class contains allready a "Clients" property .
public class ServiceStatusHub : Hub {
public static void SetStatus(string message) {
Clients.All.acknowledgeMessage(message);
}
}
2) Log errors at starting of server.
public SignalRMasterClient(string url) {
Url = url;
Connection = new HubConnection(url, useDefaultUrl: false);
Hub = Connection.CreateHubProxy("ServiceStatusHub");
Connection.Start().ContinueWith(task => { if (task.IsFaulted) {
Console.WriteLine("There was an error opening the connection:{0}",
task.Exception.GetBaseException());
} else {
Console.WriteLine("Connected");
}
});
Hub.On<string>("acknowledgeMessage", (message) =>
{
Console.WriteLine("Message received: " + message);
/// TODO: Check status of the LDAP
/// and update status to Web API.
}).Wait();
}
3) Check Client url. You need no signalr there in your path at creation of your client.
just:
var client = new SignalRMasterClient("myUrl.com/");
Here you will find a running sample which does all you need:
SignalR Console app example
Everyone! I have have custom WCF SOAP service (chatbot with getAnswer method that takes a string) and my client (website). My IService:
namespace WcfServiceLab1
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetChatbotAnswerUsingDataContract(string question);
}
}
Service.svc:
namespace WcfServiceLab1
{
public class Service1 : IService1
{
public string GetChatbotAnswerUsingDataContract(string question)
{
Chatbot chatbot = new Chatbot();
return chatbot.GetAnswer(question);
}
}
}
And my ChatbotController:
[HttpPost]
public ActionResult Create(string question)
{
try
{
ViewBag.ChatbotAnswer = obj.GetChatbotAnswerUsingDataContract(question.ToLower());
ViewBag.YourQuestion = question;
return View("Index");
}
catch
{
return View("Index");
}
}
It's works on localhost, but when I upload my WCF service on free hosting using FTP and try to add Service References Visual Studio didn't find my service. It's here: http://chatbotservice.esy.es/WcfServiceLab1/
How to "install" wcf service on the remote server? What should I do?
In my project I have different assemblies.
The SignalR hub (and client MVC4 files) live in the Website project.
My hub looks like this:
public class PredictHub : Hub
{
private readonly IChat _chat;
public PredictHub(IChat chat)
{
_chat = chat;
}
public void Chat(String message)
{
_chat.AddMessage(message);
}
}
In my second assembly Business the IChat.cs and Chat.cs live:
public class Chat : IChat
{
public void AddMessage(String message)
{
var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
}
}
But because Chat.cs is in the Business assembly the ChatHub directive is not known because it's not referenced.
How could this be solved?
You can only get the context when SignalR and the Chat class are in the same process.