RavenDb session management for WCF and integration testing - wcf

Put simply, I have a WCF service that manages apples. Apart from other functionality, it has two methods to add and remove apples from storage. I am writing an integration test to check if someone is getting advantage of the job and nicks apples. Raven DB in my WCF service has an audit role, it just records actions and apples. In the methods of WCF service there is some other processing: cleaning, validation, packaging etc.
My audit integration test can be expresses as
Empty storage (RavenDB in-memory mode)
Bob comes and puts 10 apple (open session, add, dispose session)
Jake comes and takes 4 apples (open session, remove, dispose session)
Check that 6 apples left
As these are two different people (two WCF calls) it make sense to use different instances of session. However, with Raven DB I get
Exception
Apple is not associated with the session, cannot delete unknown entity
instance
If I now run similar integration test where two different people just add apples to the storage, the total storage content corresponds to truth. This is confusing bit: adding works across session, removing doesn't work. In this post Ayende says session micro-managing is not the way to go, but it seems natural to me to use different sessions in my integration testing. Hope analogy with apples doesn't put you off.
Question: How do I use sessions in integration testing with RavenDB?
Sample code (from notepad)
public void Remove(Apple apple)
{
using (var session = Store.OpenSession())
{
session.Delete(apple);
session.SaveChanges();
}
}
public void Add(Apple apple)
{
using (var session = Store.OpenSession())
{
session.Store(apple);
session.SaveChanges();
}
}
...
var apples = new apples[10];
//init
MyRavenDB.Add(apples);
MyRavenDB.Remove(apples.Take(4)); //throws here
//verify

In RavenDB, "The session manages change tracking for all of the entities that it has either loaded or stored".
I suspect the Apple reference you are passing to Remove() method, did not originate from RavenDB Document Store, hence the error.
Try this:
public void Remove(Apple apple)
{
using (var session = Store.OpenSession())
{
var entity = session.Load<Apple>(apple.Id);
session.Delete(entity);
session.SaveChanges();
}
}

You are passing entities over the wire, and that is generally a big no-no.
Do it like this:
public void Remove(string appleId)
That would give you much better sematnics.

Related

Using SharpArch Nhibernate with different types of SessionStorage

I have a server application where I have 3 scenarios in which I seem to need different kind of nhibernate sessions:
Calls to the repository directly from the server itself (while bootstrapping)
Calls to the repository coming from a Ria Service (default ASP.NET Memberschip Service)
Calls to the repository coming from a WCF Service
Currently I have set up my nhibernate config with sharparch like this
/// <summary>
/// Due to issues on IIS7, the NHibernate initialization cannot reside in Init() but
/// must only be called once. Consequently, we invoke a thread-safe singleton class to
/// ensure it's only initialized once.
/// </summary>
protected void Application_BeginRequest(object sender, EventArgs e)
{
NHibernateInitializer.Instance().InitializeNHibernateOnce(
() => InitializeNHibernateSession());
BootStrapOnce();
}
private void InitializeNHibernateSession()
{
NHibernateSession.Init(
wcfSessionStorage,
new string[] { Server.MapPath("~/bin/bla.Interfaces.dll") },
Server.MapPath("~/Web.config"));
}
This works for the third scenario, but not for the first two.
It seems to need some wcf-session-specific context.
The SharpArch Init method seems to have protection from re-initializing it with another type of sessionstorage;
What is the best way to create a different session for three different kinds of contexts?
To me it looks like this post seems related to this one which has helped me looking in the right direction, but I have not found a solution so far.
I'm not sure you are going to be able to do what you are wanting with S#. The reason being is that you are really wanting to have 3 separate Nhibernate sessions, each with it's own storage mechanism. The current implementation only allows for one storage mechanism, regardless of the number of sessions.
I can easily get you #'s 1 and 3, but not two since I've never used RIA services. In the case of 1 and 3, you would need to take the WCF service out of the site and have it in it's own site. No way of really getting around that as their session lifecycles are different.
Your other option would be to come up with your own Session Management for NHibernate and not use the default S# one. You could look at the code for the S# version and create your own based on that.

NHibernate + WCF + Windows Service and WcfOperationSessionContext class

