2016-08-18 60 views
1

我試圖在通知JavaScript(Aurelia)客戶端(WebApp)的Web API上構建通知服務。我的Web API和WebApp位於不同的域中。無法使SignalR,Web API和SystemJS一起工作

我有一個簡單NotificationHub

public class NotificationHub:Hub 
{ 
    public void NotifyChange(string[] values) 
    { 
     Clients.All.broadcastChange(values); 
    } 
} 

我在網頁API的Startup配置SignalR如下:

public void Configuration(IAppBuilder app) 
{ 
    HttpConfiguration httpConfig = new HttpConfiguration(); 

    var cors = new EnableCorsAttribute("http://localhost:9000", "*", "*"); 
    httpConfig.EnableCors(cors); 

    app.MapSignalR(); 

    WebApiConfig.Register(httpConfig); 
    ... 
} 

在我的Web應用程序,我想從我的Web訪問signalr/hubs API如下:

Promise.all([... 
     System.import('jquery'), 
     System.import('signalr'), ... 
      ]) 
     .then((imports) => { 
      return System.import("https://localhost:44304/signalr/hubs"); 
      }); 

我hav E也加入了meta節我config.js

System.config({ 
    ... 
    meta: { 
     "https://*/signalr/hubs": { //here I also tried with full url 
      "format": "global", 
      "defaultExtension": false, 
      "defaultJSExtension": false, 
      "deps": ["signalr"] 
     } 
    } 
}); 

儘管這些配置的,我還是有以下問題:

  1. 的請求signalr/hubs,從Web應用程序,作出https://localhost:44304/signalr/hubs.jsHTTP 404返回。請注意,瀏覽https://localhost:44304/signalr/hubs將返回hubs腳本。
  2. $.connection("https://localhost:44304/signalr").start(),我收到以下錯誤:

XMLHttpRequest cannot load https://localhost:44304/signalr/negotiate?clientProtocol=1.5&_=1471505254387 . No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ' http://localhost:9000 ' is therefore not allowed access.

請讓我知道我在這裏失蹤?

更新: 使用適當的CORS的配置,並通過@kabaehr建議gist我現在能夠連接到集線器SignalR。但是,廣播(推送通知)仍然不起作用。

我SignalR配置:

public static class SignalRConfig 
{ 
    public static void Register(IAppBuilder app, EnableCorsAttribute cors) 
    { 

     app.Map("/signalr", map => 
     { 
      var corsOption = new CorsOptions 
      { 
       PolicyProvider = new CorsPolicyProvider 
       { 
        PolicyResolver = context => 
        { 
         var policy = new CorsPolicy { AllowAnyHeader = true, AllowAnyMethod = true, SupportsCredentials = true }; 

         // Only allow CORS requests from the trusted domains. 
         cors.Origins.ForEach(o => policy.Origins.Add(o)); 

         return Task.FromResult(policy); 
        } 
       } 
      }; 
      map.UseCors(corsOption).RunSignalR(); 
     }); 
    } 
} 

我使用它在Startup如下:

var cors = new EnableCorsAttribute("http://localhost:9000", "*", "*"); 
httpConfig.EnableCors(cors); 

SignalRConfig.Register(app, cors); 

WebApiConfig.Register(httpConfig); 

,我試圖以推送通知如下:

GlobalHost.ConnectionManager.GetHubContext<NotificationHub>().Clients.All.broadcastChange(new[] { value }); 

然而,我的客戶沒有通知broadcastChange。我假設我不需要明確導入https://localhost:44304/signalr/hubs,當我使用gist時。

+0

您的來源沒有使用'https'似乎?首先嚐試用「*」來解決問題。 –

+0

@MarkC。感謝您的評論。我曾嘗試用'「*」',但是,我真的不能說是否正常工作與否,'SystemJS'追加'在signalr/hubs'的'年底.js',和我得到一個' 404'。我認爲需要在某種程度上處理,但我不知道如何。 –

+0

有幾個插件系統JS使用它可以預防「的.js」像https://github.com/systemjs/plugin-text的追加,但我不知道這是不是問題。 – kabaehr

回答

0

這只是爲了分享我的發現和解決問題。

所以首先,signalr/hubs只是一個從服務器端代碼自動生成的代理。如果您可以創建自己的SignalR代理客戶端,則不必使用該代理。下面是一個簡單的SignalR客戶端,它基於@kabaehr提到的gist創建。到目前爲止,SignalR客戶端本質上是非常簡單的。這裏需要注意的

export class SignalRClient { 

    public connection = undefined; 
    private running: boolean = false; 

    public getOrCreateHub(hubName: string) { 
     hubName = hubName.toLowerCase(); 
     if (!this.connection) { 
      this.connection = jQuery.hubConnection("https://myhost:myport"); 
     } 

     if (!this.connection.proxies[hubName]) { 
      this.connection.createHubProxy(hubName); 
     } 

     return this.connection.proxies[hubName]; 
    } 

    public registerCallback(hubName: string, methodName: string, callback: (...msg: any[]) => void, 
     startIfNotStarted: boolean = true) { 

     var hubProxy = this.getOrCreateHub(hubName); 
     hubProxy.on(methodName, callback); 

     //Note: Unlike C# clients, for JavaScript clients, at least one callback 
     //  needs to be registered, prior to start the connection. 
     if (!this.running && startIfNotStarted) 
      this.start(); 
    } 

    start() { 
     const self = this; 
     if (!self.running) { 
      self.connection.start() 
       .done(function() { 
        console.log('Now connected, connection Id=' + self.connection.id); 
        self.running = true; 
       }) 
       .fail(function() { 
        console.log('Could not connect'); 
       }); 
     } 
    } 
} 

一個重要的事情是,一個JavaScript SignalR客戶端,我們需要在開始連接之前至少註冊一個回調方法。

隨着地方,你可以如下使用這樣的客戶端代理。雖然下面的代碼示例使用一般aurelia-framework,但在attached()的SignalR部分無關與Aurelia路上。

import {autoinject, bindable} from "aurelia-framework"; 
import {SignalRClient} from "./SignalRClient"; 

@autoinject 
export class SomeClass{ 

    //Instantiate SignalRClient. 
    constructor(private signalRClient: SignalRClient) { 
    } 

    attached() { 
     //To register callback you can use lambda expression... 
     this.signalRClient.registerCallback("notificationHub", "somethingChanged", (data) => { 
      console.log("Notified in VM via signalr.", data); 
     }); 

     //... or function name. 
     this.signalRClient.registerCallback("notificationHub", "somethingChanged", this.somethingChanged); 
    } 

    somethingChanged(data) { 
     console.log("Notified in VM, somethingChanged, via signalr.", data); 
    } 
} 

這是解決方案的關鍵。對於與啓用CORS相關的部分,在問題中已經提到。有關詳細信息,您可以參考以下鏈接: