PDA

View Full Version : Session Management in a WinForms App



pathakn
10-14-2006, 10:16 AM
Hi

I have been using Spring, Hibernate pretty successully in my Java project. However this time around I am working on a Winform App. In trying to use Spring.NET and NHibernate in this app I am a bit concerned about what are the implications of doing something like below:

ISessionFactory sessionFactory= (ISessionFactory) m_AppContext.GetObject("SessionFactory");
ISession session = SessionFactoryUtils.GetSession(sessionFactory, true);
TransactionSynchronizationManager.BindResource(ses sionFactory, new SessionHolder(session));
TransactionSynchronizationManager.InitSynchronizat ion();

Basically, immediately after I create my appcontext I get hold of a session and make sure that is the session that gets used through out the life of the app. Since Web apps follow a per request session model I am curious and concerned about any implication of the above model.

Ideas please.

Mark Pollack
10-16-2006, 06:15 AM
Hi,

I wouldn't use a single singleton session for the entire application, the scope is too big. I would have a session/transaction per logical use-case operation in the business service layer. Look in the NHibernate forums for more details.

Your business service layer would demarcate the transaction and then use as many data access objects as necessary. In a winform application I would have a controller that responds to the user events pass the appropriate information to the business service layer. Code up your DAOs using HibernateTemplate and you won't have have any session management code in your data access object at all - which is one of the main reasons to use the template in the first place.

I've coded up a shell of an example and put it in CVS under the example directory for the NHibernate integraiton project. It isn't working yet but you will get the idea looking at the structure which I'll briefly show below.

There are data access interfaces and the domain objects in the assembly Spring.Northwind.Dao such as this one for Customer.


public interface ICustomerDao
{
Customer FindById(string customerId);
IList FindAll();
Customer Save(Customer customer);
Customer SaveOrUpdate(Customer customer);
void Delete(Customer customer);
}


An NHibernate implementation is in the assembly Spring.Northwind.Dao.NHibernate



public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
{
public Customer FindById(string customerId)
{
return HibernateTemplate.Load(typeof (Customer), customerId) as Customer;
}

public IList FindAll()
{
return HibernateTemplate.LoadAll(typeof (Customer));
}

public Customer Save(Customer customer)
{
HibernateTemplate.Save(customer);
return customer;
}

// etc..

}


The business service is in the assembly Spring.Northwind.Service and some trival use-case I made up is shown below. You winform controller would reference this class. The important thing is the transaction demarcation via the attribute, which will trigger the hibernate tx/session management for the method scope.



public class FulfillmentService : IFulfillmentService
{

private ICustomerDao customerDao;
private IOrderDao orderDao;
private IShippingService shippingService;

// Corresponding Properties

[Transaction()]
public void ProcessCustomer(string customerId)
{
Customer customer = CustomerDao.FindById(customerId);
foreach (Order order in customer.Orders)
{
//Validate Order
Validate(order);

//Ship with external shipping service
ShippingService.ShipOrder(order);

//Update shipping date
order.ShippedDate = DateTime.Now;

//Update shipment date
OrderDao.SaveOrUpdate(order);


//Other operations...Decrease product quantity... etc
}

}
}



Hope this helps...I'll be working on this a bit more tomorrow, hopefully you will be able to cut-n-paste configuration etc. for your needs.

Cheers,
Mark

pathakn
10-16-2006, 09:46 AM
Hi Mark,

Thanks for your prompt response.

What you have suggested is what exactly I plan to use for my update/save operations. I also looked at your example but it still does not cover the kind of use cases I am looking for.

For example in my app there are couple of getter use cases which load data using ui/service/dao combination. The UI layer is a tree control just like explorer in Windows Explorer. So it needs to get the root folder and then build the subtree using folders underneath. If I just get the root folder using service/dao (and if I have configured the children to load in lazy manner in my hbm file) and then start to navigate through the root folder to build the tree I get an exception as expected (LazyLoadException) saying that the session has been closed. Now in web model this would not be a problem 'cos the page would be built first and the session would remain alive until then. Once the page is rendered and response sent back the session would close (OpenSessionInViewFilter).

Hence I thought I need to keep the session alive. However I see your point that it might result in one humungous session and also the fact that whole database might be sitting in-memory but then how do I get around the problem that my UI controls would need to load the aggregate objects (which are configured to be lazy loaded).

One pattern could be to make service/dao request for each click in the tree control and load objects one level at a time. Haven't gotten around to think of the implications of this one.

The other pattern could be to make sure I navigate the object graph in the service to the level I expect the UI control to expand before handing over the root object to UI. But I almost regret suggesting the pattern as I write it and can see the obvious flaws i.e. how do I know what a user would click.

Further ideas?

Mark Pollack
10-16-2006, 03:34 PM
Hi,

