NHibernate: Is making session singleton a bad practice? - c#

In my application I have the session as a singleton object in a SessionManager class. Whenever, I need to use it a some part of the application, I do:
using (var session = SessionManager.OpenSession())
{
}
Is this possibly a bad practice ? If so, any ideas about how I can improve ?
EDIT: Here is the implementation of session manager
public static class SessionManager
{
private static readonly ISessionFactory sessionFactory;
static SessionManager()
{
sessionFactory = Fluently.Configure().....
}
public static ISessionFactory SessionFactory
{
get { return sessionFactory; }
}
public static ISession OpenSession()
{
return sessionFactory.OpenSession();
}
}

Please note that the ISession is not thread-safe! Therefore, you should have just one ISessionFactory, but one ISession per thread.

No, it should be singleton so that it can be shared among different threads withing the application. As these objects are heavy weight because they contains the connection information, hibernate configuration information and mapping files,location path. So creating number of instances will make our application heavy weight. But the session objects are not thread safe.
Only applications that require multiple factories with different configurations have an obvious reason to create and close multiple SessionManager instances.
Single threading it will improve the performance of your application.

Related

How to find out where my legacy application using NHibernate is leaking memory

I have a legacy application that I'm maintaining that is leaking memory.
I am reasonably confident that the source is the session management/dependency injection code. It uses Simple Injector and NHibernate.
To start, here are some helper classes and interfaces we use:
public class SessionFactory : Dictionary<string, Func<ISession>>,Helpers.ISessionFactory, IDisposable
{
public ISession CreateNew(string name)
{
return this[name]();
}
public void Dispose()
{
foreach (var key in Keys)
{
this[key]().Close();
this[key]().SessionFactory.Close();
}
}
}
public interface ISessionFactory
{
ISession CreateNew(string name);
}
Here is what the container initialization looks like:
private static void InitializeContainer(Container container)
{
var connectionStrings = System.Configuration.
ConfigurationManager.ConnectionStrings;
var sf1 = new Configuration().Configure().SetProperty(
"connection.connection_string",
connectionStrings["db1"].ConnectionString
).BuildSessionFactory();
var sf2 = new Configuration().Configure().SetProperty(
"connection.connection_string",
connectionStrings["db2"].ConnectionString
).BuildSessionFactory();
var sf3 = new Configuration().Configure().SetProperty(
"connection.connection_string",
connectionStrings["db3"].ConnectionString
).BuildSessionFactory();
container.Register<ISessionFactory>(() =>
new SessionFactory
{
{"db1", sf1.OpenSession},
{"db2", sf2.OpenSession},
{"db3", sf3.OpenSession}
}, Lifestyle.Scoped);
}
Then, inside our base controller (other controllers inherit from it), this happens:
protected BaseController(ISessionFactory factory)
{
this.factory = factory;
db1Session = factory.CreateNew("db1");
db2Session = factory.CreateNew("db2");
db3Session = factory.CreateNew("db3");
}
From there, all of our methods can use a session from any database. Some request methods use multiple database sessions to complete their tasks. This project does not utilize the repository pattern at this point -- rewriting it would be an expensive operation. Is there any obvious memory leak I'm missing in this code?
I find your design very suspicious. First of all, your factory is leaking connections, since although you try to dispose it, the only thing you achieve is disposing things you just opened during disposal; this isn't very useful and means the already created connections will not be closed. Second, a design where your application requests the proper connection using a string based approach is error prone. Your application is probably dealing with multiple database schemas, where each connection relates to a certain schema. This means that connections aren't interchangeable and this warrants the use of a unique abstraction per schema. So instead of having one generic ISessionFactory abstraction that tries to serve all consumers (and currently fails), make things explicit by giving each unique schema its own abstraction. For instance:
public interface IDb1SessionProvider
{
ISession Session { get; }
}
public interface IDb2SessionProvider
{
ISession Session { get; }
}
public interface IDb3SessionProvider
{
ISession Session { get; }
}
By lack of context, I named the interfaces IDbXSessionProvider, but I bet you can come up with a better name.
This might look weird, since all interface have the same method signature, but remember that they have each a very different contract. The Liskov Substitution Principle describes that they should not share the same interface.
An implementation for such provider can be made as follows:
public class FuncDb1SessionProvider : IDb1SessionProvider
{
Func<ISession> provider;
public FuncDb1SessionProvider(Func<ISession> sessionProvider) {
this.sessionProvier = provider;
}
public ISession Session => provider();
}
And you can register such implementation in Simple Injector as follows:
var factory = new Configuration().Configure().SetProperty(
"connection.connection_string",
connectionStrings["db1"].ConnectionString)
.BuildSessionFactory();
var session1Producer = Lifestyle.Scoped.CreateProducer<ISession>(
factory.OpenSession, container);
container.RegisterSingleton<IDb1SessionProvider>(
new FuncDb1SessionProvider(session1Producer.GetInstance));
What this code does is creating a scoped InstanceProducer for the db1 session. The scoped InstanceProducer will ensure only one instance of that session is created during a certain scope (usually a web request) and it will ensure that the ISession implementation is disposed (if it implements IDisposable). The call to InstanceProducer.GetInstance() is wrapped in the FuncDb1SessionProvider. This session provider will call forward the creation of the session to the wrapped delegate.
With this design you can let your application code depend on the IDb1SessionProvider and that code can use it without the need to dispose it. Every call to IDb1SessionProvider.Session within the same session will ensure you get the same session and Simple Injector guarantees disposal on the end of the request.
It looks like you have invented your own interface called ISessionFactory. Given that you are using NHibernate which also provides an interface under this name, I would argue that it's VERY unfortunate to use the same names in your own code. You should pick a different name for your own interface and class to avoid confusion.
As for the question itself, NHibernate's ISessionFactory.OpenSession() does exactly that. It will open and return a session. There is no basis to assume that it will do something magic with regards to reuse or scoping.
To have NHibernate assist with contextual sessions, you need to configure the proper "context provider" and use, among other things, ISessionFactory.GetCurrentSession(). See Contextual Sessions in the NHibernate reference.
Alternatively, you can manage the sessions using whatever you like, but then you must use that mechanism to retrieve the current session and not expect NHibernate to know about it.

