2015-08-22 81 views
1

樞紐方面,我有一個問題,我似乎在無法從ChangedEventHandler新數據發送給連接的信號R的客戶。該文檔說,我可以用得到的樞紐方面: -SignalR解決從change事件處理

var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>(); 
context.Clients.All.addToList(insertedCustomer); 

但是沒有被髮送到客戶端(檢查了小提琴手)或報告的任何錯誤。我onchange事件此刻正在從Application_Start爲我創造一個概念證明接線。我要指出的輪轂確實工作的啓動,並從初始GetAll呼叫

protected void Application_Start() 
    { 
     ... 
     _sqlTableDependency.OnChanged += _sqlTableDependency_OnChanged; 
     _sqlTableDependency.Start(); 
     ... 
    } 

    private void _sqlTableDependency_OnChanged(object sender, RecordChangedEventArgs<BiddingText> e) 
    { 
     switch (e.ChangeType) 
     { 
      case ChangeType.Insert: 
       foreach (var insertedCustomer in e.ChangedEntities) 
       { 
        var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>(); 
        context.Clients.All.addToList(insertedCustomer); 

        biddingTextList.Add(insertedCustomer); 
       } 
       break; 
     } 
    } 

檢索數據。當我把一個斷點在輪轂上context我得到我的ChatHub回來。

我的Javascript代碼:

$.connection.hub.url = "http://localhost:37185/signalr"; 

// Reference the auto-generated proxy for the hub. 
var chat = $.connection.chatHub; 

chat.client.initialText = function(data) { 
    var index; 
    //console.log(data.length); 
    for (index = 0; index < data.List.length; ++index) { 
     $('#list').append("<li>" + data.List[index].text + "</li>"); 
    } 
}; 

chat.client.addToList = function(data) { 
    console.log(data); 
    $('#list').append("<li>" + data.text + "</li>"); 
}; 

// Start the connection. 
$.connection.hub.start({ jsonp: true }).done(function() { 
    chat.server.getAll(1831); 
}); 

我集線器代碼:

public class ChatHub : Microsoft.AspNet.SignalR.Hub 
{ 
    private readonly IMediator mediator; 

    public ChatHub(IMediator mediator) 
    { 
     this.mediator = mediator; 
    } 

    public void GetAll(int saleId) 
    { 
     var model = mediator.Request(new BiddingTextQuery { SaleId = saleId}); 
     Clients.Caller.initialText(model); 
    } 

} 

不知道這是否是相關的,但Clients.Connection.Identity不同的是,每次我用GlobalHost.ConnectionManager.GetHubContext<ChatHub>();

誰能幫助?

回答

4

我有一些類似的問題,而後來建立一個Nancy API來發布一些事件給SignalR客戶端。

我的核心問題是我沒能確保Nancy和SignalR在SignalR全球級使用相同的DI容器。

SignalR與南希一樣,有一個默認的DependencyResolver,用於解決集線器中的任何依賴關係。當我無法爲Nancy和SignalR實現相同的依賴關係源時,我基本結束了兩個獨立的應用程序。

