Nhibernate 信号器OnDisconnected事件未将数据持久化到数据库

Nhibernate 信号器OnDisconnected事件未将数据持久化到数据库,nhibernate,fluent-nhibernate,asp.net-mvc-5,signalr,castle-windsor,Nhibernate,Fluent Nhibernate,Asp.net Mvc 5,Signalr,Castle Windsor,我有一个signarhub,我在其中注入服务类,这些服务类通过castlewindsor将数据持久化到本地sqlserver实例 该中心看起来像: [Authorize] public class MyHub : Hub { private readonly IHubService _hubService; private readonly IHubUserService _hubUserService; private readonly IUserService _u

我有一个signarhub,我在其中注入服务类,这些服务类通过castlewindsor将数据持久化到本地sqlserver实例

该中心看起来像:

[Authorize]
public class MyHub : Hub 
{
    private readonly IHubService _hubService;
    private readonly IHubUserService _hubUserService;
    private readonly IUserService _userService;

    public MyHub(IHubService hubService, IHubUserService hubUserService, IUserService userService)
    {
        _hubService = hubService;
        _hubUserService = hubUserService;
        _userService = userService;
    }

    public async Task JoinHub(Guid hubId) 
    {
        var hub = _hubService.GetHubById(hubId);

        if (hub == null)
            throw new NotFoundException(String.Format("Hub ({0}) was not found.", hubId.ToString()));

        var userName = Context.User.Identity.Name;
        var user = _userService.GetUserByUserName(userName);

        if (user == null)
            throw new NotFoundException(String.Format("User ({0}) was not found.", userName));

        var hubUser = new HubUser
        {
            User = user,
            Hub = hub,
            ConnectionId = Context.ConnectionId
        };

        // Persist a new HubUser to the DB
        hubUser = _hubUserService.InsertHubUser(hubUser);

        await Groups.Add(Context.ConnectionId, hub.Id.ToString());
        Clients.Group(hub.Id.ToString()).addChatMessage(userName + " has joined.");
    }

    public async Task LeaveHub()
    {
        var userName = Context.User.Identity.Name;

        var hubUser = _hubUserService.GetHubUserByUserName(userName);

        // Removes HubUser from the DB
        _hubUserService.RemoveHubUser(hubUser);

        await Groups.Remove(Context.ConnectionId, hubUser.Hub.Id.ToString());
        Clients.Group(hubUser.Hub.Id.ToString()).addChatMessage(userName + " has left.");
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        var userName = Context.User.Identity.Name;

        var hubUser = _hubUserService.GetHubUserByUserName(userName);

        // Removes HubUser from the DB
        _hubUserService.RemoveHubUser(hubUser); // This line executes but does not persist anything to DB

        Groups.Remove(Context.ConnectionId, hubUser.Hub.Id.ToString());
        Clients.Group(hubUser.Hub.Id.ToString()).addChatMessage(userName + " has left.");
        return base.OnDisconnected(stopCalled);
    }
}
从客户端调用JoinHub和LeaveHub方法时,一切正常。但是,当OnDisconnected方法激发时,不会从数据库中删除任何内容。我可以看到代码确实执行了,但记录仍保留在数据库中,不会被删除

我想知道我的nhibernate会话是否由于castle windsor的依赖生存期或其他原因而没有将事务提交到数据库,然而,奇怪的是,LeaveHub按预期执行,但OnDisconnected方法中没有相同的代码

根据博客文章,我的依赖项注册为以下配置

Kernel.Register(
    //Nhibernate session factory
    Component.For<ISessionFactory>().UsingFactoryMethod(CreateNhSessionFactory).LifeStyle.Singleton,

    //Nhibernate session
    Component.For<ISession>().UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>().OpenSession()).LifeStyle.HybridPerWebRequestTransient()
);
Kernel.Register(
//Nhibernate会话工厂
Component.For().UsingFactoryMethod(CreateNhSessionFactory).lifety.Singleton,
//Nhibernate会议
Component.For()
);
我还注册了一个拦截器来实现工作单元模式:

// Unitofwork interceptor
Component.For<NhUnitOfWorkInterceptor>().LifeStyle.HybridPerWebRequestTransient()
//Unitofwork拦截器
Component.For()

如果有人能给出方法LeaveHub正确工作的原因以及它无法在OnDisconnected方法中持久化任何内容的原因,我们将不胜感激。

仅供参考,Nhibernate会话使用async做得不太好,因为它们根本不是线程安全的。试着同步运行,看看你得到了什么

Nhibernate是否设置为事务提交时刷新?我不能评论,因为我是一个新手,但我在不久前遇到了这个问题。我没有使用FluentNhibernate,但我确信有一个配置选项可以在事务提交时设置flush。这是假设您正在事务中包装所有打开的会话调用。我用这样的东西来治疗。去拿Nhibernate档案器吧,这是天赐之物

 public class SessionManager : ISessionManager
{
    private readonly ISessionFactory _sessionFactory;
    private ISession _currentSession;
    private ITransaction _currentTransaction;

    public SessionManager(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }

