2015-02-20 25 views
6

Tôi có ứng dụng MVC 5 phục vụ chế độ xem và ứng dụng Web API 2 làm lớp dịch vụ (.NET 4.5). Ứng dụng Web API sử dụng SignalR 2.1.2 để trả về tiến trình vì nó xử lý POST cho API dịch vụ. Cả hai được triển khai cho các miền khác nhau, vì vậy tôi đã thiết lập hỗ trợ gốc chéo theo bài viết hướng dẫn asp.net.Kết nối SignalR gốc dừng lại sau khi thương lượng

[assembly: OwinStartup(typeof (Startup))] 
namespace MyApp.Service 
{ 
    public class Startup 
    { 
     public void Configuration(IAppBuilder app) 
     { 
      app.Map("/signalr", map => 
      { 
       //worry about locking it down to specific origin later 
       map.UseCors(CorsOptions.AllowAll); 
       map.RunSignalR(new HubConfiguration()); 
      }); 
      //now start the WebAPI app 
      GlobalConfiguration.Configure(WebApiConfig.Register); 
     } 
    } 
} 

WebApiConfig.cs cũng chứa khai báo CORS của riêng nó.

namespace MyApp.Service 
{ 
    public static class WebApiConfig 
    { 
     public static void Register(HttpConfiguration config) 
     { 
      //controller invocations will come from the MVC project which is deployed to a 
      //different domain, so must enable cross origin resource sharing 
      config.EnableCors(); 
      // Web API routes 
      config.MapHttpAttributeRoutes(); 

      //Snip other controller dependency initialisation 
     } 
    } 
} 

Tôi đã xác định một lớp trung tâm đơn giản không có API phía máy chủ (nó chỉ cho phép máy chủ đẩy tới máy khách chứ không phải cho khách hàng gọi vào).

namespace MyApp.Service.Hubs 
{ 
    [HubName("testresult")] 
    public class TestResultHub : Hub 
    { 
    } 
} 

Vì tôi sẽ chuyển sang miền chéo VÀ trung tâm không hiển thị bất kỳ API phía máy chủ nào, tôi không bận tâm khi sử dụng proxy JS được tạo.

Các bit liên quan của JS thiết lập kết nối trung tâm signalr là: (nhớ điều này đang được phân phát từ ứng dụng MVC, không có bất kỳ hỗ trợ signalr nào (ngoại trừ jquery-signalr- {version} .js of Tất nhiên))

function TestScenarioHandler(signalrHubUrl) { 
    var self = this; 
//Snip irrelevant bits (mostly Knockout initialisation) 

    self.signalrConnectionId = ko.observable(); 

    var hubConnection = $.hubConnection(signalrHubUrl, { useDefaultPath: false }); 

    var hubProxy = hubConnection.createHubProxy("testresult"); 
    hubProxy.on("progress", function(value) { 
     console.log("Hooray! Got a new value from the server: " + value); 
    }); 

    hubConnection.start() 
     .done(function() { 
      self.signalrConnectionId(hubConnection.id); 
      console.log("Connected to signalr hub with connection id " + hubConnection.id); 
     }) 
     .fail(function() { 
      console.log("Failed to connect to signalr hub at " + hubConnection.url); 
     }); 
} 

Đi chéo nguồn gốc như thế này, Firefox mạng chương trình giao thông (và tôi đã khẳng định Chrome sẽ hiển thị những điều tương tự) một GET để

http://****service.azurewebsites.net/signalr/negotiate?clientProtocol=1.5&connectionData=[{"name":"testresult"}]&_=1424419288550

Chú ý rằng name trận đấu giá trị của thuộc tính HubName trên lớp trung tâm của tôi.

GET này trả về HTTP 200, phản hồi cung cấp cho tôi tải trọng JSON chứa ConnectionId, ConnectionToken và một loạt các trường khác cho thấy mọi thứ đều ổn. Phản hồi HTTP cũng có tiêu đề Access-Control-Allow-Origin: được đặt thành tên miền mà GET bắt nguồn từ đó. Tất cả có vẻ tốt, ngoại trừ đó là nơi giao thông dừng lại.

Nhưng giao diện điều khiển JS in "Failed to connect to signalr hub at http://****service.azurewebsites.net/signalr"