How many root/leaf nodes to you have? Why not just pull all the node information needed to display the tree control when the control is initializing? I guess you have a good reason. If there is a detail screen to show at each level of the node that would be a better candidate to load on demand based on the click on the tree node itself.

I don't get the analogy with the web model. The OpenSessionInView functionality works only within transaction boundaries, so you would still have to load the entire object graph for populating the asp.net tree control. There has been some talk about providing a session scope that isn't tied to the transaction boundary but nothing implemented yet.

Hope this helps.
Mark

pathakn
10-16-2006, 03:51 PM
Well that's the thing - I don't know the tree depth. In addition, what's the use of lazy loading in Winforms app then? If I am supposed to be loading/navigating the aggregate objects in Service before using them in UI - doesn't that suck the whole (or atleast partially) DB in the memory?

There is some implementation of session scope here. Have you got a chance to look at it? Its for ORM version and probably needs a little migration to make it work with Spring.Data.NHibernate - but do you think the idea is workable?

http://forum.springframework.net/showthread.php?t=676

Mark Pollack
10-16-2006, 04:06 PM
Hi,

I didn't see that post oops... my head has been down in the 'sand' working on projects and I'm just getting back on track. I'll review it and get back to you. Yea, it would suck in the all the node information, but unless you think you are going to have thousands of nodes, I doubt that there is any serious performance penalty to loading that information at startup. Node objects shouldn't be that 'heavy' to load....my 'spidey sense' of doing premature optimization is tingling...

I would be conservative right now in terms of using session scope within the winform, the session is bound to the thread, not the originating form, so if you have other MDI forms with actions firing on the GUI thread you are back to a very long lived session with potential interference of objects in the session from other forms. The scope would have to be wrapped around the creation of the form I'd guess and have to ensure nothing else is going to muck with the session on that thread. I've just started reviewing the winform framework the Chris Donnan committed - there are probably some helper classes regarding winform thread mgmt that maybe useful... I'll ping him, point him here, and see what he has to say. In any case, if you feel like experimenting...I'm all ears...

Cheers,
Mark

pathakn
10-16-2006, 04:32 PM
Sorry - didn't quite understand what Chris checked in and where?

Please can you point me to the project? Was it something related to how the sessions should be handled in WinForms app?

Mark Pollack
10-16-2006, 04:41 PM
Hi Nilesh,

Chris checked in 'Spring.Daf' under the sandbox/src/Spring but nothing specific for session mgmt. I just emailed him regarding this posting. Did you search the nhibernate forums btw? There are some posting regarding winform development...

Mark

pathakn
10-16-2006, 09:46 PM
Hi Mark,

I spent last couple of hours looking at NHibernate forums. Not much promising though I stumbled upon couple of ideas and custom implementation of LazyLoadCollections.

Any progress with Chris and/or SessionScope?

.ben
10-17-2006, 09:49 AM
custom implementation of LazyLoadCollections

I use a session per business transaction like Mark posted in all WinApps which I have created untill now.

For lazy loading I use the following structure (translations of an item):


public IList<TranslationType> Translations
{
get
{
if (m_translationsDomainChildCollection.ShouldLoad(m_ translations))
{
m_translationsDomainChildCollection.Load(this, ref m_translations);
}

return m_translationsDomainChildCollection;
}
}


public LoadChildCollection<Guid, TranslatedItem, TranslationType> SetLoadTranslations
{
set
{
m_translationsDomainChildCollection.LoadCollection Callback = value;
}
}


Basically the wiring is done by spring. I request a new object from the configuration every time I need one, in the configuration I indicate which DAO should be called to load the collection. This delegate is set in that writeonly property LoadChildCollection.

When I hit the child collection via the property Translations, the domainChildCollection looks at the mapped list (in this case m_translations) and if has to be loaded it will hit the database.

pathakn
10-18-2006, 07:53 AM
Any updates Mark?

chrisdonnan
10-19-2006, 04:01 AM
The closest thing I have added in there is a 'command model' There is a BackgroundPresenterCommand in

/springnet/Spring.Net/sandbox/src/Spring/Spring.Daf/UIModel/

http://springnet.cvs.sourceforge.net/springnet/Spring.Net/sandbox/src/Spring/Spring.Daf/UIModel/

The idea here is that you have some view, some presenter, and some presenter commands that carry out automation of a view. You can see example uses in:

springnet/Spring.Net/examples/Spring/Spring.Daf.Demo/Commands/LongRunningCommand.cs
http://springnet.cvs.sourceforge.net/springnet/Spring.Net/examples/Spring/Spring.Daf.Demo/Commands/LongRunningCommand.cs?hideattic=1&revision=1.2&view=markup

LongRunningCommand.cs

The idea is to use the SyncContext, for thread control and to seperate the command logic into foreground/ background via the command model it self.

-Chris

steinard
07-16-2007, 10:38 AM
Hi!

There is a similar discussion here: http://forum.springframework.net/showthread.php?t=2775

Cheers,
Steinar.