I have a Windows Service Application
in which i create WCF services in it.
One of the services is data
services: add, delete,
read , updatte data via
WCF.
WCF use NHibernate for data manipulation
So my guestions are:
Any advice (best practice) for session management for Hibernate using with WCF?
Anybody knows anything about
WcfOperationSessionContext (hibernate 3.0) class?
how to use it with WCF?
Well to make it concrete :
Suppose that i have WCF Service called DataServices
class WCFDataService .....
{
void SaveMyEntity(MyEntity entity)
{
.....................?? // How to do? Best Way
// Should i take one session and use it all times
// Should i take session and dipsose when operation finished then get
//new session for new operations?
// If many clients call my WCF service function at the same time?
// what may go wrong?
// etc....
}
}
And I need a NHibernateServiceProvider class
class NHibernateServiceProvider ....
{
// How to get Session ?? Best way
ISession GetCurrentSession(){.... }
DisposeSession(){ ....}
}
Best Wishes
PS: I have read similiar entries here and other web pages. But can not see "concrete" answers.
The WcfOperationSessionContext, similar to ThreadStaticSessionContext and WebRequestSessionContext is an implementation for a session context. The session context is used to bind (associate) a ISession instance to a particular context.
The session in the current context can be retrieved by calling ISessionFactory.GetCurrentSession().
You can find more information about session context here.
The WcfOperationSessionContext represents a context that spans for the entire duration of a WCF operation. You still need to handle the binding of the session in the begining of the operation and the unbinding/commiting/disposal of the session at the end of the operation.
To get access to the begin/end actions in the wcf pipeline you need to implement a IDispatchMessageInspector. You can see a sample here.
Also regarding WCF integration: if you use ThreadStatic session context it will appear to work on development, but you will hit the wall in production when various components (ex: authorization, authentication ) from the wcf pipeline are executed on different threads.
As for best practices you almost nailed it: Use WcfOperationSessionContext to store the current session and the IDispatchMessageInspector to begin/complete your unit of work.
EDIT - to address the details you added:
If you configured WcfOperationSessionContext and do the binding/unbinding as i explained above, all you have to do to is inject the ISessionFactory into your service and just use factory.GetCurrentSession(). I'll post a sample prj if time permits.
Here is the sample project
The model we use for managing NHibernate sessions with WCF is as follows:
1) We have our own ServiceHost class that inherits from System.ServiceModel.ServiceHost which also implements ICallContextInitializer. We add the service host instance to each of the operations in our service as follows:
protected override void InitializeRuntime()
{
base.InitializeRuntime();
foreach (ChannelDispatcher cd in this.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
foreach (DispatchOperation op in ed.DispatchRuntime.Operations)
{
op.CallContextInitializers.Add(this);
}
}
}
}
public void AfterInvoke(object correlationState)
{
// We don't do anything after the invoke
}
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
OperationContext.Current.Extensions.Add(new SessionOperationContext());
return null;
}
The BeforeInvoke simply makes sure that the OperationContext for each WCF call has it's own session. We have found problems with IDispatchMessageInspector where the session is not available during response serialisation - a problem if you use lazy loading.
2) Our SessionOperationContext will then be called to attach itself and we use the OperationCompleted event to remove ourselves. This way we can be sure the session will be available for response serialisation.
public class SessionOperationContext : IExtension<OperationContext>
{
public ISession Session { get; private set; }
public static SessionOperationContext Current
{
get
{
OperationContext oc = OperationContext.Current;
if (oc == null) throw new InvalidOperationException("Must be in an operation context.");
return oc.Extensions.Find<SessionOperationContext>();
}
}
public void Attach(OperationContext owner)
{
// Create the session and do anything else you required
this.Session = ... // Whatever instantiation method you use
// Hook into the OperationCompleted event which will be raised
// after the operation has completed and the response serialised.
owner.OperationCompleted += new EventHandler(OperationCompleted);
}
void OperationCompleted(object sender, EventArgs e)
{
// Tell WCF this extension is done
((OperationContext)sender).Extensions.Remove(this);
}
public void Detach(OperationContext owner)
{
// Close our session, do any cleanup, even auto commit
// transactions if required.
this.Session.Dispose();
this.Session = null;
}
}
We've used the above pattern successfully in high-load applications and it seems to work well.
In summary this is similar to what the new WcfOperationSessionContext does (it wasn't around when we figured out the pattern above;-)) but also overcomes issues surrounding lazy loading.
Regarding the additional questions asked: If you use the model outlined above you would simply do the following:
void SaveMyEntity(MyEntity entity)
{
SessionOperationContext.Current.Session.Save(entity);
}
You are guaranteed that the session is always there and that it will be disposed once the WCF operation is completed. You can use transactions if required in the normal way.
Here is a post describing, in detail, all the steps for registering and using the WcfOperationSessionContext. It also includes instructions for using it with the agatha-rrsl project.
Ok, after few days of reading internet posts etc. all approaches shown in the internets seems to be wrong. When we are using UnitOfWork pattern with NH 3^ with nhibernate transaction this all aprochaes are producing exceptions. To test it and proof that we need to create test enviroment with MSMQ transaction queue, special interface with OneWay operation contract with transaction required set on it. This approach should works like this:
1. We put transactionally message in queue.
2. Service is getting transactionally messege from queue.
3. Everything works queue is empty.
In some cases not so obious with internet approaches this does not work properly. So here are expamples which we tested that are wrong and why:
Fabio Maulo approach: Use ICallContextInitializer - open NH session/transaction on BeforeCall, after that WCF is executing service method, on AfterCall in context initializer we call session.Flush + transaction.commit. Automaticly session will be saved when transaction scope will commit operation. In situation when on calling transaction.Complete exception will be thrown WCF service will shutdown! Question can be ok, so take transaction.Complete in try/catch clausule - great! - NO wrong! Then transaction scope will commit transaction and message will be taken from queue but data will not be saved !
Another approach is to use IDispatchMessageInspector - yesterday I thought this is best approach. Here we need to open session/transaction in method AfterReceiveRequest, after WCF invoke service operation on message dispatcher inspector BeforeSendReply is called. In this method we have info about [reply] which in OneWay operation is null, but filled with fault information if it occured on invoking service method. Great I thought - this is this ! but NOT! Problem is that at this point in WCF processing pipe we have no transaction ! So if transaction.Complete throw error or session.Flush will throw it we will have not data saved in database and message will not come back to queue what is wrong.
What is the solution?
IOperationInvoker and only this!
You need to implement this interface as a decorator pattern on default invoker. In method Invoke before call we are openning session/transaction open then we call invoke default invoker and after that call transaction.complete in finally clausule we call session.flush. What types of problem this solves:
1. We have transaction scope on this level so when complete throws exception message will go back to queue and WCF will not shutdown.
2. When invocation will throw exception transaction.complete will not be called what will not change database state
I hope this will clear everyones missinformation.
In some free time I will try to write some example.

NHibernate many to many and ISession.Close()

I am using NHibernate for my project. i am quite a beginner at working on NHibernate.
I use many-to-many relation mapping "users" and "roles". Here is the code to get the user:
public User GetUser(int userId){
using(ISessuib session = new SessionManager().GetSession())
{
return session.Get<User>(userId);
}
}
public void LazyLoadUsingSessionTest(){
var user= GetUser(1);
Assert.NotNull(user.Roels);
}
it throws an exception:failed to lazily initialize a collection, no session or session was closed
if i do not use the "using" statement in the "GetUser" method,it works. But i must call the session.Close() to release the resource
when i use it in a web page,i only want to use the GetUser(), not the ISession object.so my question is : Does it mean that i must have a ISession object(to release resouse) in my web page? or any better solution?(because i do not want the ISession object appears in my aspx.cs files)
thanks!
You need to use the Session per Request pattern. See this link for an explanation of the best practices for using NHibernate with ASPX.
The simplest way is to use NHibernateUtil.Initialize (read here for details):
using(ISession session = new SessionManager().GetSession())
{
User user = session.Get<User>(userId);
NHibernateUtil.Initialize(user.Roles);
return user;
}
However, sooner or later you would need to somehow manage the sessions in your application. I recommend creating a data provider layer that would give you access to the database. The data provider layer will manage the creation and destruction of sessions. You could either have a session per request or per conversation (single ISession for the duration of an ASP.Net session).
The Summer Of NHibernate video series would be helpful. Session 5 and 13 are most relevant for you.

Best way to share data between .NET application instance?

I have create WCF Service (host on Windows Service) on load balance server. Each of this service instance maintain list of current user. E.g. Instance A has user A001, A002, A005, instance B has user A003, A004, A008 and so on.
On each service has interface that use to get user list, I expect this method to return all user in all service instance. E.g. get user list from instance A or instance B will return A001, A002, A003, A004, A005 and A008.
Currently I think that I will store the list of current users on database but this list seem to update so often.
I want to know, is it has another way to share data between WCF service that suit my situation?
Personally, the database option sounds like overkill to me just based on the notion of storing current users. If you are actually storing more than that, then using a database may make sense. But assuming you simply want a list of current users from both instances of your WCF service, I would use an in-memory solution, something like a static generic dictionary. As long as the services can be uniquely identified, I'd use the unique service ID as the key into the dictionary and just pair each key with a generic list of user names (or some appropriate user data structure) for that service. Something like:
private static Dictionary<Guid, List<string>> _currentUsers;
Since this dictionary would be shared between two WCF services, you'll need to synchronize access to it. Here's an example.
public class MyWCFService : IMyWCFService
{
private static Dictionary<Guid, List<string>> _currentUsers =
new Dictionary<Guid, List<string>>();
private void AddUser(Guid serviceID, string userName)
{
// Synchronize access to the collection via the SyncRoot property.
lock (((ICollection)_currentUsers).SyncRoot)
{
// Check if the service's ID has already been added.
if (!_currentUsers.ContainsKey(serviceID))
{
_currentUsers[serviceID] = new List<string>();
}
// Make sure to only store the user name once for each service.
if (!_currentUsers[serviceID].Contains(userName))
{
_currentUsers[serviceID].Add(userName);
}
}
}
private void RemoveUser(Guid serviceID, string userName)
{
// Synchronize access to the collection via the SyncRoot property.
lock (((ICollection)_currentUsers).SyncRoot)
{
// Check if the service's ID has already been added.
if (_currentUsers.ContainsKey(serviceID))
{
// See if the user name exists.
if (_currentUsers[serviceID].Contains(userName))
{
_currentUsers[serviceID].Remove(userName);
}
}
}
}
}
Given that you don't want users listed twice for a specific service, it would probably make sense to replace the List<string> with HashSet<string>.
A database would seem to offer a persistent store which may be useful or important for your application. In addition it supports transactions etc which may be useful to you. Lots of updates could be a performance problem, but it depends on the exact numbers, what the query patterns are, database engine used, locality etc.
An alternative to this option might be some sort of in-memory caching server like memcached. Whilst this can be shared and accessed in a similar (sort of) way to a database server there are some caveats. Firstly, these platforms are generally not backed by some sort of permanent storage. What happens when the memcached server dies? Second they may not be ACID-compliant enough for your use. What happens under load in terms of additions and updates?
I like the in memory way. Actually I am designing a same mechanism for one my projects I'm working now. This is good for scenarios where you don't have opportunities to access database or some people are really reluctant to create a table to store simple info like a list of users against a machine name.
Only update I'd do there is a node will only return the list of its available users to its peer and peer will combine that with its existing list. Then return its existing list to the peer who called. Thats how all the peers would be in sync with same list.
The DB option sounds good. If there are no performance issues it is a simple design that should work. If you can afford to be semi realtime and non persistent one way would be to maintain the list in memory in each service and then each service updates the other when a new user joins. This can be done as some kind of broadcast via a centralised service or using msmq etc.
If you reconsider and host using IIS you will find that with a single line in a config file you can make the ASP Global, Application and Session objects available. This trick is also very handy because it means you can share session state between an ASP application and a WCF service.

NHibernate sessions - what's the common way to handle sessions in windows applications?

I've just started using NHibernate, and I have some issues that I'm unsure how to solve correctly.
I started out creating a generic repository containing CUD and a couple of search methods. Each of these methods opens a separate session (and transaction if necessary) during the DB operation(s). The problem when doing this (as far as I can tell) is that I can't take advantage of lazy loading of related collections/objects.
As almost every entity relation has .Not.LazyLoad() in the fluent mapping, it results in the entire database being loaded when I request a list of all entities of a given type.
Correct me if I'm wrong, 'cause I'm still a complete newbie when it comes to NHibernate :)
What is most common to do to avoid this? Have one global static session that remains alive as long as the program runs, or what should I do?
Some of the repository code:
public T GetById(int id)
{
using (var session = NHibernateHelper.OpenSession())
{
return session.Get<T>(id);
}
}
Using the repository to get a Person
var person = m_PersonRepository.GetById(1); // works fine
var contactInfo = person.ContactInfo; // Throws exception with message:
// failed to lazily initialize a collection, no session or session was closed
Your question actually boils down to object caching and reuse. If you load a Foo object from one session, then can you keep hold of it and then at a later point in time lazy load its Bar property?
Each ISession instance is designed to represent a unit of work, and comes with a first level cache that will allow you to retrieve an object multiple times within that unit of work yet only have a single database hit. It is not thread-safe, and should definitely not be used as a static object in a WinForms application.
If you want to use an object when the session under which it was loaded has been disposed, then you need to associate it with a new session using Session.SaveOrUpdate(object) or Session.Update(object).
You can find all of this explained in chapter 10 of the Hibernate documentation.
If this seems inefficient, then look into second-level caching. This is provided at ISessionFactory level - your session factory can be static, and if you enable second-level caching this will effectively build an in-memory cache of much of your data. Second-level caching is only appropriate if there is no underlying service updating your data - if all database updates go via NHibernate, then it is safe.
Edit in light of code posted
Your session usage is at the wrong level - you are using it for a single database get, rather than a unit of work. In this case, your GetById method should take in a session which it uses, and the session instance should be managed at a higher level. Alternatively, your PersonRepository class should manage the session if you prefer, and you should instantiate and dispose an object of this type for each unit of work.
public T GetById(int id)
{
return m_session.Get<T>(id);
}
using (var repository = new PersonRepository())
{
var person = repository.GetById(1);
var contactInfo = person.ContactInfo;
} // make sure the repository Dispose method disposes the session.
The error message you are getting is because there is no longer a session to use to lazy load the collection - you've already disposed it.