FluentNHibernate and Not Recognizing the Session - nhibernate

For some reason the Nhibernate is chocking out when I try to access the session. It is throwing the following exception:
No CurrentSessionContext configured (set the property current_session_context_class)!
Please note I am not using XML to setup the configuration!
I am opening the session in my test:
[SetUp]
public void Initialize()
{
_session = GetSessionFactory().OpenSession();
_transaction = _session.BeginTransaction();
SetupContext();
When();
}
and then I am using Repository to access the current session. The repository is in different dll.
public void Save(Category newCategory)
{
var session = SessionFactory.GetSession();
session.SaveOrUpdate(newCategory);
}
public static ISession GetSession()
{
var session = _sessionFactory.GetCurrentSession();
if (session == null)
return _sessionFactory.OpenSession();
return session;
}
UPDATE:
In my BaseTest.cs class I also have a teardown:
[TearDown]
public void CleanUp()
{
_session.Dispose();
_transaction.Dispose();
}
During debugging it seems like the CleanUp is being fired and killing the _session object!
Another update: I have added the following code when building the configuration:
public static ISessionFactory CreateSessionFactory()
{
_sessionFactory =
Fluently.Configure().Database(
MsSqlConfiguration.MsSql2000.ConnectionString(
c => c.FromConnectionStringWithKey("ConnectionString")))
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<Category>())
**.ExposeConfiguration(x =>
{
x.SetProperty("current_session_context_class",
"thread_static");
})**
.BuildSessionFactory();
return _sessionFactory;
}
Now I get the following error:
No session bound to the current context

You need to bind the session to the current context.
In the setup method:
var session = SessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
And in the teardown method:
var session = CurrentSessionContext.Unbind(SessionFactory);
session.Dispose();

Related

SignalR OnDisconnected event not persisting data to DB

I have a SignalR hub in which I'm injecting service classes which persist data to a local SQL Server instance via Castle Windsor.
The hub looks like:
[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);
}
}
When calling JoinHub and LeaveHub methods from the client, everything works fine. However, when the OnDisconnected method fires, nothing is deleted from the database. I can see that the code does indeed execute, but the record remains in the DB and does not get deleted.
I'm wondering if perhaps my nhibernate session is not committing the transaction to the database due to castle windsor's dependency lifetimes or something, however, it's odd that LeaveHub executes as expected but the same code does not in the OnDisconnected method.
My dependencies are registered with the following configuration as per this blog post.
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()
);
and I also register an interceptor to implement a unit of work pattern:
// Unitofwork interceptor
Component.For<NhUnitOfWorkInterceptor>().LifeStyle.HybridPerWebRequestTransient()
If anyone can give any input on why the method LeaveHub works correctly and why it fails to persist anything in the OnDisconnected method, that'd be greatly appreciated.
Just an FYI Nhibernate Sessions don't do so well using async as they are not threadsafe at all. Try running things synchronously and see what you get.
Is Nhibernate set to flush on transaction commit? I can't comment becasue I am a newbie but I ran into this issue some time ago. I am not using FluentNhibernate but I am sure there is a config option to set flush on transaction commit. This is assuming you are wrapping all open session calls in a transaction. I use something like this for sessions. Also go get Nhibernate Profiler it is a godsend.
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();
}
}
}
}
Here is my configuration, I am using it on several apps. On a side not there is a reason I don't use FluentNhibernate, The mapping by code built in is awesome and flexible. Let me know I can send you some sample mappings.
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;
}
}
Here is a neat little bit for managing SignalR dependencies with Castle. You may want to give this a try just for giggles.
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;
}
}
}
Put this in global asax before you set your controller factory
// SignalR
_container.Register(Classes.FromThisAssembly().BasedOn(typeof(IHub)).LifestyleTransient());
SignalRDependencyResolver signalRDependencyResolver = new SignalRDependencyResolver(_container);
Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver = signalRDependencyResolver;

ASP.NET Web API - How can I keep a session alive until after custom MediaTypeFormatter is complete?

