互联网上的文档中缺少很多内容。我写了一篇关于同时使用 SignalR 2.0 和 Autofac 的文章,因为 Autofac 的文档不完整:
我写了一篇关于这个的博客,但我把那个网站写下来了,这是那篇博客文章的 HTML:
在 MVC 应用程序中通过 Autofac 大量使用 DI 并且在使用 Signalr 2.0 时遇到问题?
您是否遵循 Autofacs 文档并安装了 Autofac.SignalR Nuget 包:
https ://code.google.com/p/autofac/wiki/SignalRIntegration
Autofac 的文档存在多个问题,Autofac.Singalr Nuget 包适用于 SignalR 1.0。
所以首先,让我们使用 SignalR 2.0 进行修复。您只需将 Autofac.SignalR 包朝正确的方向轻推,将以下内容添加到您的 Web.config 中:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNet.SignalR.Core" publicKeyToken="31bf3856ad364e35" culture="" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="2.1.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
现在实际工作的实际代码:
public interface IConversationHub
{
System.Threading.Tasks.Task OnConnected();
void SendNotifications(long _account_id, int _partition_id, List<long> _userIds,
DTO.ConversationEventMessage _message);
}
[Authorize]
public class ConversationHub : Hub, IConversationHub
{
readonly ILifetimeScope _hubLifetimeScope;
private uTextAPP.AppLayer.IManageUsers _ManageUsers { get; set; }
private uTextAPP.AppLayer.IManageUserConnections _ManageUserConnections { get; set; }
private uTextDDD.ServiceLayer.IReportUserConnections _ReportUserConnections { get; set; }
public ConversationHub(ILifetimeScope lifetimeScope)
{
// Create a lifetime scope for the hub.
_hubLifetimeScope = lifetimeScope.BeginLifetimeScope();
// Resolve dependencies from the hub lifetime scope.
_ManageUsers = _hubLifetimeScope.Resolve<uTextAPP.AppLayer.IManageUsers>();
_ManageUserConnections = _hubLifetimeScope.Resolve<uTextAPP.AppLayer.IManageUserConnections>();
_ReportUserConnections = _hubLifetimeScope.Resolve<uTextDDD.ServiceLayer.IReportUserConnections>();
}
public override System.Threading.Tasks.Task OnConnected()
{
//var username = Context.User.Identity.Name; //this is the user_id!! yay!
var user = _ManageUsers.GetCurrentUser();
var _issues = new Issues();
if (user == null || user.account_id == 0)
return base.OnConnected();
var conn = new user_connection
{
connection_id = Context.ConnectionId,
user_id = user.user_id
};
_ManageUserConnections.CreateUserConnection(user.account_id, user.user_id, user.partition_id, conn, _issues);
return base.OnConnected();
}
internal static void SendNotifications(long _account_id, int _partition_id, List<long> _userIds, DTO.ConversationEventMessage _message, IEnumerable<uTextDTO.AppLayer.user_connection> _connections )
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ConversationHub>();
if (_connections == null) return;
foreach (var c in _connections)
{
if (_userIds.Any(_userIds.Contains))
{
if (context.Clients.Client(c.connection_id) != null)
{
context.Clients.Client(c.connection_id).receiveNotification(_message);
}
}
}
}
public void SendNotifications(long _account_id, int _partition_id, List<long> _userIds, DTO.ConversationEventMessage _message)
{
var _issues = new Issues();
SendMessage(_account_id, _partition_id, _userIds, _message, _ReportUserConnections.GetAllUserConnectionsByDaysBack(_account_id, -1L, _partition_id, 1, _issues))
;
}
public override Task OnDisconnected(bool stopCalled)
{
var user = _ManageUsers.GetCurrentUser();
var _issues = new Issues();
if (user == null || user.account_id == 0)
return base.OnConnected();
var original = _ManageUserConnections.GetUserConnectionByConnectionId(user.account_id, user.partition_id,
user.partition_id, Context.ConnectionId, _issues);
if (original != null && original.user_connection_id != 0L)
{
var mod = new user_connection().CopyModelExt(original);
mod.is_active = false;
_ManageUserConnections.UpdateUserConnection(user.account_id, user.user_id, user.partition_id, original.user_connection_id,mod, original, _issues);
}
return base.OnDisconnected(stopCalled);
}
protected override void Dispose(bool disposing)
{
// Dipose the hub lifetime scope when the hub is disposed.
if (disposing && _hubLifetimeScope != null)
_hubLifetimeScope.Dispose();
base.Dispose(disposing);
}
}
首先,请注意上面的代码,公共覆盖 Task OnDisconnected 不可信,它不会触发并且不是管理与 SignalR 断开连接的可靠方法,此方法可能会捕获一些断开连接。幸运的是,对于我的要求,我可以忽略超过一天的连接。
接下来注意,使用上面的代码,内部静态 void SendNotifications。SendNotifications 必须是静态的,以便 SignalR 上下文在访问时不会引发运行时错误。
最后请注意,静态方法是从调用者传递的连接,即 SendNotifications 的公共公开方法。我需要 SendNotifications 中的 IReportUserConnections 实例,但 IReportUserConnections 不是静态的,也不能是静态的,无法由 Autofac 正确注入。所以我不能在静态 void SendNotifications 中使用 IReportsUserConnections,所以我用公共版本的 SendNotifications 解决了这个问题。
对于 Autofac 容器:
public static class SimpleInjectorInitializer
{
public static IContainer Container;
public static void Initialize()
{
var builder = new ContainerBuilder();
// Register the SignalR hubs.
builder.RegisterHubs(typeof(uTextAPP.SignalR.ConversationHub).Assembly);
uTextMVC.RegisterMe.Register(builder);
Container = builder.Build();
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(Container));
var signalRDependencyResolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(Container);
GlobalHost.DependencyResolver = signalRDependencyResolver;
}
}
互联网上缺少的重要部分之一,如何实际使用您的 IoC 注入的 ConversationHub 发送通知:
public Lazy _ConversationHub { get; set; }
_ConversationHub.Value.SendNotifications(account.account_id, account.partition_id, userIds, convoEv);
您必须确保在 Register.me 中使用 Autofac 注册 Hub,以便初始化 _ConversationHub:
container.RegisterType<SignalR.ConversationHub>().As<SignalR.IConversationHub>().InstancePerLifetimeScope().PropertiesAutowired();