How to pass unit of work container into constructor of repository using dependency injection?

I have a persistence framework built on top of Nbernate that is used in a few Web apps. It hides the NH implementation behind an IRepository and IRepository.

I have a persistence framework built on top of Nbernate that is used in a few Web apps. It hides the NH implementation behind an IRepository and IRepository interface, with the concrete instances provided by Unity (thus I could in theory swap out N say, Entity Framework fairly easily). Since Unity doesn't (or at least the version I'm using doesn't) support the passing in of constructor parameters other than those that are dependency injections themselves, passing in an extant NH ISession isn't possible; but I do want all objects in the UOW to share the same ISession.

I solve this by having a controlling repository class that manages access to the ISession on a per-thread basis: public static ISession Session { get { lock (_lockObject) { // if a cached session exists, we'll use it if (PersistenceFrameworkContext.Current.Items. ContainsKey(SESSION_KEY)) { return (ISession)PersistenceFrameworkContext.Current. ItemsNSESSION_KEY; } else { // must create a new session - note we're not caching the new session here... that's the job of // BeginUnitOfWork().

Return _factory. OpenSession(new N } } } } In this example, PersistenceFrameworkContext.Current. Items accesses an IList that is stored either ThreadStatic if not in a Web context, or within HttpContext.Current.

Items if it is in a Web context (to avoid thread-pool problems). The first call to the property instantiates the ISession from the stored factory instance, subsequent calls just retrieve it from storage. The locking will slow things down slightly but not as much as just locking an appdomain-scoped static ISession instance.

I then have BeginUnitOfWork and EndUnitOfWork methods to take care of the UOW - I have specifically disallowed nested UOWs because frankly they were a pain to manage. Public void BeginUnitOfWork() { lock (_lockObject) { if (PersistenceFrameworkContext.Current.Items. ContainsKey(SESSION_KEY)) EndUnitOfWork(); ISession session = Session; PersistenceFrameworkContext.Current.Items.

Add(SESSION_KEY, session); } } public void EndUnitOfWork() { lock (_lockObject) { if (PersistenceFrameworkContext.Current.Items. ContainsKey(SESSION_KEY)) { ISession session = (ISession)PersistenceFrameworkContext.Current. ItemsSESSION_KEY; PersistenceFrameworkContext.Current.Items.

Remove(SESSION_KEY); session.Flush(); session.Dispose(); } } } Finally, a pair of methods provide access to the domain-type-specific repositories: public IRepository For() where T : PersistentObject { return Container.Resolve(); } public TRepository For() where T : PersistentObject where TRepository : IRepository { return Container.Resolve(); } (Here, PersistentObject is a base class providing ID and Equals support. ) Access to a given repository is thus in the pattern NFor().Save(); This is then facaded over such that you can use MyDomainType.Repository.Save(); Where a given type has a specialised repository (ie needs more than it can get from IRepository) then I create an interface deriving from IRepository, an extending implementation inheriting from my IRepository implementation, and in the domain type itself I override the static Repository property using new new public static IUserRepository Repository { get { return MyApplication.Repository.For(); } } (MyApplication which is called something less noddy in the real product is a facade class which takes care of supplying the Repository instance via Unity so you have no dependency on the specific Nbernate repository implementation within your domain classes. ) This gives me full pluggability via Unity for the repository implementation, easy access to the repository in code without jumping through hoops, and transparent, per-thread ISession management.

There's lots more code than just what's above (and I've simplified the example code a great deal), but you get the general idea. MyApplication.Repository.BeginUnitOfWork(); User user = User.Repository. FindByEmail("[email protected]"); user.

FirstName = "Joe"; // change something user. LastName = "Bloggs"; // you *can* call User.Repository. Save(user), but you don't need to, because... MyApplication.Repository.EndUnitOfWork(); // ...causes session flush which saves the changes automatically In my Web app, I have session-per-request, so BeginUnitOfWork and EndUnitOfWork get called in BeginRequest and EndRequest respectively.

That's awesome. I'll definitely be checking out if my code could use some of yours' goodness. XD – rebelliard Jul 23 '10 at 14:41 Stack Overflow needs a button for 'Probably the right answer, but to be frank I don't understand it'.

I'd be clicking it right here. I will try to digest it all over the weekend but it may come second best to getting drunk. At least I appreciated your email address!

– David Jul 23 '10 at 15:22 Getting drunk is an excellent idea which I shall be copying later this evening :-) As for the code, all the levels of indirection and metaprogramming does make for a harder read. The real and full implementation of our persistence framework is about the most complex code in our arsenal here - but once you've done it once, you never need to do it again. It's paid for itself many times over.

– Neil Hewitt Jul 23 '10 at 15:28.

See this article for a full explanation of how to provide sessions to concrete repository implementations using castle.

Thanks, I'm having a good look, but digestion will take some time. – David Jul 23 '10 at 13:44.

I have a pretty similar structure to yours, and here's how I solve your question: 1) To specify my container on each method, I have a separate class ("SessionManager") which I then invoke via a static property. By doing so, here's an example using my Save implementation: private static ISession NbernateSession { get { return SessionManager.Instance.GetSession(); } } public T Save(T entity) { using (var transaction = NBeginTransaction()) { ValidateEntityValues(entity); NSave(entity); transaction.Commit(); } return entity; } 2) My container is not created on each ASPX page. I instantiate all of my Nbernate goodness on the global.

Asax page. ** A few more things spring up ** 3) You don't need to have a helper to instantiate the Load. You might as well use Get instead of Load.

More information @ Difference between Load and Get. 4) Using your current code, you would have to repeat pretty much the same code for each domain object you need (StoredWillRepository, PersonRepository, CategoryRepository, etc..?), which seems like a drag. You could very well use a generic class to operate over N like: public class Dao : IDao { public T SaveOrUpdate(T entity) { using (var transaction = NBeginTransaction()) { NSaveOrUpdate(entity); transaction.Commit(); } return entity; } } In my implementation, I could then use something like: Service.Instance.

SaveOrUpdate(will).

Thank you very much for your input. I'll respond to your points in numbered comments below: – David Jul 23 '10 at 13:45 1) A static ISession? Unless I've misunderstood, that would mean the ISession (which is not thread safe) is shared between all threads of the application - very dangerous.Is this not correct?

– David Jul 23 '10 at 13:46 2) Container for what? Sorry, I don't see what you mean. – David Jul 23 '10 at 13:47 3) In the code I posted, I used NUtil to pre-load the entity.

Notice the Session is created and destroyed in the method call. This means the returned entity would be outside the Session, so when it tries to lazy load, an exception is thrown. Since I'm now passing an ISession in to the factory, I don't have to preload the entity as it will lazy load normally.

– David Jul 23 '10 at 13:48 1 Apparently ThreadStatic is not a good idea in ASP. NET: hanselman.Com/blog/StoringThingsOnThreads. Aspx – David Jul 23 '10 at 14:03.

Technically, the answer to my question is to use the overload of container. Resolve which allows you to specify the constructor argument as an anonymous type: IUnitOfWork unitOfWork = Code to get unit of work; _storedWillRepository = container. Resolve(new { unitOfWork = unitOfWork }); But let's face it, the answers provided by everyone else have been much more informative.

This is, as you say, technically the answer to my question even if not the best solution architecturally. I'm green-ticking you. – David Nov 4 '10 at 14:51.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions