Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simply cannot make SignalR (asp.net mvc4) and require.js work together

I've seen similar posts around the web and nothing anyone has suggested works for me. I'm really faced with the choice of dumping one or the other it seems at this point.

This "Getting Started with SignalR and MVC 4 tutorial":

http://www.asp.net/signalr/overview/getting-started/tutorial-getting-started-with-signalr-and-mvc-4

says you need two script includes to make signalR work:

    <!--Reference the SignalR library. -->
    <script src="~/Scripts/jquery.signalR-1.0.1.js"></script>
    <!--Reference the autogenerated SignalR hub script. -->
    <script src="~/signalr/hubs"></script>

I'm at a loss as to how to make the second one, the autogenerated SignalR hub script, happen in require.js. Unless I'm missing something there just doesn't seem to be a viable require.js syntax for inclusion of autogenerated scripts. Without it you get this error at line 159 of jquery.signalR-1.1.2.js:

"JavaScript runtime error: SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. "

The code at that point in jquery.signalR is doing this:

    signalR.hub = {
            start: function () {
                // This will get replaced with the real hub connection start method when hubs is referenced correctly
                throw new Error("SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/hubs'></script>.");
        }
    };

Has anyone actually made this autogenerated script thing happen via require.js?

Been studying this a bit more. Let me add some detail:

I'm using this approach - Structuring scalable client side applications: (http://johndavidmathis.wordpress.com/2013/04/23/structuring-scalable-client-side-applications/) to make a more scalable structure. Second part in that series "Permit modules to utilize multiple files and a logical folder structure" http://johndavidmathis.wordpress.com/2013/04/23/structuring-scalable-client-side-applications/ has me splitting my actual signalr code out into a separate Marionette chat module (separate from my main app.js file) to achieve a better file structure. I really like this approach. The rest of my project is set up like this now and it really is showing benefits when it comes to finding code. I think that extra split is where I'm stuck. Can't seem to get that second dependency, the autogenerated script, into that separate chat module file. I'm still studying this but it looks like this to me at this point. require.js gets the dependency into my Marionette app:

    require(["marionette","handlebars", "signalr", "signalr.hubs"], function (Marionette) {
        window.App = new Marionette.Application();

        App.addRegions({
            headerRegion: "#header",
            contentRegion: "#content",
            footerRegion: "#footer",
        });            

        require(["modules/main/loader", "modules/chat/loader"], function () {
            App.start();
        });
    })

If I want chat that dependency to make its way further into the app, into the chat module in another file?

Something like?

    define(dependencies,
        function () {
            App.module("ChatModule", function (ChatModule, App, Backbone, Marionette, $, _, "signalr.hubs", "signalr.hubs") {

            // SignalR Proxy created on the fly
                var chat = $.connection.chatHub;

                // Start the connection
                $.connection.hub.start();

    //more chat code...

An update:

The answer below does work in my dev environment. But it does not work when I publish the code to a real production server.

When the code is published to a real production server (IIS 6.1 on Windows Server Enterprise 2008 R2) the browser console once again shows a "404" for the autogenerated reference.

Specifically, the console shows the "?" is being added into the reference path before ".js", like this...

http://mydomain.com/myapp/Scripts/application/signalr/hubs?.js...

Tried taking the "?" out but then it removes my app name from the path, like this...

http://mydomain.com/signalr/hubs.js.

I think what would get me there is the first one, without the "?", like...

http://mydomain.com/myapp/Scripts/application/signalr/hubs.js

I'm just not seeing how to make that happen.

FINAL UPDATE:

Final piece of the puzzle for production server is the site's virtual directory. Here's final code that worked for me. Thanks Raciel R for your help:

    requirejs.config({        
        paths: {
            //core
            "jquery": "jquery-1.9.1",

            "signalr": "jquery.signalR-1.1.2",
            "signalr.hubs": "/productionservervirtualdirectory/signalr/hubs?"
        },
        shim: {
            "jquery": {exports: "$"},            
            "signalr": { deps: ["jquery"] },
            "signalr.hubs": { deps: ["signalr"] }
        });
    //Then all you have to do is to make signalr.hubs required in your modules. Ie:

    require(["signalr.hubs"], function(){
         //your code here
    });
like image 680
Robert Avatar asked Aug 02 '13 16:08

Robert


2 Answers

requirejs.config({        
    paths: {
        //core
        "jquery": "jquery-1.9.1",

        "signalr": "jquery.signalR-1.1.2",
        "signalr.hubs": "/signalr/hubs?"
    },
    shim: {
        "jquery": {exports: "$"},            
        "signalr": { deps: ["jquery"] },
        "signalr.hubs": { deps: ["signalr"] }
    });

Then all you have to do is to make signalr.hubs required in your modules. Ie:

require(["signalr.hubs"], function(){
     //your code here
});
like image 106
Raciel R. Avatar answered Nov 13 '22 17:11

Raciel R.


I set up RequireJS successfully using @raciel-r's solution but I was still having problems with other JavaScript modules like karma that were also confused by the dynamic proxy. I converted the signalr proxy to a static file and used that with RequireJS instead:

  1. Import Microsoft.AspNet.SignalR.Utils

  2. Run packages/Microsoft.AspNet.SignalR.Utils.2.X.X/tools/signalr.exe ghp /path:my/bin /o:path/to/scripts/server.js where /my/bin is the directory containing the assemblies with your SignalR Hubs.

  3. Replace your reference in to /signalr/hubs with server:

    requirejs.config({        
    paths: {
         // ...
         "signalr.hubs": "path/to/scripts/server"
    },
    //  ....
    
  4. If you are using the convenience methods of the generated proxy, you will also have to rewrite them (see How to create a physical file for the SignalR generated proxy)

like image 39
mikebridge Avatar answered Nov 13 '22 16:11

mikebridge