I have an ASP.Net Web API project. I am using NHibernate in this project; Fluent NHibernate to be specific. I am handling NHib session management using a custom ActionFilterAttribute. It looks like this:
public class SessionManagement : ActionFilterAttribute
{
public SessionManagement()
{
SessionFactory = WebApiApplication.SessionFactory;
}
private ISessionFactory SessionFactory { get; set; }
public override void OnActionExecuting(HttpActionContext actionContext)
{
var session = SessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
session.BeginTransaction();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var session = SessionFactory.GetCurrentSession();
var transaction = session.Transaction;
if (transaction != null && transaction.IsActive)
{
transaction.Commit();
}
session = CurrentSessionContext.Unbind(SessionFactory);
session.Close();
}
This was working well for my needs. However, I have recently added a custom JSON.NET MediaTypeFormatter to format the my action's resulting JSON. The problem I am having is that my ActionFilter OnActionExecuted() method is called before the MediaTypeFormatter's WriteToStreamAsync can do it's job. The result is that lazily loaded (the problem) collections are now not available because the session is closed. What is the best way to handle this? Should I remove the ActionFilter's OnActionExecuted method and just close my session in the MediaTypeFormatter?
Thanks!!
The MediaTypeFormatter is the wrong layer to close the session at because this behavior really has nothing to do with the particular formatter you're using. Here's what I recommend doing:
Derive from HttpContent and create a class that derives from ObjectContent. Override the SerializeToStreamAsync implementation to await the base implementation's SerializeToStreamAsync then close the session:
public class SessionClosingObjectContent : ObjectContent
{
private Session _session;
public SessionClosingObjectContent(Type type, object value, MediaTypeFormatter formatter, Session session)
: base(type, value, formatter)
{
_session = session;
}
protected async override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
await base.SerializeToStreamAsync(stream, context);
// Close the session and anything else you need to do
_session.Close();
}
}
Now in your action filter, instead of closing the session, you want to replace the response Content with your new class that closes the session:
public class SessionManagement : ActionFilterAttribute
{
public SessionManagement()
{
SessionFactory = WebApiApplication.SessionFactory;
}
private ISessionFactory SessionFactory { get; set; }
public override void OnActionExecuting(HttpActionContext actionContext)
{
var session = SessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
session.BeginTransaction();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var session = SessionFactory.GetCurrentSession();
var response = actionExecutedContext.Response;
if (response.Content != null)
{
ObjectContent objectContent = response.Content as ObjectContent;
if (objectContent != null)
{
response.Content = new SessionClosingObjectContent(objectContent.ObjectType, objectContent.Value, objectContent.Formatter, session);
foreach (KeyValuePair<string, IEnumerable<string>> header in objectContent.Headers)
{
response.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
}
}
}
You could also choose instead to return an HttpResponseMessage with your new Content directly from your controller code wherever you need it.

Nancy - Unable to resolve type: NHibernate.ISession

My CustomBootstrapper looks like below
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override NancyInternalConfiguration InternalConfiguration
{
get
{
//This will tell Nancy it won't have to look in the Nhibernate assemblies for implementations of our interfaces.
return NancyInternalConfiguration
.Default
.WithIgnoredAssembly(asm => asm.FullName.StartsWith("NHibernate", StringComparison.InvariantCulture))
.WithIgnoredAssembly(asm => asm.FullName.StartsWith("Fluent", StringComparison.InvariantCulture))
.WithIgnoredAssembly(asm => asm.FullName.StartsWith("Iesi", StringComparison.InvariantCulture));
}
}
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
base.ConfigureRequestContainer(container, context);
//container.Register((c, p) => SessionFactory.OpenSession());
container.Register(SessionFactory.OpenSession());
}
}
I have a repository which accepts ISession as a constructor dependency. When I run my application I get an error saying Unable to resolve type: NHibernate.ISession
I can confirm that
My bootstrapper is picked up by Nanacy
The ISession registration code is executed
I have tried commenting out .WithIgnoredAssembly(asm => asm.FullName.StartsWith("NHibernate", StringComparison.InvariantCulture)) from property InternalConfiguration
I get the error with both of the ways of registering component (one is commented in my code)
I have looked at similar other questions on SO and none has helped so far.
I've done a sample project that uses NH with Nancy. In the bootstrapper I set up:
a BeforeRequest hook that creates the session and binds it to the session context
a AfterRequest hook that commits the session
an OnError hook that rolls back
The code is as follows:
public class Bootstrapper : WindsorNancyBootstrapper
{
// other stuff
protected override void ApplicationStartup(IWindsorContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
// other setup
ConfigureNHibernateSessionPerRequest(container, pipelines);
}
private void ConfigureNHibernateSessionPerRequest(IWindsorContainer container, IPipelines pipelines)
{
pipelines.BeforeRequest += ctx => CreateSession(container);
pipelines.AfterRequest += ctx => CommitSession(container);
pipelines.OnError += (ctx, ex) => RollbackSession(container);
}
private Response RollbackSession(IWindsorContainer container)
{
var sessionFactory = container.Resolve<ISessionFactory>();
if (CurrentSessionContext.HasBind(sessionFactory))
{
var requestSession = sessionFactory.GetCurrentSession();
requestSession.Transaction.Rollback();
CurrentSessionContext.Unbind(sessionFactory);
requestSession.Dispose();
}
return null;
}
private Response CreateSession(IWindsorContainer container)
{
var sessionFactory = container.Resolve<ISessionFactory>();
var requestSession = sessionFactory.OpenSession();
CurrentSessionContext.Bind(requestSession);
requestSession.BeginTransaction();
return null;
}
private AfterPipeline CommitSession(IWindsorContainer container)
{
var sessionFactory = container.Resolve<ISessionFactory>();
if (CurrentSessionContext.HasBind(sessionFactory))
{
var requestSession = sessionFactory.GetCurrentSession();
requestSession.Transaction.Commit();
CurrentSessionContext.Unbind(sessionFactory);
requestSession.Dispose();
}
return null;
}
}

