Cleaning up some transactional logic and wondered how other people were handling it.
Ayende's recommendation seems to be to handle transactions at the service boundary. This is a ASP.NET web app though, so it hasn't got a clear cut service boundary, at least not right now.
What do people do?
Create a single transaction per request in a HttpModule and handle commit on EndRequest, rollback on Error?
Create transactions in the actual "services" in the application and handle it multiple places?
Something else?
You can use a IoC Container for your service layer and the container can manage the transaction and the Nibenrate Session.
Your WebApp Controller => call (A) Service Layer => call (B) one or several DAO methods /operations.
The IoC container like Spring.NET will manage te TX scope, by example at (A) and will provide a Session to your DAO in (B). The commit (or rollback) will be handled at the end of the service layer call.
Most people use a session-per-request strategy as stated in your first bullet point. However, I don't believe that the transaction needs to be committed on EndRequest. In many web pages it would be easier to commit the transaction based on user action (e.g. clicking submit) and let EndRequest just handle disposing the ISession.
As far as I can tell, there's no need to create an HttpModule as the same functionality can be created in global.asax: http://forum.hibernate.org/viewtopic.php?t=993041.
Related
I wonder what is the best way to manage NHibernate Session Context
when using NH data layer from Xsockets controller.
Particularly I refer to self hosted winservice/console application or Azure worker role,
where HTTPContext is not available.
Of course there is always an option to create and dispose session per call, but that means a performance hit, so better reuse sessions in some way.
My controller provides API for CRUD operations in underlying NH repository and is pushing updates to relevant subscribers when certain records are updated in DB.
Your ideas appreciated :)
I'm using StructureMap to handle dependencies and create a NestedContainer to handle session per request. Don't have to mess with CurrentSessionContext or HttpContext anymore for storing session.
http://structuremap.github.io/the-container/nested-containers/
You could even just create a middleware UnitOfWork if you are using OWIN with WebAPI.
Since XSockets has state is will be bad for your database if you open the connection in the OnOpen event since the connection will remain open as long as the socket is open. Best is to use the repository only in the methods calling the CRUD operations as briefly as possible.
To get the instance of your repository should not be a bottleneck in this case.
I will be happy to review any code you might have.
Regards
Uffe
I'm using StructureMap and I've configured ISession with HybridHttpOrLocalThreadStorage life cycle. New session is created and injected into controllers on per request basis.
Now, the question I have is about disposal. I've read number of articles presenting number of different approaches. Some people were doing it in controllers, some in repositories, some in http modules and others did it in Application_EndRequest() handler. Critique ranged from SRP violations to 'the one creating an object should be responsible for its disposal' to name a few.
So the bottom line is that:
common approach was to manually dispose these sessions - why? I have already configured my container to manage particular object's life cycle. Shouldn't it (i.e. IoC) manage it for me?
out of options available for disposal is handling it in Application_EndRequest() "the best" way of going about it?
For example, this article explains in length one available approach but the article itself is over 2.5 years old. Perhaps new version of StructureMap makes most of that implementation obsolete?
If you are using RavenDB .net client you will be using DocumentStore and DocumentSession. Both of these object do a fair amount of work in the background; local caching to mention one thing. Just to keep things clean and efficient, each session should call session.dispose() when the work is done. documentStore.Dispose() should be called when the application ends.
I've been trying several different ways in order to get a simple set of transactions to work for a simple WCF client/server situation. My WCF server has a class level declaration of the Entity Framework class for my database access and several methods to modify data and a method to SaveChanges. I'm using the Oracle Data Access (ODP.NET).
For instance I want to call a modification from the client and then a separate call to save the changes in the WCF service. It doesn't work. Basically, everything executes fine, but when the second call to save the changes is made, the WCF service no longer has the original context and therefore no changes are saved (and, consequently, the previous call that made the changes was automatically rolled back).
I'm utilizing Transaction scope around both operations in my client and executing Complete() after done. My WCF services have OperationContract's that use [TransactionFlow(TransactionFlowOption.Mandatory)] and those method implementations use [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]. Finally, my web config is configured with a wsHttpBinding that has the transactionFlow property set to True.
I'm having no luck. No matter what I try, when I try hitting the service for the follow-up save, the EF context is already renewed.
This has nothing to do with transaction. Transaction works on transactional resource but without calling SaveChanges in the first request there was no transactional resource active because EF context is not part of the transaction - the database is and the database is affected only when you call SaveChanges. To make this work you don't need distributed transactions. You need session-full service and store the EF context in the service instance. It a client uses the same client proxy instance to communicate with the service for all requests the communication will be handled by the same service instance = same EF context instance which will remember changes from previous calls.
IMHO this is very bad architecture. Simply don't use it. Expose specialized methods on WCF service which will do changes and save them. If you need to execute these methods in transaction with other transactional resources use the real distributed transaction.
this might be a reason. Since your are making an update in the different context. context doesn't know that the object is update to have say the context that the object is modified and then you call savechnages(). See if it helps
Is Castle Windsor's Inteceptor mechanism considered to be a good/effective way of implementing the Unit of Work pattern?
My project involves Castle Windsor, the NHibernate Facility and of course NHibernate - all used in self-hosted WCF services.
Each service method normally requests from the Windsor container an instance of a helper class into which the WCF call is delegated. The helper class has an ISessionManager constructor argument which Windsor resolves via the NHibernate Facility.
The trouble is, the helper class is doing too much work. It has both logic and data access intermingled which means its difficult (virtually impossible) to test and difficult to read.
What I want is to re-arrange responsibilities
I don't want the WCF helper to know anything about transactions or sessions, so no ISessionManager constructor arg, no references to transactions and no ISession.
In order for the WCF helper to do data access, its going to have to rely on a new helper, dare I call it a DAO? or God forbid a repository, on which will be methods for fetching, querying, and possibly saving domain objects.
The problem with returning NHibernate proxied objects from a DAO is that if the session is closed before the entity is returned, any subsequent attempt to access collections on the domain object from the client code will result in an exception as the session is no longer there to be used to lazily fetch the required data. It's obvious really, but everyone new to NHibernate must hit this issue.
So if DAOs and Repos cant close the session, what does?
What I need is one NHibernate session per WCF service operation call, where several DAOs or Respositories can call OpenSession as much as they like, but they all get the same session, and ideally, any attempt to dispose the session would be ignored unless its the last Dispose. Not sure about the last bit, but maybe DAOs and repos just call ISessionManager.OpenSession and leave it to something else to flush and dispose the session.
I thought maybe I could use an interceptor which takes an ISessionManager, opens a session and starts a transaction, forwards the invocation, then if no exception occurs, commits the transaction and disposes the session, otherwise rolls back the transaction if any exception occurs.
Any thoughts?
So if DAOs and Repos cant close the
session, what does?session, what does?
Services own units of work, not DAOs. They demark units of work.
Spring manages transactions using AOP, so interceptors sound like a good bet for transaction management to me.
As far as sessions go, those are UI concepts, so it ought to be the web or desktop UI controller that opens the session, marshals services to fulfill use cases, and closes the session when it's complete.
Castle.Service.Transactions also ties well together with the rest of the castle stack and allow you to use AOP to handle transactions.
Have a look at v3!
https://github.com/haf/Castle.Services.Transaction
And the wiki there!
I also created a new NHibernate Facility:
https://github.com/haf/Castle.Facilities.NHibernate/wiki/NHibernate-Facility---Quick-Start
I'm developing and application that runs as a Windows service. There are other components which include a few WCF services, a client GUI and so on - but it is the Windows service that access the database.
So, the application is a long-running server, and I'd like to improve its performance and scalability, I was looking to improve data access among other things. I posted in another thread about second-level caching.
This post is about session management for the long-running thread that accesses the database.
Should I be using a thread-static context?
If so, is there any example of how that would be implemented.
Every one around the net who is using NHibernate seem to be heavily focussed on web-application style architectures. There seems to be a great lack of documentation / discussion for non-web app designs.
At the moment, my long running thread does this:
Call 3 or 4 DAO methods
Verify the state of the detached objects returned.
Update the state if needed.
Call a couple of DAO methods to persist the updated instances. (pass in the id of the object and the instance itself - the DAO will retrieve the object from the DB again, and set the updated values and session.SaveOrUpdate() before committing the transaction.
Sleep for 'n' seconds
Repeat all over again!
So, the following is a common pattern we use for each of the DAO methods:
Open session using sessionFactory.OpenSession()
Begin transaction
Do db work. retrieve / update etc
Commit trans
(Rollback in case of exceptions)
Finally always dispose transaction and session.Close()
This happens for every method call to a DAO class.
I suspect this is some sort of an anti-pattern the way we are doing it.
However, I'm not able to find enough direction anywhere as to how we could improve it.
Pls note, while this thread is running in the background, doing its stuff, there are requests coming in from the WCF clients each of which could make 2-3 DAO calls themselves - sometimes querying/updating the same objects the long running thread deals with.
Any ideas / suggestions / pointers to improve our design will be greatly appreciated.
If we can get some good discussion going, we could make this a community wiki, and possbily link to here from http://nhibernate.info
Krishna
There seems to be a great lack of documentation / discussion for non-web app designs.
This has also been my experience. However, the model you are following seems correct to me. You should always open a session, commit changes, then close it again.
This question is a little old now, but another technique would be to use Contextual Sessions rather than creating a new session in each DAO.
In our case, we're thinking of creating the session once per thread (for our multi-threaded win32 service), and make it available to the DAOs using either a property that returns SessionFactory.GetCurrentSession() (using the ThreadContext current session provider, so it's session-per-thread) or via DI (dependency injection - once again using ThreadContext.)
More info on GetCurrentSession and Contextual Sessions here.
You can also flush the session without actually closing it and it achieves the same thing. I do.
We've recently started using an IoC container to manage session lifecycle, as a replacement for the contextual sessions mentioned above. (More details here).
I agree, there aren't many examples for stateful apps.
I'm thinking of doing the following:
Like you I have a windows service hosting a number of WCF services. So the WCF services are the entry points.
Ultimately all my WCF services inherit from AbstractService - which handles a lot of logging and basic DB inserts/updates.
In one of the best NHibernate posts I've seen, a HttpModule does the following:
see http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx
private void BeginTransaction(object sender, EventArgs e) {
NHibernateSessionManager.Instance.BeginTransaction();
}
private void CommitAndCloseSession(object sender, EventArgs e) {
try {
NHibernateSessionManager.Instance.CommitTransaction();
}
finally {
NHibernateSessionManager.Instance.CloseSession();
}
}
So perhaps I should do something similar in AbstractService. So effectively I'll end up with a session per service invocation. If you examine the NHib best practices article link above, you'll see that the NHibernateSessionManager should deal with everything else, as long as I open and close the session (AbstractService constructor and destructor).
Just a thought. But I'm experiencing errors because my session seems to be hanging around for too long, and I'm getting the infamous error - NHibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs).