Replies: 1 comment
-
I found your post awhile ago when struggling through using ISession in a Blazor Server app. I still haven't found anyone talking about it online, so I'll post my solution here. I had to implement my own session management in a
Blazor injects scoped services, which live for the lifetime of the SPA (until reload). In our experience, injecting an ISession into each page is not feasible, because Blazor is asynchronous. This means that it will often run methods that both utilize the same ISession to call the database in parallel, which will result in a concurrent session error. A solution to this would be to inject the using (var session = sessionFactory.OpenSession())
using (var transaction = session.BeginTransaction()) {
... Since we wrap the session in a NHibernate uses LazyLoading by default, which is great for performance. You can't lazy load an object if the session is already closed. This means that we cannot lazy-load anything in Blazor, because we dispose of the session before the UI renders. To use this method, we must use a lot of A solution to this problem would be to not dispose the session; rather we leave it open so that when Blazor asynchronously updates the UI, the session is still open so that the object in question may be LazyLoaded on demand. var session = sessionFactory.OpenSession();
using (var transaction = session.BeginTransaction()) { There is an obvious issue with this: each time the routine encapsulating a database query is called, it opens a new session which will never be disposed. LazyLoading will work, however. The solution to this issue is to implement our own session management. Track each open session in a @using NHibernate
@implements IDisposable
@code {
public NHibernate.ISessionFactory sessionFactory { get; set; }
public List<NHibernate.ISession> sessions { get; set; }
/// <summary>
/// Get the sessionFactory
/// </summary>
protected override void OnInitialized()
/// <summary>
/// Dispose all sessions with closed transactions after rendering
/// This allows sessions to remain open long enough to lazy-load during rendering
/// </summary>
/// <param name="firstRender"></param>
protected override void OnAfterRender(bool firstRender)
/// <summary>
/// Open a new session and maintain an internal handle to it
/// </summary>
/// <param name="protect">If true, the session will not be automatically discarded.</param>
/// <returns>An open NHibernate ISession</returns>
public NHibernate.ISession GetSession(bool protect = false)
/// <summary>
/// Dispose of all remaining sessions when navigating to another page
/// </summary>
public void Dispose()
} Every page in my Blazor application that needs to do a database transaction inherits from the above component. I can share my implementation of the stub above if anyone is interested. Here is a simple example of how to use it. @inherits NhibernateBase
...
var session = GetSession();
using (var transaction = session.BeginTransaction())
{
MyList = await session.Query<MyClass>().ToListAsync();
await transaction.CommitAsync();
} |
Beta Was this translation helpful? Give feedback.
-
Anyone use NHibernate with Blazor Server? If so, how are you handling ISession and razor component lifetimes?
Beta Was this translation helpful? Give feedback.
All reactions