    public ISession OpenSession()
    {
        if (CurrentSessionContext.HasBind(_sessionFactory))
        {
            _currentSession = _sessionFactory.GetCurrentSession();
        }
        else
        {
            _currentSession = _sessionFactory.OpenSession();
            CurrentSessionContext.Bind(_currentSession);
        }
        CurrentSessionContext.Bind(_currentSession);
        _currentTransaction = _currentSession.BeginTransaction();
        return _currentSession;
    }

    public void Dispose()
    {
        try
        {
            if (_currentTransaction != null && _currentTransaction.IsActive)
                _currentTransaction.Commit();
        }
        catch (Exception)
        {
            if (_currentTransaction != null) _currentTransaction.Rollback();
            throw;
        }
        finally
        {
            if (_currentSession != null)
            {
                if (_currentTransaction != null) _currentTransaction.Dispose();
                _currentSession.Close();
            }
        }
    }
}
这是我的配置,我正在几个应用程序上使用它。从另一方面来说,我没有理由不使用FluentNhibernate,内置代码的映射非常棒而且灵活。让我知道我可以给你发送一些示例映射

  public class SessionFactoryBuilder
{
    public static ISessionFactory BuildSessionFactory(string connectionString)
    {
        var cfg = new Configuration();
        cfg.DataBaseIntegration(db =>
        {
            db.Dialect<MsSql2012Dialect>();
            db.Driver<Sql2008ClientDriver>();
            db.ConnectionString = connectionString;
            db.BatchSize = 1500;
            db.LogSqlInConsole = false;
            db.PrepareCommands = true;
            db.ConnectionReleaseMode = ConnectionReleaseMode.AfterTransaction;
            db.IsolationLevel = IsolationLevel.ReadCommitted;
        })
            .SetProperty(Environment.CurrentSessionContextClass, "web")
            .SetProperty(Environment.UseSecondLevelCache, "true")
            .SetProperty(Environment.ShowSql, "true")
            .SetProperty(Environment.PrepareSql, "true")
            .Cache(c =>
            {
                c.UseQueryCache = true;
                c.Provider<RtMemoryCacheProvider>();
                c.DefaultExpiration = 1440;
            }).SessionFactory().GenerateStatistics();

        HbmMapping mapping = GetMappings();
        cfg.AddDeserializedMapping(mapping, "AppName");
        SchemaMetadataUpdater.QuoteTableAndColumns(cfg);
        return cfg.BuildSessionFactory();
    }

    private static HbmMapping GetMappings()
    {
        var mapper = new ModelMapper();

        mapper.AddMappings(typeof (UserMap).Assembly.GetTypes());
        HbmMapping mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
        return mapping;
    }
}

我只是猜测,因为我没有足够的上下文,但是由于您使用的是task,您是否确定OnDisconnected在UnitOfWork发布之前完成。我不相信OnDisconnected在UnitOfWork发布之前完成。拦截器在存储库级别截取所有方法,因此UnitOfWork在OnDisconnected中在我的服务调用
\u hubUserService.RemoveHubUser(hubUser)中启动和完成我相信在您的拦截器实现中,您有一些类似于提交当前trunsaction的东西?你能把breakepoint放在那里吗?也许看看Sql事件探查器中发生了什么?我可以看到事务在我期望的时候提交。我将尝试使用NHibernate探查器进行更深入的挖掘。在日志中,NHibernate在OnDisconnected方法期间不执行任何查询。我相信这可能与我如何管理会话有关。我将尝试这种方法来管理会话,也许它会解决问题。因此,在我的存储库类中,我应该注入ISessionManager,并在构造函数中调用_sessionManager.OpenSession()?实现您的方法非常有效,但在OnDisconnected方法期间仍然存在相同的问题。我在这一行得到一个空对象错误:
if(CurrentSessionContext.HasBind(\u sessionFactory))
。调试显示my_sessionFactory不是空的,因此我仍然不确定问题所在。请将您的上下文设置为web环境。在您的nhibernate配置中设置为CurrentSessionContextClass,“web”。您现在要让我使用信号器创建一些内容,对吗。LOLI对生活方式有点好奇。HybridPerWebRequestTransient()为什么生活方式PerWebRequest不起作用?
  public class SignalRDependencyResolver : Microsoft.AspNet.SignalR.DefaultDependencyResolver
{
    private readonly IWindsorContainer _container;

    public SignalRDependencyResolver(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        _container = container;
    }

    public override object GetService(Type serviceType)
    {
        return TryGet(serviceType) ?? base.GetService(serviceType);
    }

    public override IEnumerable<object> GetServices(Type serviceType)
    {
        return TryGetAll(serviceType).Concat(base.GetServices(serviceType));
    }

    [DebuggerStepThrough]
    private object TryGet(Type serviceType)
    {
        try
        {
            return _container.Resolve(serviceType);
        }
        catch (Exception)
        {
            return null;
        }
    }

    private IEnumerable<object> TryGetAll(Type serviceType)
    {
        try
        {
            Array array = _container.ResolveAll(serviceType);
            return array.Cast<object>().ToList();
        }
        catch (Exception)
        {
            return null;
        }
    }
}
 // SignalR
        _container.Register(Classes.FromThisAssembly().BasedOn(typeof(IHub)).LifestyleTransient());
        SignalRDependencyResolver signalRDependencyResolver = new SignalRDependencyResolver(_container);
        Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver = signalRDependencyResolver;