Để xác minh Tôi không làm bất cứ điều gì quá ngu ngốc, tôi đã thêm hỗ trợ signalr và một trung tâm cơ bản để ứng dụng MVC (vì vậy không có nguồn gốc chéo bắt buộc), và đã thay đổi $.hubConnection()hubConnection.createProxy() cuộc gọi tương ứng. Khi tôi thực hiện điều đó, lưu lượng truy cập trình duyệt hiển thị cùng một thông số /signalr/negotiate?... GET (rõ ràng không phải là nguồn gốc chéo), nhưng sau đó cũng GET đến /signalr/connect?.../signalr/start?.... Bảng điều khiển JS cũng in một thông báo thành công.

Vì vậy, tóm lại;

  • CORS được kích hoạt trên lớp dịch vụ, và các signalr /negotiate GET trả về 200, những gì dường như là một id kết nối hợp lệ, và dự kiến ​​Access-Control-Allow-Origin: tiêu đề. Điều này cho thấy rằng sự hỗ trợ CORS phía máy chủ đang hoạt động chính xác, nhưng kết nối signalr không thành công.
  • Khi tôi cấu hình lại để kết nối tín hiệu KHÔNG phải là nguồn gốc chéo, mọi thứ hoạt động như mong đợi.

WTF Tôi đang thiếu hoặc đang làm sai? Một số xung đột giữa HttpConfiguration.EnableCors()IAppBuilder.UseCors(CorsOption) có lẽ?

+0

Trình tạo và trình phân phối ... Có vẻ như khi máy khách JS tín hiệu quyết định đó là yêu cầu có nguồn gốc chéo, nó sẽ thay đổi ứng dụng http-Kiểu nội dung từ "application/json; charset = UTF-8" thành '"/x-www-form-urlencoded; charset = UTF-8 "'. Tôi không có ý tưởng tại sao nó sẽ làm điều đó, cũng không phải lý do tại sao nó nên tạo sự khác biệt. – tones

Trả lời

6

Giải quyết. Thay vào đó, tôi đã thay đổi map.UseCors(CorsOptions.AllowAll) để chuyển đối tượng CorsPolicy và đặt SupportsCredentials thành sai, đã đọc ở nơi khác mà Access-Control-Allow-Origin: * không tương thích với access-control-allow-credentials: true.

private static readonly Lazy<CorsOptions> SignalrCorsOptions = new Lazy<CorsOptions>(() => 
{ 
    return new CorsOptions 
    { 
     PolicyProvider = new CorsPolicyProvider 
     { 
      PolicyResolver = context => 
      { 
       var policy = new CorsPolicy(); 
       policy.AllowAnyOrigin = true; 
       policy.AllowAnyMethod = true; 
       policy.AllowAnyHeader = true; 
       policy.SupportsCredentials = false; 
       return Task.FromResult(policy); 
      } 
     } 
    }; 
}); 

public void Configuration(IAppBuilder app) 
{ 
    app.Map("/signalr", map => 
    { 
     map.UseCors(SignalrCorsOptions.Value); 
     map.RunSignalR(new HubConfiguration()); 
    }); 
    //now start the WebAPI app 
    GlobalConfiguration.Configure(WebApiConfig.Register); 
} 

Thiết SupportCredentials kết quả đúng trong Access-Control-Allow-Origin tiêu đề được viết lại với nguồn gốc thực tế (không *) và access-control-allow-credentials: true trong các phản ứng.

Và giờ nó hoạt động.

+0

Tôi có cùng một vấn đề nhưng giải pháp này không giải quyết nó, bất kỳ đầu mối khác về những gì nó có thể được? – evilpilaf

+0

Trong trường hợp của tôi, tôi phải tạo chính sách tùy chỉnh như trên, nhưng thay vào đó hãy sử dụng 'SupportsCredentials = true'. – keithl8041

+0

vấn đề của tôi đã được giải quyết bằng cách thay thế map.UseCors mặc định (CorsOptions.AllowAll) thành giải pháp được cung cấp ở trên. Phản ứng tuyệt vời. Bây giờ cors orgin header xuất hiện trong tất cả các tiêu đề phản hồi signalR. –

Các vấn đề liên quan