SignalR and MVC bundle
Asked Answered
A

6

25

I'm trying to use SignalR with MVC bundle, but having problem finding out how to include the /signalr/hubs script into the bundle. For now I have to insert the path in between jquery.signalR and my code. That will result in three javascript file requests.

Is there any way to include /signalr/hubs into my mvc bundle?

Antidepressant answered 19/7, 2012 at 7:43 Comment(0)
S
14

The default /signalr/hubs script is generated dynamically by the runtime on the first request and then cached.

You can use hubify.exe (see http://weblogs.asp.net/davidfowler/archive/2012/06/10/signalr-0-5-1-released.aspx for details) to pre-generate the file yourself, so you can add it into the MVC bundle.

Skivvy answered 19/7, 2012 at 16:40 Comment(3)
This works well in most cases. Except if the site is hosted in a virtual directory. The hubs js generates this $.hubConnection("/signalr" ... which will not work if the site is in a virtual directory.Comber
Went to the link above and the link to generate hubify.exe is in github.com/SignalR/SignalR/tree/master/SignalR.ProxyGenerator and that does not workAcidimetry
It's not super well documented but you can do this now using Microsoft.AspNet.SignalR.Utils. Quick steps: * Install Microsoft.AspNet.SignalR.Utils using nuget * Add something like this to your Post build event: "$(SolutionDir)packages\Microsoft.AspNet.SignalR.Utils.2.2.2\tools\signalr" ghp "$(TargetPath)" XCOPY "$(TargetDir)server.js" "$(ProjectDir)Scripts\hubs" /R /YFurnish
M
49

A bit late, but here is my contribution:
Create a javascript file with the following contents:

(function ($) {
    $.ajax({
        url: "/signalr/hubs",
        dataType: "script",
        async: false
    });
}(jQuery));

Then add the file to the bundles collection.
This will load the "/signalr/hubs" code for you.

Minx answered 6/11, 2012 at 21:47 Comment(8)
cache: true if you want to benefit from client cacheLipetsk
This seems to work with IIS Express but will fail with a 404 error when you deploy to full IIS. How to reference the dynamically generated proxyPaba
@Minx Why "async: false" ?Multicellular
@Multicellular because you don't want other things that depend on it firing before it is loaded.Justiciary
@DarylTeo and in terms of efficiency, this is equal to putting a script html tag in the head?Multicellular
@Multicellular I'm afraid I'm not qualified to answer that. It won't load in the head though, I think.Justiciary
Perhaps I don't understand the code. But isn't signalr/hubs just downloaded separately and not in the bundle? So the only benefit is that you save a line of <script> code in the .cshtml file ?Antipasto
I have no words to thank you enoughSchell
S
14

The default /signalr/hubs script is generated dynamically by the runtime on the first request and then cached.

You can use hubify.exe (see http://weblogs.asp.net/davidfowler/archive/2012/06/10/signalr-0-5-1-released.aspx for details) to pre-generate the file yourself, so you can add it into the MVC bundle.

Skivvy answered 19/7, 2012 at 16:40 Comment(3)
This works well in most cases. Except if the site is hosted in a virtual directory. The hubs js generates this $.hubConnection("/signalr" ... which will not work if the site is in a virtual directory.Comber
Went to the link above and the link to generate hubify.exe is in github.com/SignalR/SignalR/tree/master/SignalR.ProxyGenerator and that does not workAcidimetry
It's not super well documented but you can do this now using Microsoft.AspNet.SignalR.Utils. Quick steps: * Install Microsoft.AspNet.SignalR.Utils using nuget * Add something like this to your Post build event: "$(SolutionDir)packages\Microsoft.AspNet.SignalR.Utils.2.2.2\tools\signalr" ghp "$(TargetPath)" XCOPY "$(TargetDir)server.js" "$(ProjectDir)Scripts\hubs" /R /YFurnish
N
2

I know this is an old thread but I would like to add the following for SignalR 2.x. I really wanted to bundle the proxy using SquishIt and by trial and error I managed to come up with the following:

using Microsoft.AspNet.SignalR
using Microsoft.AspNet.SignalR.Hubs

var resolver = new DefaultHubManager(new DefaultDependencyResolver());
var proxy = new DefaultJavaScriptProxyGenerator(resolver, new NullJavaScriptMinifier());
string iCanHazScriptNao = proxy.GenerateProxy("/signalr");
Necrolatry answered 12/8, 2014 at 6:29 Comment(0)
B
1

From asp.net, using the SignalR.Utils NuGet package, I found that I needed to be in the directory with the DLL that has the hub in it:

(assuming you have a standard solution structure and are using 2.2.0 of SignalR.Utils)

cd C:\YourSolution\YourProjectWithTheHub\bin\Debug
..\..\..\packages\Microsoft.AspNet.SignalR.Utils.2.2.0\tools\signalr.exe ghp

After running the tool, there will be a server.js file in the directory you ran it from (in this case, Debug).

(Note: I couldn't get it to work when specifying the path with the /p flag, and for some reason even when it does work, it creates a temp directory with the signalr.exe file in it)

Butyraldehyde answered 13/5, 2015 at 19:36 Comment(0)
S
1

You can generate the code with the Microsoft.AspNet.SignalR.Utils NuGet package. Add that to your project, then you can add the below as a post-build script (Project -> {project name} Properties -> Build Events). It should be a post-build script and not pre- since you want it to build against your updated hub code after it's compiled.

It will find whatever version of the Microsoft.AspNet.SignalR.Utils package that you have installed and put the server.js file in the Scripts folder.

You must also have a version redirect for Newtonsoft.Json in your web.config file (assuming your project uses Newtonsoft.Json). This is because signalr.exe is built against version 6.0.0 and you're likely using a newer version. The /configFile switch is to tell it to use your project's config file so that it uses the redirect.

Post-build script:

cd $(ProjectDir)\Scripts
FOR /F "usebackq delims=" %%p IN (`dir ..\..\packages /b /ad ^| find "Microsoft.AspNet.SignalR.Utils"`) DO (
  set "UTILSPATH=%%p"
)
$(SolutionDir)\packages\%UTILSPATH%\tools\net40\signalr.exe ghp /path:$(TargetDir) /configFile:$(TargetPath).config

Then include ~/Scripts/server.js in your bundle.

Shoulders answered 31/10, 2022 at 19:53 Comment(0)
A
0

I used @KTW response mentioned on this Thread and here is the complete change

BundleConfig

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
            "~/Scripts/modernizr-2.6.2.js",
            "~/Scripts/jquery-2.2.3.js",
            "~/Scripts/jquery-ui-1.11.4.js",
            "~/Scripts/jquery.multiselect.js",
            "~/Scripts/jquery.dataTables.js",
            "~/Scripts/jquery.jstepper.min.js",
            "~/Scripts/underscore.min.js"
        ));

        bundles.Add(new ScriptBundle("~/bundles/SignalRScripts").Include(
            "~/Scripts/jquery.signalR-2.2.2.min.js",
            "~/Scripts/signalRBundle.js",
            "~/Scripts/Views/Search/SignalRFunctions.js"));
    }
}

SignalRFunctions.js

    $(function() {
    // Declare a proxy to reference the hub.
    var usersHub = $.connection.currentUsersHub;
    //Create a function that the hub can call to broadcast messages.
    usersHub.client.broadcastMessage = function(reservationNumber, usrName) {
        //Message broadcast from server
        //now find the id with reservationNumber on the page and to that append the user name
        var id = '#' + reservationNumber;
        if ($(id).length) {
            if (usrName.length) {
                itemsOpened($(id), usrName);
            } else {
                itemsClosed($(id));
            }
        } 
        //else {
        //    //is it possible that server broad casted for a reservationNumber and is not available at the client?
        //}
    };

    //Accepts dictionary from hub and goes through search results
    //https://mcmap.net/q/538049/-reading-c-dictionary-in-javascript
    usersHub.client.broadcastCollection = function (reservationNumberAndUsers) {
       for (var resNumKey in reservationNumberAndUsers) {
            if (reservationNumberAndUsers.hasOwnProperty(resNumKey)) {
                //Message broadcast from server
                //now find the id with ReservationNumber on the page and to that append the user name
                var id = '#' + resNumKey;
                if ($(id).length) {
                    if (reservationNumberAndUsers[resNumKey].length) {
                        itemsOpened($(id), reservationNumberAndUsers[resNumKey]);
                    } else {
                        itemsClosed($(id));
                    }
                }
            }
        }
    };

    $.connection.hub.start().done(function() {
                var searchedReservationNumbers = [];
                if (typeof jsData !== 'undefined') {
                    if (jsData && jsData.length) {
                        for (var i = 0; i < jsData.length; i++) {
                            searchedReservationNumbers.push(jsData[i].UReservationNumber);
                        }
                        if (searcheduReservationNumbers.length !== 0) {
                            usersHub.server.getWorkingUsersOnUReservationNumber(searcheduReservationNumbers);
                        }
                    }
                }
            }).fail(function () { console.log('Could not Connect To SignalrHub!'); });
        /*In case we would decide to continuously reconnect making connection to server.
        $.connection.hub.disconnected(function() {
            setTimeout(function() {
                    $.connection.hub.start();
                },
                5000); // Restart connection after 5 seconds.
        });*/

function itemsOpened(elem, id) {
    var item = "Opened By - " + id;
    elem.prop('title', item);
    elem.css('background-color', 'chocolate');
};

function itemsClosed(elem) {
    elem.prop('title', "");
    elem.css('background-color', '');
};
});

signalRBundle.js

(function ($) {
$.ajax({
    url: "/signalr/hubs",
    dataType: "script",
    async: false
});
}(jQuery));
/* Source https://mcmap.net/q/524884/-signalr-and-mvc-bundle */

SomePartialView.cshtml Instead of writing below in above partial view

@using Localization
@using Newtonsoft.Json
@model NameSpace.ViewModels.FilterVM

@{
    ViewBag.Title = Strings.Filter;
}

@using (Html.BeginForm())
{
    <div class="large-12 columns">
        ---SOME CODE HERE 
    </div>

}

@section scripts
{
<script type="text/javascript" language="javascript">
    var jsData = @Html.Raw(JsonConvert.SerializeObject(Model));
</script>
<script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
<script src="~/signalr/hubs"></script>
<script src="~/Scripts/Views/Search/SignalRFunctions.js"></script>
}

This changed to

 @using Localization
    @using Newtonsoft.Json
    @model NameSpace.ViewModels.FilterVM

    @{
        ViewBag.Title = Strings.Filter;
    }

    @using (Html.BeginForm())
    {
        <div class="large-12 columns">
            ---SOME CODE HERE 
        </div>

    }

    @section scripts
    {
    <script type="text/javascript" language="javascript">
        var jsData = @Html.Raw(JsonConvert.SerializeObject(Model));
    </script>
    @Scripts.Render("~/bundles/SignalRScripts")
    }

Notice

@Scripts.Render("~/bundles/SignalRScripts") 

in partial view above.Without @KTW file above(ajax request to /signalr/hubs)

var usersHub = $.connection.currentUsersHub;

was always coming as null.

Acidimetry answered 29/11, 2017 at 20:33 Comment(1)
As @mathew leger pointed out below This seems to work with IIS Express but will fail with a 404 error when you deploy to full IIS.Acidimetry

© 2022 - 2024 — McMap. All rights reserved.