Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

404 /signalr/negotiate for deployed app in Azure

SignalR works on localhost but doesn't work when is deployed in Azure

Asp.net Core 1.0.0 (.Net Framework 4.6.1)

SignalR.Core 2.2.1

public static void UseSignalR2(this IApplicationBuilder app)
    {
        app.UseAppBuilder(appBuilder => {
            appBuilder.MapSignalR(new HubConfiguration());
        });
        GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule());
        GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule());
    }

SignalR.js 2.2.1 with default settings

$.connection.hub.url = '/signalr';

Expected behavior

200 for url:

https://(name).azurewebsites.com/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22productsimporthub%22%7D%5D&_=1472811629592

Actual behavior

/signalr/negotiate - on localhost returns 200 but for deployed app in azure returns 404

/signalr - works on both - Protocol error: Unknown transport.

/signalr/hubs - works on both - returns the SignalR js correctly

like image 900
user3305104 Avatar asked Nov 08 '22 07:11

user3305104


1 Answers

To find out the real cause of the issue you need to navigate to the negotiate url, and look for the response.

If the response tells you something about a 'CryptographicException: The data protection operation was unsuccessful...'. This is how to fix it.

1) Create a custom IDataProtectionProvider
2) Configure signalr

internal class MachineKeyProtectionProvider : IDataProtectionProvider
{
    public IDataProtector Create(params string[] purposes)
    {
        return new MachineKeyDataProtector(purposes);
    }
}

internal class MachineKeyDataProtector : IDataProtector
{
    private readonly string[] _purposes;

    public MachineKeyDataProtector(string[] purposes)
    {
        _purposes = purposes;
    }

    public byte[] Protect(byte[] userData)
    {
        //return MachineKey.Protect(userData, _purposes);
        return userData;
    }

    public byte[] Unprotect(byte[] protectedData)
    {
        //return System.Web.Security.MachineKey.Unprotect(protectedData, _purposes);
        return protectedData;
    }
}


I use katana extension methods to bridge the IAppBuilder to IApplicationBuilder. This allows your owin middleware to connect to asp.net core. It is important to use the RunSignalr method

app.UseAppBuilder(appBuilder =>
        {
            appBuilder.SetDataProtectionProvider(new MachineKeyProtectionProvider());

            appBuilder.Map("/signalr", map =>
            {
                var hubConfiguration = new HubConfiguration
                {
                    EnableDetailedErrors = true
                };

                map.RunSignalR(hubConfiguration);
            });


        });
like image 89
hannes neukermans Avatar answered Dec 16 '22 16:12

hannes neukermans