Azure Redis StackExchange.Redis ConnectionMultiplexer in ASP.net MVC

I have read that in order to connect to Azure Redis cache is best to follow this practice:
private static ConnectionMultiplexer Connection { get { return LazyConnection.Value; } }
private static readonly Lazy<ConnectionMultiplexer> LazyConnection =
new Lazy<ConnectionMultiplexer>(
() =>
{
return
ConnectionMultiplexer.Connect(connStinrg);
});
And according to Azure Redis docs:
The connection to the Azure Redis Cache is managed by the ConnectionMultiplexer class. This class is designed to be shared and reused throughout your client application, and does not need to be created on a per operation basis.
So what is best practice for sharing ConnectionMultiplexer across my ASP.net MVC app ?
Should it be called in Global.asax, or should I initialize it once per Controller, or smth. else ?
Also I have service which is tasked to communicate with the app, so if I want to communicate with Redis inside the Service should I send instance of ConnectionMultiplexer to service from Controllers, or should I initialize it in all my services, or ?
As you can see I'm a bit lost here, so please help !
The docs are right in that you should have only one instance of ConnectionMultiplexer and reuse it. Don't create more than one, it is recommended that it will be shared and reused.
Now for the creation part, it shouldn't be in Controller or in Global.asax. Normally you should have your own RedisCacheClient class (maybe implementing some ICache interface) that uses a ConnectionMultiplexer private static instance inside and that's where your creation code should be - exactly as you wrote it in your question. The Lazy part will defer the creation of the ConnectionMultiplexer until the first time it is used.
Dears;
You can reuse StackExchange.Redis ConnectionMultiplexer by using the following code. It can be used in any layer of your code.
public class RedisSharedConnection
{
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(ConfigurationManager.ConnectionStrings["RedisConnectionString"].ConnectionString);
connectionMultiplexer.PreserveAsyncOrder = false;
return connectionMultiplexer;
});
public static ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
}

NHibernate Performance and Scalability

