user610217
user610217

Reputation:

SignalR triggering events client-side in MVC3

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.

Upvotes: 1

Views: 1561

Answers (1)

Drew Marsh
Drew Marsh

Reputation: 33379

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) {

Upvotes: 1

Related Questions