Connection to SignalR Hub fails with Negotiate 404

2019-06-12 11:06发布

问题:

I've been researching this issue for 3 days now and cannot find a solution. I created a SignalR Hub with the following code:

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;

namespace Messenger.Hubs
{
    public class MessengerHub : Hub 
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
}

Simple enough, the startup code is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Messenger.Hubs;

namespace Messenger
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddSignalR();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseSignalR(routes =>
            {
                routes.MapHub<ChatHub>("c:/myapp/Messenger");
            });
            app.UseMvc();
        }
    }
}

I pretty much cut and pasted the code from a solution posted on the internet somewhere, I forget where, not stackoverflow though. I then created the following client in a Xamarin (v4.12.3.81) project using Visual Studio 2017 (v15.9.10). That code is:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;

namespace SignalR.Client.Hubs
{
    public class SampleHub
    {
        // MessengerHub is a appliaction folder aliased as MessengerHub
        // the direct path on the machine is c:\mywebapp\messenger
        private const string _hubUrl = "http://example.com/MessengerHub";
        private readonly HubConnection _hubConnection;
        public event EventHandler<string> OnMessageReceived;

        public SampleHub()
        {
            var builder = new HubConnectionBuilder().WithUrl(_hubUrl);
            _hubConnection = builder.Build();
        }

        public async Task<bool> ConnectAsync()
        {
            try
            {
                await _hubConnection.StartAsync();
                _hubConnection.On("messageReceived", (string platform, string message) =>
                {
                if (OnMessageReceived != null)
                    {
                        OnMessageReceived(this, string.Format("{0}: {1}", platform, message));
                    }
                });
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
                //Console.WriteLine($"Connection error: {ex.Message}");
                return false;
            }

            return true;
        }

        public async Task<int> GetNumberAsync(int number)
        {
            return await _hubConnection.InvokeAsync<int>("GetNumber", number);
        }

        public Task Send(string message)
        {
            return _hubConnection.SendAsync("Send", message);
        }
    }
}

The code in the activity that uses that client is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;

using Android.Views.InputMethods;
using SignalR.Client.Hubs;


namespace MyXamarinApp
{
    [Activity(Label = "Messenger")]
    public class Messenger : Activity
    {
        protected override async void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Create your application here
            SetContentView(Resource.Layout.Messenger);

            RequestedOrientation = Android.Content.PM.ScreenOrientation.Portrait;
            try
            {
                var input = FindViewById<EditText>(Resource.Id.Input);
                var messages = FindViewById<ListView>(Resource.Id.Messages);

                var inputManager = (InputMethodManager)GetSystemService(InputMethodService);
                var adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, new List<string>());

                messages.Adapter = adapter;

                var hub = new SampleHub();


                await hub.ConnectAsync(); // <---- fails here

                input.EditorAction +=
                  delegate
                  {
                      inputManager.HideSoftInputFromWindow(input.WindowToken, HideSoftInputFlags.None);

                      if (string.IsNullOrEmpty(input.Text))
                          return;

                      hub.Send(input.Text);

                      input.Text = "";
                  };

                hub.OnMessageReceived +=
                  (sender, message) => RunOnUiThread(() =>
                    adapter.Add(message));
            }
            catch (Exception ex)
            {
                var msg = ex.Message;
            }
        }
    }
}

The hub is (I believe) running correctly on the server, I set logging on and this is what is in the log:

Hosting environment: Production
Content root path: C:\mywebapp\Messenger
Application started. Press Ctrl+C to shut down.

The attempt to connect to the hub generates the following error:

{System.Net.Http.HttpRequestException: 404 (Not Found)

  at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode () [0x0002a] in <25ebe1083eaf4329b5adfdd5bbb7aa57>:0

  at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection+<NegotiateAsync>d__44.MoveNext () [0x00226] in <843c441fa9954906b53e3710152bebb9>:0

--- End of stack trace from previous location where exception was thrown
  --- at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection+<GetNegotiationResponseAsync>d__51.MoveNext () [0x00077] in <843c441fa9954906b53e3710152bebb9>:0

--- End of stack trace from previous location where exception was thrown
  ---
 at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection+<SelectAndStartTransport>d__43.MoveNext () [0x00169] in <843c441fa9954906b53e3710152bebb9>:0

--- End of stack trace from previous location where exception was thrown
  ---
  at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection+<StartAsyncCore>d__40.MoveNext () [0x00118] in <843c441fa9954906b53e3710152bebb9>:0

--- End of stack trace from previous location where exception was thrown
  --- at System.Threading.Tasks.ForceAsyncAwaiter.GetResult () [0x0000c] in <843c441fa9954906b53e3710152bebb9>:0

  at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection+<StartAsync>d__39.MoveNext () [0x0008b] in <843c441fa9954906b53e3710152bebb9>:0

--- End of stack trace from previous location where exception was thrown
  --- at Microsoft.AspNetCore.SignalR.Client.HttpConnectionFactory+<ConnectAsync>d__3.MoveNext () [0x0009d] in <d50de232736c4c8f910083ea0cb358a8>:0

--- End of stack trace from previous location where exception was thrown
  ---
 at Microsoft.AspNetCore.SignalR.Client.HttpConnectionFactory+<ConnectAsync>d__3.MoveNext () [0x00142] in <d50de232736c4c8f910083ea0cb358a8>:0

--- End of stack trace from previous location where exception was thrown
  ---
 at Microsoft.AspNetCore.SignalR.Client.HubConnection+<StartAsyncCore>d__47.MoveNext () [0x00130] in <f381011e9b214489bcb373743f31ed9d>:0

--- End of stack trace from previous location where exception was thrown
  ---
 at System.Threading.Tasks.ForceAsyncAwaiter.GetResult () [0x0000c] in <f381011e9b214489bcb373743f31ed9d>:0

  at Microsoft.AspNetCore.SignalR.Client.HubConnection+<StartAsync>d__39.MoveNext () [0x00091] in <f381011e9b214489bcb373743f31ed9d>:0

--- End of stack trace from previous location where exception was thrown
  ---
  at SignalR.Client.Hubs.SampleHub+<ConnectAsync>d__6.MoveNext () [0x00037] in C:\Users\<username>\Documents\Visual Studio 2017\Projects\signalr_client\signalr_client\Resources\layout\Client.cs:28 }

This is what I see in the IIS Log for the site.

"POST /MessengerHub/negotiate HTTP/1.1" 303 446
"GET /MessengerHub/negotiate HTTP/1.1" 404 1509

I have no idea what to try next.