NHibernate Performance and Scalability - c#

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

Related

Use static global variable class in ASP.NET MVC web application

I am creating an ASP.NET MVC web application. It has service classes to execute business logic and it access data through Entity Framework.
I want to change some business logic based on application variable. These variables are global variables and load from app config and don't change after the initial loading.
public class BroadcastService : IBroadcastService
{
private static readonly ILog Logger = LogProvider.GetCurrentLogger();
private readonly IUnitOfWork _worker;
private readonly IGlobalService _globalService;
public BroadcastService(IUnitOfWork worker, IGlobalService globalService)
{
_worker = worker;
_globalService = globalService;
}
public IEnumerable<ListItemModel> GetBroadcastGroups()
{
if(Global.EnableMultiTenant)
{
//load data for all tenants
}
else
{
//load data for current tenant only
}
return broadcastGroups ?? new List<ListItemModel>();
}
...
}
public static class Global
{
public static bool EnableMultiTenant{get;set;}
}
For example, EnableMultiTenant will hold application is running in multi-tenant mode or not.
My concerns are:
Is it ok to use a static global variable class to holds those values?
This application is hosting on Azure app service with load balancing. Is there any effect when running multi-instance and when app pool restarts?
To answer your question as to whether it is 'okay' to do this, I think that comes down to you.
I think the biggest thing to know is when that data is going to get refreshed. From experience I believe that static information gets stored in the application pool, so if it is restarted then the information will be refreshed.
Lifetime of ASP.NET Static Variable
Consider how many times you need that information, if you only need it once at startup, is it worth having it as a static. If you are getting that information a lot (and say for example it is stored in a database) then it may be sensible to store that in a cache somewhere such as a static member.
I think my only recommendation with static member variables is asp is keep them simple, booleans seem fine to me. Remember that users do share the same application meaning that static variables are global for all users. If you want a user specific variable then you want to use sessions cache.
Always remember the two hardest thing in programming
Naming things
Cache invalidation
Off by one errors
https://martinfowler.com/bliki/TwoHardThings.html
Even though this is a joke, it holds a lot of truth
Hope this helps
This is thread safe if you initialize these values once and then only read from them. It is also safe in the presence of multiple worker processes and restarts because the multiple processes don't share variables.
As an alternative consider creating an instance of a class holding your settings:
class MySettings {
bool IsEnabled;
}
Then you can use dependency injection to inject a singleton value of this class to your code. This makes it easier to tests and makes the code more uniform.

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.

NHibernate: Is making session singleton a bad practice?

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.

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