I have a web forms site that use NHibernate to connect to a MSSQL database.
I use the following class to create the SessionFactory and get the current session to use:
internal static class SessionManager
{
static readonly Configuration Configuration = new Configuration().Configure();
internal readonly static ISessionFactory SessionFactory = Configuration.BuildSessionFactory();
internal static ISession CurrentSession { get { if (!CurrentSessionContext.HasBind(SessionFactory))CurrentSessionContext.Bind(SessionFactory.OpenSession()); return SessionFactory.GetCurrentSession(); } }
}
And that is an example of how I use the previous one:
public abstract class Repository<TEntity>
{
protected internal ISession Session { get { return SessionManager.CurrentSession; } }
public IQueryable<TEntity> AllItems { get { return Session.Query<TEntity>(); } }
}
Everything works fine, although I believe I'm doing something really bad in terms of performance and scalability, but I can't see what.
Can anyone point me out what is and/or suggest a better way to handle this?
Thanks in advance!
I think the main issue in your code is that, when you put the Session object as a static field in a static class, you will have only one session for the whole process, what can bring you problems, like "a different object with the same identifier value was already associated with the session", for example.
What you could do is create another static method to allow you to close the session, but you would have to control when to close it (in a web environment, it could be in the end of every Request), or you could use some dependency injection framework like NInject or Castle Windsor to control the lifetime of the Session object.
Take a look at this:
(Yet another) nHibernate sessionmanager for ASP.NET (MVC)
Effective NHibernate Session management for web apps

NHibernate: Configure() in every page request?

I have been reading many books on NHibernate and have noticed how the Configure() is implemented. In the books that method is called every time the application is run in a console application. Most of the ASP.NET examples online call Configure() on every page request. I think this will have alot of overhead since NHibernate must be configured on every request. Does it matter if NHibernate is configured on every page request? If not, how would someone save the configuration - application wide in asp.net mvc?
NHibernate is designed to be configured once per application start. In the case of a console program, that's every time you run the program. In the case of an ASP.NET application, that's every time the application starts, firing the Application.Start event.
The SessionFactory NHibernate creates from Configure() is safe to be cached for the lifetime of the application and is thread-safe to create sessions repeatedly. There is no need to configure on every request.
In the most basic way, you can use a lazy-initialized static property to safely give you a singleton for your application to use:
public static class NHibernateSessions
{
private static readonly Lazy<SessionFactory> lazyFactory;
static NHibernateSessions
{
lazyFactory = new Lazy<SessionFactory >(
() => NHibernateSessions.CreateSessionFactory());
}
public static SessionFactory Factory
{
get
{
return NHibernateSessions.lazyFactory.Value;
}
}
public static void Initialize()
{
if(!NHibernateSessions.lazyFactory.IsValueCreated)
{
// Access the value to force initialization.
var factory = lazyFactory.Value;
}
}
private static SessionFactory CreateSessionFactory()
{
// Add code here to configure and create factory.
}
}
This code uses the Lazy<T> type, to ensure the initialization is thread-safe. You can then call NHibernateSessions.Factory to get the singleton factory with which to re-use throughout your application.
By default the factory is initialized on the first get of the Factory property. This means that for an ASP.NET application, the first request to attempt to use NHibernate will be a slow one. If this is a problem, you can force initialization when the application starts by calling the Initialize() method in an Application.Start event-handler.

C# .NET Singleton life of app pool

I want to create a singleton that remains alive for the life of the app pool using HttpContent.Current.Cache.
Where would I create the class and how should it be implemented? I understand how to implement a singleton but am not too familiar with threading and httpcontent.current.cache.
Thanks!
It doesn't matter where to put the singleton code.
As soon as you access the instance and the type is initialized, it will remain in memory for the entire life of your ApplicationDomain. So use it as a normal class and the rest is done on first use.
Perhaps you are over-complicating the issue? i'm not sure why you need to use the cache. Could you not just add a file to the App_Code folder to house your class e.g "mSingleton.cs"
public sealed class mSingleton
{
static readonly mSingleton _instance = new mSingleton();
public int MyVal { get; set; }
public static mSingleton Instance
{
get { return _instance; }
}
private mSingleton()
{
// Initialize members, etc. here.
}
}
Then it is global to all your code and pages, maintains state until the app pool recycles or there is a app rebuild (i don't know if this causes the app to recycle as well - if it does then it suits your criteria anyway), doesn't need to be added to any cache, application or session variables.. no messy handling
You can do this on page_load in any aspx.cs file and refresh it to see the count go up each time to prove state is maintained:
mSingleton getMyObj = mSingleton.Instance;
getMyObj.MyVal++;
I'd not use the cache for this. I'd recommend a static class or singleton with static getInstance().

Categories

Resources