In a set of SOAP web services the user is authenticated with custom SOAP header (username/password). Each time the user call a WS the following Auth method is called to authenticate and retrieve User object from NHibernate session:
[...]
public Services : Base {
private User user;
[...]
public string myWS(string username, string password)
{
if( Auth(username, password) ) { [...] }
}
}
public Base : WebService {
protected static ISessionFactory sesFactory;
protected static ISession session;
static Base {
Configuration conf = new Configuration();
[...]
sesFactory = conf.BuildSessionFactory();
}
private bool Auth(...) {
session = sesFactory.OpenSession();
MembershipUser user = null;
if (UserCredentials != null && Membership.ValidateUser(username, password))
{
luser = Membership.GetUser(username);
}
...
try {
user = (User)session.Get(typeof(User), luser.ProviderUserKey.ToString());
} catch {
user = null;
throw new [...]
}
return user != null;
}
}
When the WS work is done the session is cleaned up nicely and everything works: the WSs create, modify and change objects and Nhibernate save them in the DB.
The problems come when an user (same username/password) calls the same WS at same time from different clients (machines). The state of the saved objects are inconsistent.
How do I manage the session correctly to avoid this? I searched and the documentation about Session management in NHibernate is really vast. Should I Lock over user object? Should I set up a "session share" management between WS calls from same user? Should I use Transaction in some savvy way?
Thanks
Update1
Yes, mSession is 'session'.
Update2
Even with a non-static session object the data saved in the DB are inconsistent. The pattern I use to insert/save object is the following:
try {
Auth([...]);
} catch {
// ....
}
var return_value = [...];
try {
using(ITransaction tx = session.Transaction)
{
tx.Begin();
MyType obj = new MyType();
user.field = user.field - obj.field; // The fields names are i.e. but this is actually what happens.
session.Save(user);
session.Save(obj);
tx.Commit();
return_value = obj.another_field;
}
} catch ([...]) {
// Handling exceptions...
} finally {
// Clean up
session.Flush();
session.Close();
}
return return_value;
All new objects (MyType) are correctly saved but the user.field status is not as I would expect. Even obj.another_field is correct (the field is an ID with generated=on-save policy).
It is like 'user.field = user.field - obj.field;
' is executed more times then necessary.