インターネット上のドキュメントには多くの欠落があります。Autofacのドキュメントが完全ではないため、SignalR2.0とAutofacを一緒に使用することについて書きました。
私はこれについてブログに書いたが、私はそのウェブサイトを下に書いた。これがそのブログ記事のHTMLである:
MVCアプリケーションでAutofacを介してDIを多用し、Signalr 2.0で問題が発生していませんか?
Autofacsのドキュメントに従い、Autofac.SignalR Nugetパッケージをインストールしましたか:
https ://code.google.com/p/autofac/wiki/SignalRIntegration
Autofacのドキュメントには複数の問題があり、Autofac.SingalrNugetパッケージはSignalR1.0用です。
まず、SignalR2.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);
}
}
まず、上記のコードで、パブリックオーバーライドタスクOnDisconnectedは信頼できず、起動せず、SignalRからの切断を管理する信頼できる方法ではないことに注意してください。このメソッドは、一部の切断をキャッチする可能性があります。幸いなことに、1日以上前の接続は無視できます。
次の注意点は、上記のコードで、内部静的voidSendNotificationsです。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;
}
}
そして、インターネットに欠けている大きな部分の1つは、IoCが注入されたConversationHubを実際に使用して通知を送信する方法です。
public Lazy _ConversationHub { get; set; }
_ConversationHub.Value.SendNotifications(account.account_id, account.partition_id, userIds, convoEv);
_ConversationHubが初期化されるように、Register.meでハブをAutofacに登録する必要があります。
container.RegisterType<SignalR.ConversationHub>().As<SignalR.IConversationHub>().InstancePerLifetimeScope().PropertiesAutowired();