Fluent nhibernate throws TypeInitializationException when trying to get ISession

I have this code that uses NHibernate
public bool ValidateUser(string username, string password)
{
bool loginResult;
using (var session = SessionFactory.Session)
{
session.BeginTransaction();
var makeQuery = session.Query<User>().SingleOrDefault(x => x.Username == username && x.Password == password);
loginResult = makeQuery != null;
}
return loginResult;
}
My SessionFactory looks like this
using NHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using WebSite.DatabaseModels;
using System;
namespace GameServer.Repository
{
public class SessionFactory
{
private static string connString = System.Configuration.ConfigurationManager.ConnectionStrings["MySQLConnectionString"].ConnectionString;
private static ISessionFactory session;
private static object syncRoot = new Object();
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MySQLConfiguration
.Standard
.ConnectionString(connString))
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<UserMap>())
.ExposeConfiguration(UpdateSchema)
.BuildSessionFactory();
}
private static void UpdateSchema(Configuration cfg)
{
new SchemaUpdate(cfg);
}
public static ISession Session
{
get
{
if (session == null)
{
lock (syncRoot)
{
if (session == null)
session = CreateSessionFactory();
}
}
return session.OpenSession();
}
}
^
I tried putting a break point at the Session property, but that aint hit, but the exception is thrown at using (var session = SessionFactory.Session) and cant really see how I can fix it in error report
It would be better if you pasted the actual exception string (entire exception with stack trace) instead of an image.
As you can see in your stack trace, the exception happens in cctor of your SessionFactory class. cctor is a static constructor. Since you don't have one explicitly, your code probably breaks on initializing static fields of SessionFactory class.
My best bet would be that you don't have a connection string named MySQLConnectionString in your config file. In that case:
// this is null
ConfigurationManager.ConnectionStrings["MySQLConnectionString"];
// this will throw NullReferenceException
ConfigurationManager.ConnectionStrings["MySQLConnectionString"].ConnectionString;

How to make this thread-safe

I have the following SessionFactory for Fluent NHibernate.
I am getting an error of
An invalid or incomplete configuration was used while creating a SessionFactory.
with an InnerException of
An item with the same key has already been added.
This problem is only happening occasionally and my application works fine most of the time.
Based on NHibernate: System.Argument Exception : An item with the same key has already been added I'm guessing my class is not thread-safe which would explain the intermittent nature of this error.
using System;
using NHibernate;
using NHibernate.Cache;
using NHibernate.Cfg;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using WSS.Data.Domain;
namespace WSS.Data {
public static class SessionFactory {
private static ISessionFactory _factory = null;
private static ISessionFactory GetFactory() {
if (_factory == null) {
NHibernate.Cfg.Configuration config;
config = new NHibernate.Cfg.Configuration();
config.Configure();
if (config == null) {
throw new InvalidOperationException("NHibernate configuration is null.");
}
config.AddAssembly("WSS.Data");
_factory = config.BuildSessionFactory();
if (_factory == null) {
throw new InvalidOperationException("Call to Configuration.BuildSessionFactory() returned null.");
}
}
return _factory;
}
private static ISessionFactory GetFluentFactory() {
if(_factory == null) {
_factory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2000
.ConnectionString(c => c
.Is(ConnectionStrings.Auto))
.Cache(c => c
.UseQueryCache()
.ProviderClass())
.ShowSql())
.Mappings(m => m
.FluentMappings.AddFromAssemblyOf())
.BuildSessionFactory();
}
return _factory;
}
public static ISession OpenSession() {
ISession session;
session = GetFluentFactory().OpenSession();
if (session == null) {
throw new InvalidOperationException("Call to factory.OpenSession() returned null.");
}
return session;
}
}
}
The usual approach is to create a mutex (probably in your public method) that only allows single access. See http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx
Not tested as compiling, but something like:
private static Mutex _sessionMutex = new Mutex();
public static ISession OpenSession() {
ISession session;
_sessionMutex.WaitOne();
session = GetFluentFactory().OpenSession();
if (session == null) {
throw new InvalidOperationException("Call to factory.OpenSession() returned null.");
}
_sessionMutex.ReleaseMutex();
return session;
}