I want to create Live Chat application using SignalR in ASP.NET MVC. I have created this but the problem is it is sending message to all the users who are connected to that server. I only want to have private chat between two users. So please help me out. Here is my Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
//this is ChatHub.cs file
namespace LiveChat
{
public class ChatHub : Hub
{
public override System.Threading.Tasks.Task OnConnected()
{
Clients.Caller.user(Context.User.Identity.Name);
return base.OnConnected();
}
public void send(string message)
{
Clients.Caller.message("You:" + message);
Clients.Others.message(Context.User.Identity.Name + ": " + message);
}
}}
//This is Startup class
using Microsoft.Owin;
using Owin;
[assembly: OwinStartupAttribute(typeof(LiveChat.Startup))]
namespace LiveChat
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.MapSignalR();
}
}
}
//This is my js
<script>
var hub = $.connection.chatHub;
hub.client.message = function (msg) {
$("#message").append("<li>" + msg + "</li>")
}
hub.client.user = function (msg) {
$("#user").append("<li>" + msg + "</li>")
}
$.connection.hub.start(function () {
$("#send").click(function () {
if ($("#txt").val() == "") {
return;
}
hub.server.send($("#txt").val());
$("#txt").val(" ");
});
$("#txt").keyup(function (event) {
if ($("#txt").val() == "") {
return;
}
if (event.keyCode == 13) {
hub.server.send($("#txt").val());
}
});
});
</script>
you can use a static list , the list contains all client that connected to the hub and their connection id,
on send message, you have to the hub the text and the destination member. and than send to the specific memeber.
add the member to the list in the function OnConnected, the client id :
Context.clientID
send to specific client in function send
var clientId = ""; // get from the static list by id you got
var scbscriber = Clients.Client(clientId);
scbscriber.message(text);
public class ChatHub : Hub
{
private static List<Users> ConnectedUsers;
public ChatHub()
{
ConnectedUsers = new List<Users>();
}
public override System.Threading.Tasks.Task OnConnected()
{
Clients.Caller.user(Context.User.Identity.Name);
ConnectedUsers.Add(new Users(){
UserName = Context.User.Identity.Name,
ClientId = Context.clientID;
});
return base.OnConnected();
}
public void send(string message, string UserName)
{
//Clients.Caller.message("You:" + message);
var clientId = ConnectedUsers.FirstOrDefulat(x=>x.UserName == UserName).ClientId; // get from the static list by id you got
var scbscriber = Clients.Client(clientId);
scbscriber.message(Context.User.Identity.Name + ": "message);
//Clients.Others.message(Context.User.Identity.Name + ": " + message);
}
}
public class Users
{
public string UserName{get;set;}
public string ClientId {get;set;}
}
Here you go mate:
public void SendPrivateMessage(Messaging objMessaging)
{
var fromNurse = objConnectedUserList.FirstOrDefault(x => x.NurseId == objMessaging.FromNurseId);
var toNurse = objConnectedUserList.FirstOrDefault(x => x.NurseId == objMessaging.ToNurseId);
var chatObject = new { MessageThreadId = 0, Name = fromNurse.NurseName, Message = objMessaging.Message, DTStmp = DateTime.Now, frmNurseId = fromNurse.NurseId };
Result objResult = objMessagingDAL.InsertMessage(objMessaging);
if (toNurse != null)
{
Clients.Client(toNurse.ConnectionId).ReceivePrivateMessage(chatObject);
}
Clients.Caller.ReceivePrivateMessage(chatObject);
}
Related
I've implemented ng-chat https://github.com/rpaschoal/ng-chat (SignalR).
I have 3 users: User1, User2 and User3
If I send a message from User1 to User2 it works well User2 receives the message, but if I create a group (with User1 I open User2's chat and then Add the User3) a new group is created with Users (User2 and User3).
So, when I send a message from this new chat, the users (User2 and User3) doesn't receive any message
Here is my SingalR Hub:
using AdvansysOficina.Api._Core.Infraestructura;
using AdvansysOficina.Api.Generales.Servicios.UsuarioNs;
using Microsoft.AspNetCore.SignalR;
using NgChatSignalR.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AdvansysOficina.Api.Desarrollo.Servicios.ConversacionPuntoNs.HubNs
{
public class ConversacionHub : Hub
{
private static List<ParticipantResponseViewModel> AllConnectedParticipants { get; set; } = new List<ParticipantResponseViewModel>();
private static List<ParticipantResponseViewModel> DisconnectedParticipants { get; set; } = new List<ParticipantResponseViewModel>();
private readonly object ParticipantsConnectionLock = new object();
private ISesion _sesion;
private IUsuarioServicio _usuarioServicio;
public ConversacionHub(ISesion sesion, IUsuarioServicio usuarioServicio)
{
_sesion = sesion;
_usuarioServicio = usuarioServicio;
}
public static IEnumerable<ParticipantResponseViewModel> ConnectedParticipants(string currentUserId)
{
return AllConnectedParticipants
.Where(x => x.Participant.Id != currentUserId);
}
public void Join(string userName, dynamic grupo)
{
lock (ParticipantsConnectionLock)
{
AllConnectedParticipants.Add(new ParticipantResponseViewModel()
{
Metadata = new ParticipantMetadataViewModel()
{
TotalUnreadMessages = 0
},
Participant = new ChatParticipantViewModel()
{
DisplayName = userName,
Id = Context.ConnectionId,
}
});
// This will be used as the user's unique ID to be used on ng-chat as the connected user.
// You should most likely use another ID on your application
//Clients.Caller.SendAsync("generatedUserId", Context.ConnectionId);
Clients.Caller.SendAsync("generatedUserId", Context.ConnectionId);
Clients.All.SendAsync("friendsListChanged", AllConnectedParticipants);
}
}
public void SendMessage(MessageViewModel message)
{
var sender = AllConnectedParticipants.Find(x => x.Participant.Id == message.FromId);
if (sender != null)
{
Clients.Client(message.ToId).SendAsync("messageReceived", sender.Participant, message);
}
}
public override Task OnDisconnectedAsync(Exception exception)
{
lock (ParticipantsConnectionLock)
{
var connectionIndex = AllConnectedParticipants.FindIndex(x => x.Participant.Id == Context.ConnectionId);
if (connectionIndex >= 0)
{
var participant = AllConnectedParticipants.ElementAt(connectionIndex);
AllConnectedParticipants.Remove(participant);
DisconnectedParticipants.Add(participant);
Clients.All.SendAsync("friendsListChanged", AllConnectedParticipants);
}
return base.OnDisconnectedAsync(exception);
}
}
public override Task OnConnectedAsync()
{
lock (ParticipantsConnectionLock)
{
var connectionIndex = DisconnectedParticipants.FindIndex(x => x.Participant.Id == Context.ConnectionId);
if (connectionIndex >= 0)
{
var participant = DisconnectedParticipants.ElementAt(connectionIndex);
DisconnectedParticipants.Remove(participant);
AllConnectedParticipants.Add(participant);
Clients.All.SendAsync("friendsListChanged", AllConnectedParticipants);
}
return base.OnConnectedAsync();
}
}
}
}
My signalR Adapter (Angular)
import { ChatAdapter, Message, ParticipantResponse, Group, IChatController } from 'ng-chat';
import { map, catchError } from 'rxjs/operators';
import { HttpClient } from '#angular/common/http';
import * as signalR from '#aspnet/signalr';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { AlertasHelper } from '../../../shared/helpers/alertas.helper';
import { PushNotificationHelper } from './notifications/push-notification';
export class SignalRAdapter extends ChatAdapter {
public static serverBaseUrl = 'http://192.168.16.51:5021/'; // if running locally
public userId: string;
private grrupo;
private hubConnection: signalR.HubConnection;
constructor(private username: string, private http: HttpClient, private notification: PushNotificationHelper
) {
super();
this.initializeConnection();
}
private initializeConnection(): void {
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${SignalRAdapter.serverBaseUrl}chat`, { transport: signalR.HttpTransportType.LongPolling })
.build();
this.hubConnection
.start()
.then(() => {
this.joinRoom();
this.initializeListeners();
})
.catch(err => console.log(`Error while starting SignalR connection: ${err}`));
}
private initializeListeners(): void {
this.hubConnection.on('generatedUserId', (userId) => {
// With the userId set the chat will be rendered
this.userId = userId;
});
this.hubConnection.on('messageReceived', (participant, message) => {
// Handle the received message to ng-chat
console.log(message);
this.notification.notify('Nuevo mensaje de: ' + participant.displayName, message);
this.onMessageReceived(participant, message);
});
this.hubConnection.on('friendsListChanged', (participantsResponse: Array<ParticipantResponse>) => {
// Handle the received response to ng-chat
this.onFriendsListChanged(participantsResponse.filter(x => x.participant.id !== this.userId));
});
}
joinRoom(): void {
if (this.hubConnection && this.hubConnection.state === signalR.HubConnectionState.Connected) {
this.hubConnection.send('join', this.username, '');
}
}
listFriends(): Observable<ParticipantResponse[]> {
// List connected users to show in the friends list
// Sending the userId from the request body as this is just a demo
// return this.http
// .post(`${SignalRAdapter.serverBaseUrl}listFriends`, { currentUserId: this.userId })
// .pipe(
// map((res: any) => res),
// catchError((error: any) => Observable.throw(error.error || 'Server error'))
// );
return of([]);
}
getMessageHistory(destinataryId: any): Observable<Message[]> {
// This could be an API call to your web application that would go to the database
// and retrieve a N amount of history messages between the users.
return of([]);
}
sendMessage(message: Message): void {
if (this.hubConnection && this.hubConnection.state === signalR.HubConnectionState.Connected) {
console.log(message);
this.hubConnection.send('sendMessage', message);
}
}
groupCreated(group: Group): void {
console.log( group);
}
}
Use of component
<ng-chat #chat *ngIf="signalRAdapter && signalRAdapter.userId"
[adapter]="signalRAdapter"
[userId]="signalRAdapter.userId"
[groupAdapter]="signalRAdapter"
(onParticipantChatOpened)="chatOpened($event)"
[historyEnabled]="false">
</ng-chat>
I've downloaded the example of github's creator page, but he doesn't have an example with signalr using groups, I hope you can help me.
ng-chat treats groups as individual participants. You will have to join your room when this event gets invoked:
groupCreated(group: Group): void {
console.log( group);
// Invoke your SignalR hub and send the details of the newly created group
}
ng-chat will generate unique ids every time a group is created so you can track which group is which whenever one gets created from a running ng-chat instance. How you will handle the persistence of these groups is up to your application.
You might want to push a notification to involved users from your SignalR adapter that their friends list has changed (They'll be able to see the group at this stage). You could also decide not to do so and only push a notification if the user who has created the group send an initial message (Once again, up to your application requirements and needs).
You might also want to implement IChatGroupAdapter on your adapter to make the contract more explicit.
Hope this helps!
I have a razor page that calls a rest service to find the geocodes for a supplied address. The call uses a event triggered callback when it completes the lookup. Everything is working, but the timing is off. By the time the callback finishes, the page is already drawn, and I need the results from the callback to properly draw the page.
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Northwind.ModelsDB;
using System.Runtime.Serialization.Json;
using BingMapsRESTToolkit;
using System.Net;
namespace Northwind.Pages.CustomerPages
{
public class DetailsModel : PageModel
{
private readonly Northwind.ModelsDB.NorthwindContext _context;
private readonly IOptions<MyConfig> config;
public string BingMapKey { get; private set; }
public double latitude { get; private set; }
public double longitude { get; private set; }
public string query { get; private set; }
public VIndividualCustomer VIndividualCustomer { get; private set; }
public DetailsModel(Northwind.ModelsDB.NorthwindContext context, IOptions<MyConfig> configg)
{
_context = context;
this.config = configg;
BingMapKey = config.Value.BingMapKey;
}
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
VIndividualCustomer = await _context.VIndividualCustomer
.AsNoTracking()
.FirstOrDefaultAsync(m => m.BusinessEntityId == id);
if (VIndividualCustomer == null)
{
return NotFound();
}
query = VIndividualCustomer.AddressLine1 + " " +
VIndividualCustomer.AddressLine2 + ", " +
VIndividualCustomer.City + ", " +
VIndividualCustomer.StateProvinceName + ", " +
VIndividualCustomer.PostalCode;
query = "1 Microsoft Way, Redmond, WA";
Uri geocodeRequest = new Uri(string.Format("http://dev.virtualearth.net/REST/v1/Locations?q={0}&key={1}", query, BingMapKey));
GetResponse(geocodeRequest, (x) =>
{
var location = (BingMapsRESTToolkit.Location)x.ResourceSets[0].Resources[0];
latitude = location.GeocodePoints[0].Coordinates[0];
longitude = location.GeocodePoints[0].Coordinates[1];
});
return Page();
}
private void GetResponse(Uri uri, Action<Response> callback)
{
System.Net.WebClient wc = new WebClient();
wc.OpenReadCompleted += (o, a) =>
{
if (callback != null)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));
callback(ser.ReadObject(a.Result) as Response);
}
};
wc.OpenReadAsync(uri);
}
}
}
Your method will never be updated because the response is already sent to the client. You need to block the method (use HttpClient instead) and wait for the response:
public async Task<IActionResult> OnGetAsync(int? id)
{
// this "reads" better
if (id.HasValue)
{
return NotFound();
}
VIndividualCustomer = await _context.VIndividualCustomer
.AsNoTracking()
.FirstOrDefaultAsync(m => m.BusinessEntityId == id);
if (VIndividualCustomer == null)
{
return NotFound();
}
query = VIndividualCustomer.AddressLine1 + " " +
VIndividualCustomer.AddressLine2 + ", " +
VIndividualCustomer.City + ", " +
VIndividualCustomer.StateProvinceName + ", " +
VIndividualCustomer.PostalCode;
query = "1 Microsoft Way, Redmond, WA";
// string interpolation
//https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated
var url = $"http://dev.virtualearth.net/REST/v1/Locations?q={query}&key={BingMapKey}";
var geocodeRequest = new Uri(url);
var ser = new DataContractJsonSerializer(typeof(Response));
var response = await (new HttpClient()).GetAsync(geocodeRequest);
var json = await response.Content.ReadAsStringAsync();
var x = ser.ReadObject(json) as Response;
var location = (BingMapsRESTToolkit.Location)x.ResourceSets[0].Resources[0];
latitude = location.GeocodePoints[0].Coordinates[0];
longitude = location.GeocodePoints[0].Coordinates[1];
return Page();
}
The most closed code to your own code is this snippet:
private async Task GetResponseAsync(Uri uri, Action<Response> callback) {
System.Net.Http.HttpClient wc = new HttpClient();
var response = await wc.GetAsync(uri);
if (callback != null) {
var stream = await response.Content.ReadAsStreamAsync();
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));
callback(ser.ReadObject(stream) as Response);
}
}
and call it just like:
await GetResponse(geocodeRequest, (x) =>
{
/ bla bla bla...
});
However, it's not a good refactored code. But can do the job.
I am using Microsoft.AspNetCore.SignalR to broadcast a message to all connected clients. The Hub is hosted in Azure as App Service.
I am able to see the connected client's Connection IDs by inserting them to a table in DB.
When I hit broadcast the messages are send only to 8 out of 10 clients(Always misses few clients). The status of the missed out clients are logged as connected in DB.
My Hub Code:
public class NotificationHub : Hub
{
public override async Task OnConnectedAsync()
{
****Here I insert the connection IDs to DB with connected status***
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalRUsers_" + Context.ConnectionId);
await base.OnConnectedAsync();
}
}
I am calling the HubContext from outside the Hub as I need to broadcast the message on external process completion.
My Broadcaster Code:
public class SignalBroadcaster : ISignalBroadcaster
{
private readonly IHubContext<NotificationHub> _hubContext;
public class SignalRConnections
{
public string ConnectionId { get; set; }
public DateTime ConnectedOn { get; set; }
public string Status { get; set; }
}
public SignalBroadcaster(IHubContext<NotificationHub1> hubContext)
{
_hubContext = hubContext;
}
public async void BroadcastToAll(ISignal signal, TelemetryClient log)
{
List<SignalRConnections> lstsignalRConnections = new List<SignalRConnections>();
try
{
using (SqlConnection conn = new SqlConnection(Environment.GetEnvironmentVariable("XXXXXXX")))
{
using (SqlCommand command = new SqlCommand("", conn))
{
try
{
conn.Open();
command.CommandText = "SELECT * FROM SignalRXXXXXXX WHERE SignalRStatus = 'CONNECTED'";
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
SignalRConnections signalRConnections = new SignalRConnections()
{
ConnectionId = reader.GetString(0),
ConnectedOn = reader.GetDateTime(1),
Status = reader.GetString(2),
};
lstsignalRConnections.Add(signalRConnections);
}
}
}
catch (Exception ex)
{
//command.CommandText = "INSERT INTO SignalRConnections (ConnectionId,ConnectedOn,SignalRStatus) VALUES ('" + Context.ConnectionId + "',GETDATE(),'DISCONNECTED')";
//command.ExecuteNonQuery();
}
finally
{
conn.Close();
}
}
}
foreach (var item in lstsignalRConnections)
{
try
{
await _hubContext.Clients.Client(item.ConnectionId).SendAsync("ReceiveMessage", signal.JobId, signal.QuantificationResult, signal.JobType);
log.TrackTrace("SignalR sent: " + item.ConnectionId);
}
catch(Exception ex)
{
log.TrackTrace("SignalR send failed: " + item.ConnectionId + " Exception :" + ex.ToString());
}
}
}
catch (Exception ex)
{
Exception exp= new Exception(String.Format(Constants.GETDATAEXCEPTIONMESSAGE, "BroadcastToAll ", ex.InnerException));
}
}
}
Please ignore the DB connection mess here as I am doing it for testing purpose. Will refactor later.
My client Code:
connection.on("ReceiveMessage", (user, message,msg1) => {
var msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
var encodedMsg = user + " says " + msg + msg1;
var li = document.createElement("li");
li.textContent = encodedMsg;
document.getElementById("messagesList").appendChild(li);
});
connection.start().catch(err => console.log(err));
Please help me why it is missing few clients randomly. I tried searching lot of articles and help but could not find something specific to this issue.
I've a problem for sending data to the server via POST/DELETE.
I always get a CORS error when I'm trying to send data to the WebAPI.
The client-side was implemented with AngularJS and the server-side with ASP.NET WebAPI by C#.
Here's the Code of server-side WebAPI:
//Model:
public class TestRepository : ITestRepository
{
private List<Person> persons = new List<Person>();
public TestRepository()
{
Add(new Fond { id = "DE001", fname = "John", age = 32 });
Add(new Fond { id = "DE002", fname = "Jeffrey", age = 23 });
}
public IEnumerable<Person> GetAll()
{
return persons;
}
public Person Add(Person item)
{
if (item == null) {
throw new ArgumentNullException();
}
persons.Add(item);
return item;
}
public bool Delete(string id)
{
fonds.RemoveAll(p => p.id == id);
return true;
}
}
//Controller
public class TestController : ApiController
{
static readonly ITestRepository rep = new TestRepository();
// GET api/fond
public IEnumerable<Person> GetAllPersons()
{
return rep.GetAll();
}
// POST api/fond
[HttpPost]
public Person PostPerson(Person item)
{
return rep.Add(item);
}
// DELETE api/fond/5
public bool DeletePerson(string id)
{
if (rep.Delete(id))
{
return true;
}
else
{
return false;
}
}
I've installed the Nuget Package Microsoft.AspNet.WebApi.Cors.
In the WebApiConfig file I've added following lines:
...
var cors = new EnableCorsAttribute("http://localhost:63831", "*", "*");
config.EnableCors(cors);
And the client-side Code:
//Get the list works!
$scope.list = ResService.person.query();
//Delete doesn't work
$scope.deletePerson = function (removePers) {
$scope.res = ResService.person.remove(function () {
$log.info('[Resource]', $scope.res);
$scope.res.$delete(removeItem);
});
};
//Post doesn't work
$scope.addPerson = function (newPers) {
var persObj = {
id: newPers.id,
fname: newPers.fname,
age: newPers.age
};
$http.post(baseUrl + '/api/person', persObj).success(function (persData) {
$scope.list.push(persData);
}).error(function (message) {
$log.error(message);
});
Only GetAll function works. When I'm using POST or DELETE then comes an error message Cross-Origin-Request blocked..
I have an invoice importer hub like so:
public class ImporterHub : Hub, IDisconnect, IConnected
{
public void InvoiceImported(InvoiceImportedMessage message)
{
Clients["importer"].InvoiceImported(message);
}
public void FileImported(FileImportedMessage message)
{
Clients["importer"].FileImported(message);
}
public System.Threading.Tasks.Task Disconnect()
{
return Clients["importer"].leave(Context.ConnectionId, DateTime.Now.ToString());
}
public System.Threading.Tasks.Task Connect()
{
return Clients["importer"].joined(Context.ConnectionId, DateTime.Now.ToString());
}
public System.Threading.Tasks.Task Reconnect(IEnumerable<string> groups)
{
return Clients["importer"].rejoined(Context.ConnectionId, DateTime.Now.ToString());
}
}
In my controller, I'm capturing events for a long-running import process like so:
[HttpPost]
public ActionResult Index(IndexModel model)
{
if (ModelState.IsValid)
{
try
{
model.NotificationRecipient = model.NotificationRecipient.Replace(';', ',');
ImportConfiguration config = new ImportConfiguration()
{
BatchId = model.BatchId,
ReportRecipients = model.NotificationRecipient.Split(',').Select(c => c.Trim())
};
var context = GlobalHost.ConnectionManager.GetHubContext<ImporterHub>();
context.Groups.Add(this.Session.SessionID, "importer");
System.Threading.ThreadPool.QueueUserWorkItem(foo => LaunchFileImporter(config));
Log.InfoFormat("Queued the ImportProcessor to process invoices. Send Notification: {0} Email Recipient: {1}",
model.SendNotification, model.NotificationRecipient);
TempData["message"] = "The import processor job has been started.";
//return RedirectToAction("Index", "Home");
}
catch (Exception ex)
{
Log.Error("Failed to properly queue the invoice import job.", ex);
ModelState.AddModelError("", ex.Message);
}
}
private void LaunchFileImporter(ImportConfiguration config)
{
using (var processor = new ImportProcessor())
{
processor.OnFileProcessed += new InvoiceFileProcessing(InvoiceFileProcessingHandler);
processor.OnInvoiceProcessed += new InvoiceSubmitted(InvoiceSubmittedHandler);
processor.Execute(config);
}
}
private void InvoiceSubmittedHandler(object sender, InvoiceSubmittedEventArgs e)
{
var context = GlobalHost.ConnectionManager.GetHubContext<ImporterHub>();
var message = new InvoiceImportedMessage()
{
FileName = e.FileName,
TotalErrorsInFileProcessed = e.TotalErrors,
TotalInvoicesInFileProcessed = e.TotalInvoices
};
context.Clients["importer"].InvoiceImported(message);
}
private void InvoiceCollectionSubmittedHandler(object sender, InvoiceCollectionSubmittedEventArgs e)
{
}
private void InvoiceFileProcessingHandler(object sender, InvoiceFileProcessingEventArgs e)
{
var context = GlobalHost.ConnectionManager.GetHubContext<ImporterHub>();
var message = new FileImportedMessage()
{
FileName = e.FileName
};
context.Clients["importer"].FileImported(message);
}
I have the following script in my view for the importer:
<script type="text/javascript">
jQuery.connection.hub.logging = true;
var importerHub = jQuery.connection.importerHub;
importerHub.InvoiceImported = function (message) {
jQuery('#' + message.FileName + '_Invoices').text(message.TotalInvoicesInFileProcessed);
jQuery('#' + message.FileName + '_Errors').text(message.TotalErrorsInFileProcessed);
};
importerHub.FileImported = function (message) {
jQuery('#' + message.FileName + '_Processed').text('Done');
};
jQuery.connection.hub.start();
</script>
What I expected to happen:
I was expecting the server side events to trigger, which would send messages to the client,
which would, in turn, fire events to update the status of the import process.
What seems to be happening:
All server-side events trigger, all is well. The signalR library seems to initialize properly, but the events never fire, and I never get the updates to appear on the screen.
What am I doing wrong? This is my first attempt to use the signalR library, so it's entirely possible I'm doing everything wrong.
I believe your problem is that your client side hub events are named with init-caps and the default behavior of SignalR is to translate those to init-lower when publishing to the client to align with common JavaScript conventions. Try changing your hub event registrations to this:
importerHub.invoiceImported = function (message) {
AND
importerHub.fileImported = function (message) {