Do you need a framework?
I had a discussion about a session life style management, and the guy I was talking with mentioned a framework that would handle that for me. It made me think for a while, because my first instinct was to ask, what for?
Here is how I usually handle session life style management in web applications nowadays:
public class Global: System.Web.HttpApplication { public static ISessionFactory SessionFactory = CreateSessionFactory(); protected static ISessionFactory CreateSessionFactory() { return new Configuration() .Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "hibernate.cfg.xml")) .BuildSessionFactory(); } public static ISession CurrentSession { get{ return (ISession)HttpContext.Current.Items["current.session"]; } set { HttpContext.Current.Items["current.session"] = value; } } protected void Global() { BeginRequest += delegate { CurrentSession = SessionFactory.OpenSession(); }; EndRequest += delegate { if(CurrentSession != null) CurrentSession.Dispose(); }; } }
And yes, I copy / paste it or recreate it from scratch whenever I need to handle this in a new application. To be frank, it is simpler to do so than to try to package a it in a resuable form that would make sense to use.
Now, if you wanted support for things like multiple session life styles, then you are starting to talk about enough complexity to justify using a framework. But for the most part, code such as the one above is all that you would require to get things done, because it most applications, you only require a single lifestyle.
The same is true for the other cases as well, not just session life style management. There is a reason that I don’t particularly like commons and util libraries. In order to make such things useful as libraries, you have to satisfy a wide variety of scenarios, which complicate your life. I find that single purpose, single use, “snippets” (for lack of a better word) work better for me for the simple infrastructure concerns.
Comments
Just make sure people clue into the "single use" aspect.
I've seen people say, "Wow, that's just two lines of code, why not just paste it wherever you need it."
"Because then if it changes, that's a lot of search and replace."
If it's used once, I agree, why not just cut and paste. But if it is simple, has a single purpose, but is used often, that is where putting it in a "common" spot or as a "util" makes sense so if the behavior does change, it can change in one place.
People have differing views of what goes in a "util" library. I think in many cases the instant you reference a business class or a domain entity, you are not longer in the realm of util.
I use something similar using SessionScopes
I never got the pattern of a session per request demonstrated above. To me the session is a logical unit of work and a single request can have many of those.
For example in one request i'm creating a new user, putting order for it and sending the shipping information and I would use a session for each of them.
Hi,
You said that it is simpler to copy paste than packaging it in a reusable form. I think that encapsulating it in an HttpModule would take you less than 5 min to have it packaged and would prevent you from copy/paste it or doing it from scratch in every new project. Don't you think so ?
I agree with Nicolas. HttpModule's basically are reusable Global.asax.cs files and they do not interfere with application specific logic that might be in the Global.asax.cs.
Where/how are you calling the Flush()/Commit()/etc methods?
Nicolas,
Yes, it would.
Now I would need to manage configuration for it, I would need to carry on the DLL that contains it.
It is more of a mess than helping, just from dependency management perspective.
DaRage,
You tend not to do things like that, just because the user doesn't do things like that.
But note that a session doesn't equate to a transaction.
Igor,
Transactions are handled in a separate manner. Usually as part of the controller level, which orchestrate operations
I typically let my IOC container take care of creating sessions for me. I use StructureMap to cache the session factory as a singleton and then I have a session injected into the controller.
That's heresy! :)
But you can have simple libs, you know.
Bunter,
No, I can't. Not and manage them.
The cost of managing the dependencies is just too high
Is SessionFactory.OpenSession() very lightweight because you call it on every request even if you have pages that don't need it.
I would have thought the lazy construction in CurrentSession get would have been a little safer.
[)amien
Damien,
OpenSession is very light, yes. It just create a new session, and the session create a few objects. It is all in memory, and no DB is involved at all.
Oren,
How do you usually refer to your session in services, controllers, etc? Do you inject the current session using Windsor's factory method capability?
I'm guessing that you're NOT actually referencing "Global.CurrentSession" everywhere...
Nick,
The container injects that.
Setup is something like:
Container.Register(Component.For <isession()
.FactoryMethod(() => Global.CurrentSession)
.LifeStyle.Is(LifestyleType.Transient));
Oren, any reason why you are not using SessionFactory.GetCurrentSession() with current_session_context_class="web" instead of manually setting the HttpContext.Current.Item[""]?
Dmitry,
Because it would take me more time to write it up that way than this way, and because I have been doing it this way since before GetCurrentSession().
Oren, what about session management in WindowsForms or WPF application? For example, the main form with grid and the dialog window to edit the current object with collections.
If it is a one session conversation, then how to load previous objects states, if the user was modify the data and press Cancel button?
If it is a two session process then how to update main form persistent object, if the user was modify the data and pess Ok button?
P.S. Thank you for your open source mission.
@Ayende
I +1 this post and its underlying premise. I abandoned a few 'common' libraries on my current project just because there was too much friction given the speed of development.
I also bring in the unit tests for these snippets, if present since they take on a life of their own. You agree with doing this?
And not only that Oren.
For who what work with session-per-request + test and GetCurrentSessionContext the framework is NHibernate itself...
But believe me that it is really hard to explain.
I also +1 this approach too. I actually got a bit further and have a code snippet on GitHub:
http://gist.github.com/108433
I swipe this and modify on a per-project basis. I'd rather do that than worry about crafting and maintaining one complex DLL that works for all projects.
@Fabio
Yeah, I use the CurrentSessionContext along with an enum, it's quick and simple:
UoW.Configure( conStr, UoW.Environment.Test );
http://gist.github.com/108433
Den,
I have a full article about it, which will be publish soon
@Fabio - I've been asking just about this feature (contextual session through GetCurrentSession() ) on NHusers group few days ago but couldn't make it work in my setup. So I'm basically doing it manually, like Ayende.
Why doesn't NHibernate ship this in an assembly? I know when getting started with NHibernate just figuring out how to glue it into your application is little tricky.
If its so common you can copy and paste with impunity into every project, I dont see why NHibernate doesn't just give it to us as part of its distribution.
Nathan,
Because this is a single use scenario, it is not generally applicable.
And NH does have builtin support for that.
@Rafal,
You were probably missing CurrentSessionContext.Bind(Session); CurrentSessionContext.Unbind(SessionFactory); statements. You need the first statement after the session is opened and the second statement after the session is closed.
I like to use contextual session because I have a class managing NHibernate sessions in the data access assembly. This approach makes testing easier.
However, the new .NET System.Web.Abstractions assembly does let you mock HttpContext; but you would have to use HttpContextBase instead of HttpContext.
Great post great way of tackling unnecessary complexity that doesn't even need to be there!
As always Ayende's specific recipe is wrong (don't copy/paste) but the thinking is useful.
I posted complete example here:
zvolkov.com/.../...ASPNET-MVC-with-NHibernate.aspx
You will still have to reference NHibernate. And depending on the database, DB libs as well. Having one additional lib with simple framework code for is is just adding ... another reference.
Bunter,
Take a note that there is a big difference between a few cohesive frameworks and a lot of minor, unrelated, details.
zvolkov,
Even though your solution also was interesting it did include a nessecity to use both CastleWindsor and MVCContrib, so I think your way of doing things are a bit more involved and complicated (arguably).
However, one point was raised in the comments that at least I think is important. How does one achieve having this behavior, but only actually opening a session when needed? Not in every request? Even though the opening of a session is VERY lightweight, it would be nice to avoid it.
Any ideas anyone?
Comment preview