小免責聲明:您還沒有貼出你的配置代碼,所以在這裏我的解決方案是基於一些假設(以及從大衛福勒以下Twitter的答案,當你在Twitter上達到了:

@rippo你有一個自定義依賴解析器和全球已經有另一個你需要現在一些代碼使用一個容器 (https://twitter.com/davidfowl/status/635000470340153344

首先您將n eed實現一個自定義的SignalR depependency解析器,並確保它使用與其他應用程序相同的依賴關係源。

這是我用一個Autofac容器的實現:

using Autofac; 
using Autofac.Builder; 
using Autofac.Core; 
using Microsoft.AspNet.SignalR; 
using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace LabCommunicator.Server.Configuration 
{ 
    internal class AutofacSignalrDependencyResolver : DefaultDependencyResolver, IRegistrationSource 
    { 
     private ILifetimeScope LifetimeScope { get; set; } 

     public AutofacSignalrDependencyResolver(ILifetimeScope lifetimeScope) 
     { 
      LifetimeScope = lifetimeScope; 
      var currentRegistrationSource = LifetimeScope.ComponentRegistry.Sources.FirstOrDefault(s => s.GetType() == GetType()); 
      if (currentRegistrationSource != null) 
      { 
       ((AutofacSignalrDependencyResolver)currentRegistrationSource).LifetimeScope = lifetimeScope; 
      } 
      else 
      { 
       LifetimeScope.ComponentRegistry.AddRegistrationSource(this); 
      } 
     } 

     public override object GetService(Type serviceType) 
     { 
      object result; 

      if (LifetimeScope == null) 
      { 
       return base.GetService(serviceType); 
      } 

      if (LifetimeScope.TryResolve(serviceType, out result)) 
      { 
       return result; 
      } 

      return null; 
     } 

     public override IEnumerable<object> GetServices(Type serviceType) 
     { 
      object result; 

      if (LifetimeScope == null) 
      { 
       return base.GetServices(serviceType); 
      } 

      if (LifetimeScope.TryResolve(typeof(IEnumerable<>).MakeGenericType(serviceType), out result)) 
      { 
       return (IEnumerable<object>)result; 
      } 

      return Enumerable.Empty<object>(); 
     } 

     public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor) 
     { 
      var typedService = service as TypedService; 
      if (typedService != null) 
      { 
       var instances = base.GetServices(typedService.ServiceType); 

       if (instances != null) 
       { 
        return instances 
         .Select(i => RegistrationBuilder.ForDelegate(i.GetType(), (c, p) => i).As(typedService.ServiceType) 
         .InstancePerLifetimeScope() 
         .PreserveExistingDefaults() 
         .CreateRegistration()); 
       } 
      } 

      return Enumerable.Empty<IComponentRegistration>(); 
     } 

     bool IRegistrationSource.IsAdapterForIndividualComponents 
     { 
      get { return false; } 
     } 
    } 
} 

接下來,在你的SignalR的配置,你需要指定自定義依賴解析器:

注:我的應用程序使用了owin,所以你可能不需要HubConfiguration位,但你需要GlobalHost位(當我的東西不工作時,這是我搞砸的那個位)。

var resolver = new AutofacSignalrDependencyResolver(container); 
'Owin config options. 
var config = new HubConfiguration() 
      { 
       Resolver = resolver, 
       EnableDetailedErrors = true, 
       EnableCrossDomain = true 
      }; 
    GlobalHost.DependencyResolver = resolver; 
    'More owin stuff  
    app.MapHubs(config); 

希望這將有助於解決您的問題。

+0

完美,我使用'SimpleInjector',在我的情況下只需要添加'GlobalHost.DependencyResolver = resolver;'從來沒有注意到任何文檔!歡呼聲matey,現在我欠你 – Rippo

+0

我記得做了很多!研究和挖掘到底。最後,我相信大衛福勒幫我解決了最後的細節問題。 – Vidar

1

你需要跟蹤連接到集線器的客戶端,然後發送新郵件,像這樣

這是一個基類,我寫我的集線器

/// <summary> 
/// base class for Hubs in the system. 
/// </summary> 
public class HubBase : Hub { 
    /// <summary> 
    /// The hub users 
    /// </summary> 
    protected static ConcurrentDictionary<Guid, HubUser> Users = new ConcurrentDictionary<Guid, HubUser>(); 

    /// <summary> 
    /// Called when the connection connects to this hub instance. 
    /// </summary> 
    /// <returns> 
    /// A <see cref="T:System.Threading.Tasks.Task" /> 
    /// </returns> 
    public override System.Threading.Tasks.Task OnConnected() { 
     Guid userName = RetrieveUserId(); 
     string connectionId = Context.ConnectionId; 

     HubUser user = Users.GetOrAdd(userName, _ => new HubUser { 
      UserId = userName, 
      ConnectionIds = new HashSet<string>() 
     }); 
     lock (user.ConnectionIds) { 
      user.ConnectionIds.Add(connectionId); 
     } 
     return base.OnConnected(); 
    } 

    /// <summary> 
    /// Called when a connection disconnects from this hub gracefully or due to a timeout. 
    /// </summary> 
    /// <param name="stopCalled">true, if stop was called on the client closing the connection gracefully; 
    /// false, if the connection has been lost for longer than the 
    /// <see cref="P:Microsoft.AspNet.SignalR.Configuration.IConfigurationManager.DisconnectTimeout" />. 
    /// Timeouts can be caused by clients reconnecting to another SignalR server in scaleout.</param> 
    /// <returns> 
    /// A <see cref="T:System.Threading.Tasks.Task" /> 
    /// </returns> 
    public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled) { 
     try { 
      Guid userName = RetrieveUserId(); 
      string connectionId = Context.ConnectionId; 
      HubUser user; 
      Users.TryGetValue(userName, out user); 
      if (user != null) { 
       lock (user.ConnectionIds) { 
        user.ConnectionIds.RemoveWhere(cid => cid.Equals(connectionId)); 
        if (!user.ConnectionIds.Any()) { 
         HubUser removedUser; 
         Users.TryRemove(userName, out removedUser); 
        } 
       } 
      } 
     } catch { 
      //Bug in SignalR causing Context.User.Identity.Name to sometime be null 
      //when user disconnects, thus remove the connection manually. 
      lock (Users) { 
       HubUser entry = Users.Values.FirstOrDefault(v => v.ConnectionIds.Contains(Context.ConnectionId)); 
       if (entry != null) entry.ConnectionIds.Remove(Context.ConnectionId); 
      } 
     } 
     return base.OnDisconnected(stopCalled); 
    } 

    private Guid RetrieveUserId() { 
     Cookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName]; 
     FormsAuthenticationTicket decryptedCookie = FormsAuthentication.Decrypt(authCookie.Value); 
     var user = JsonConvert.DeserializeObject<User>(decryptedCookie.UserData); 

     return user.Id; 
    } 
} 

然後集線器代碼是

/// <summary> 
/// A hub for sending alerts to users. 
/// </summary> 
public class AlertHub : HubBase, IAlertHub { 
    /// <summary> 
    /// Sends the alert. 
    /// </summary> 
    /// <param name="message">The message.</param> 
    /// <param name="userId">The user identifier.</param> 
    public void SendAlert(string message, Guid userId) { 
     HubUser user; 
     Users.TryGetValue(userId, out user); 
     if (user != null) { 
      IHubContext context = GlobalHost.ConnectionManager.GetHubContext<AlertHub>(); 
      context.Clients.Clients(user.ConnectionIds.ToList()).sendAlert(message); 
     } 
    } 

    /// <summary> 
    /// Send alert to user. 
    /// </summary> 
    /// <param name="returnId">The return identifier.</param> 
    /// <param name="userId">The user identifier.</param> 
    public void ReturnProcessedAlert(Guid returnId, Guid userId) { 
     HubUser user; 
     Users.TryGetValue(userId, out user); 
     if (user != null) { 
      IHubContext context = GlobalHost.ConnectionManager.GetHubContext<AlertHub>(); 
      context.Clients.Clients(user.ConnectionIds.ToList()).returnProcessedAlert(returnId); 
     } 
    } 
} 
+0

即使在我的情況下,這不是我的問題,這段代碼將幫助我在其他地方。謝謝+1 – Rippo