Multi-screen (i.e. multi-session) desktop application guidance

16 views
Skip to first unread message

Everett Muniz

unread,
Oct 20, 2009, 2:10:55 PM10/20/09
to nhu...@googlegroups.com
We're developing a desktop app with an MDI-like (but not real MDI) UI.  For certain screen types multiple screens can exist at the same time and each screen would need to have access to it's own distinct session.  Some situations will also require 1 screen to access sessions for 2 different databases.  There seems to be quite a bit of guidance about session/transaction management out there for web development but I've been hard pressed to find much for the kind of desktop application I described above.

If anyone can offer/point me at some information or a sample implementation along these lines it would be a huge help.  Not sure it it matters by for the sake of a bit more context I'll add that we're relying pretty heavily on DI using StructureMap.

Paulo Quicoli

unread,
Oct 20, 2009, 2:44:04 PM10/20/09
to nhu...@googlegroups.com
i have a mdi like here, but i make use of  CpBT (Conversation per Business Transaction) ..
take a look in this:
 
 
and:
 
2009/10/20 Everett Muniz <everet...@gmail.com>
We're developing a desktop app with an MDI-like (but not real MDI) UI.  For certain screen types multiple screens can exist at the same time and each screen would need to have access to it's own distinct session.  Some situations will also require 1 screen to access sessions for 2 different databases.  There seems to be quite a bit of guidance about session/transaction management out there for web development but I've been hard pressed to find much for the kind of desktop application I described above.

If anyone can offer/point me at some information or a sample implementation along these lines it would be a huge help.  Not sure it it matters by for the sake of a bit more context I'll add that we're relying pretty heavily on DI using StructureMap.


--
Paulo R. Quicoli

Editor Técnico - ClubeDelphi Magazine - DevMedia

Everett Muniz

unread,
Oct 20, 2009, 2:59:11 PM10/20/09
to nhu...@googlegroups.com
Thanks Paulo, I'll take a look.  I've looked at a few conversation per business transaction posts on Fabio's blog.  The concept resonated with me but the specific implementation seemed to hinge on things just outside our familiarity and I was looking for a better fit to our scenario.  I guess I may have to dig in and try to better grok Fabio's implementation and see if it's something that can be implemented with the bits we're using.

Germán Schuager

unread,
Oct 20, 2009, 3:05:32 PM10/20/09
to nhu...@googlegroups.com
Hi, I have a post about this topic proposing an implementation using the Castle stack.

José F. Romaniello

unread,
Oct 20, 2009, 3:11:57 PM10/20/09
to nhu...@googlegroups.com
I've an example for WPF, "The Chinook Media Manager"  also, 
BTW cool name don't you think?

It use the same CpBT, as Paulo says. Look the posts in the nhusers group.
The code is in unhaddins.

2009/10/20 Germán Schuager <gsch...@gmail.com>

Everett Muniz

unread,
Oct 20, 2009, 3:46:30 PM10/20/09
to nhu...@googlegroups.com
thanks Germán!  As a matter of fact I was actually looking through your code earlier today.  Thanks for making it available.  I actually had a question about it now that you mention it ;-)

In the UI project the ProductAdminModel has constructor dependencies on the unit of work, and the repository like so...

public ProductAdminModel(IUnitOfWork unitOfWork, IProductRepository productRepository)

If I was understanding the code correctly the ISession is held by the implementations of both of these interfaces.  Is that correct?

Everett Muniz

unread,
Oct 20, 2009, 3:47:44 PM10/20/09
to nhu...@googlegroups.com
Thanks José, I'll add your implementation to the list of work I'm going to be reviewing.

José F. Romaniello

unread,
Oct 20, 2009, 3:52:02 PM10/20/09
to nhu...@googlegroups.com
Paulo and I, were talking about the same implementation, unhaddins.. 
Chinook Media Manager is just an example that use CpBT and other things like pluggin observables collections and NotifyPropertyChanged behavior to entities.


2009/10/20 Everett Muniz <everet...@gmail.com>

Everett Muniz

unread,
Oct 20, 2009, 4:04:20 PM10/20/09
to nhu...@googlegroups.com
Ah, I see, I'm a bit slow on the up-take this afternoon.  Thanks again!

Germán Schuager

unread,
Oct 20, 2009, 4:42:43 PM10/20/09
to nhu...@googlegroups.com
Actually, the ISession is held by the Castle NHibernate facility and I just retrieve it by doing ISessionManager.OpenSession().

As a side note, if are not already using this stack then probably it would make more sense to go for a more generic approach like the one that Paulo and José are pointing you to.

Everett Muniz

unread,
Oct 20, 2009, 5:19:15 PM10/20/09
to nhu...@googlegroups.com
Thanks for the clarification Germán.  I should have been more precise.  I guess what I really meant to ask was, are both the unit of work and the repository in your example working with the same session instance?

I think your advice makes a lot of sense.  I get the essentials of CpBT conceptually -- I think I even get the what a basic implementation looks like based on my reading of the code Paulo pointed me to here: http://fabiomaulo.blogspot.com/2009/09/nhibernate-in-winform-coupled.html.

I'm revisiting some of Fabio's other posts to try to better understand how to implement the concept in the context of our requirements and the tools we're using (i.e. StructureMap et al).

Germán Schuager

unread,
Oct 20, 2009, 5:41:20 PM10/20/09
to nhu...@googlegroups.com
They are working with the same instance of ISessionManager.... then if you do this:

using (unitOfWork.Start())   <----- calls ISessionManager.OpenSession()
{
     productRepository.GetSomething();     <----- calls ISessionManager.OpenSession()
}

both calls to OpenSession will return the same session instance.

But if you do this:

productRepository.GetSomething();
productRepository.GetOtherThing();

without opening a session in an outher scope then you will actually have 2 different sessions.

Everett Muniz

unread,
Oct 20, 2009, 5:55:49 PM10/20/09
to nhu...@googlegroups.com
Ok, that's helpful, thanks again!

Jason Meckley

unread,
Oct 21, 2009, 8:14:45 AM10/21/09
to nhusers
Another approach, pair a service bus with an UI event aggregator. the
service bus would take care of all the NH work while the aggregator
notifies the UI of replies from the service bus.

Jeremy Miller's StoryTeller code base has a UI aggregator model. Since
you are already using StructureMap porting the applicable code should
be easy. Then comes the service bus. My experience is with RSB which
depends on Castle. However, MassTransit and NServiceBus are IoC
agnostic so on of these would work for your architecture. The service
bus would have a hook some where where you can extend functionality
before/after a message is processed. with RSB This can be done with a
IMessageModule.

the idea is that when a message is received open a new session, when a
message is completed dispose of the session. Using one of the various
ICurrentSessionContext implementations provided with NHibernate you
can access the current session without a need for Castle's NH
facility.

with this approach the UI knows nothing about NH. a button click or
form load would send a message using the service bus. the service bus
would process the message and send a reply. A UI consumer/handler
would process the reply and load the response into the event
aggregator. the event aggregator would then publish events to the UI
elements and they would get updated.

initially configuring the architecture will take some time, especially
if you haven't used these concepts before. but once it's up and
running it very simple to extend functionality.

On Oct 20, 5:55 pm, Everett Muniz <everettmu...@gmail.com> wrote:
> Ok, that's helpful, thanks again!
>
> On Tue, Oct 20, 2009 at 5:41 PM, Germán Schuager <gschua...@gmail.com>wrote:
>
> > They are working with the same instance of ISessionManager.... then if you
> > do this:
> > using (unitOfWork.Start())   <----- calls ISessionManager.OpenSession()
> > {
> >      productRepository.GetSomething();     <----- calls
> > ISessionManager.OpenSession()
> > }
>
> > both calls to OpenSession will return the same session instance.
>
> > But if you do this:
>
> > productRepository.GetSomething();
> > productRepository.GetOtherThing();
>
> > without opening a session in an outher scope then you will actually have 2
> > different sessions.
>

Germán Schuager

unread,
Oct 21, 2009, 8:25:20 AM10/21/09
to nhu...@googlegroups.com
Hi, I have a couple of questions:
- What kind of objects do you send to the UI? business objects or DTOs?
- If you send business objects... how do you handle lazy loading?

Everett Muniz

unread,
Oct 21, 2009, 8:43:39 AM10/21/09
to nhu...@googlegroups.com
Jason, thanks for taking the time to flesh out that approach!  I've actually been spelunking in StoryTeller just in the last week.  I've even spiked the core bits of Jeremy's approach for our situation and I like what I'm seeing.  I'm still struggling a bit to map the function pieces to the names Jeremy has chosen but until I grok it a bit better I'm sticking with what's represented in the code base.

I don't have any experience with implementing one of the service bus implementations you mention but that's not necessarily a deal breaker.  I spent some time with the non-aop conversation example from the unhAddins project last night and there are several "moving parts" to the CpBT implementation.  I guess my point is that I'm looking at a learning curve regardless of the direction we choose.  I'd prefer not to have to get quite so intimate with NHibernate as the CpBT implementation seems to require but it may be unavoidable.

Can you point me at any solid reference implementations of the kind of architecture you're describing?  I mean something that's using the service bus concept.

José F. Romaniello

unread,
Oct 21, 2009, 8:56:02 AM10/21/09
to nhu...@googlegroups.com
Did you see the nhibernate session handling in this class (from the chinook sample):


Checkout the AOP way, it is really a "Manna from heaven".

2009/10/21 Everett Muniz <everet...@gmail.com>

Everett Muniz

unread,
Oct 21, 2009, 8:57:46 AM10/21/09
to nhu...@googlegroups.com
:-) with that kind of recommendation I'll be sure to check it out

Jason Meckley

unread,
Oct 21, 2009, 9:39:13 AM10/21/09
to nhusers
with the service bus/event aggregator model you would pass DTOs to the
View/UI. This is also called the View Model. Each screen has it's own
set of DTO's. mapping the Domain model to the View Model can be
accomplished with a framework like AutoMapper.

Unfortunately I haven't found a spike for a full blown service bus/
event aggregator. StoryTeller has all the moving parts for the event
aggregator. There are many pieces on the web about how to handle
messaging. with RSB it would look something like this

within a presenter you would send the message
bus.Send(new MyMessage {[properties]});

then you would have a consumer to process that message. here is a
basic example utilizing AutoMapper

class MyMessageConsumer : ConsumerOf<MyMessage>
{
public class MyMessageConsumer(ISession session, IMappingEngine
mapper, IServiceBus bus) {...}

public void Consume(MyMessage message)
{
var entity = session.Get<Entity>(message.Id);
var dto = mapper.Map<Entity, DTO>(entity);
bus.Reply(new MyResponse{ Data = dto});
}
}

the reply is sent back to the source, in this case our rich client.
where MyResponse will be processed


class MyResponseConsumer : ConsumerOf<MyResponse>
{
public class MyResponseConsumer(IEventAggregator aggregator) {...}

public void Consume(MyResponse message)
{
aggregator.Handle(message.Dto);
}
}

this is where the EventAggregator takes over. It would know that it's
consuming a type of DTO and notify all the instantiated presenters to
update their view.
All of this is happening in background threads, so the event
aggregator uses a SynchronizationContext to allow the UI to update on
the main thread. That is easy enough to follow from StoryTellers code
base.

I know with Rhino (and I believe for the other service buses)
consumers/handlers are transient (or not singletons). Using the IoC of
you choice you can inject the current session into the consumer.

now this is the simplest example. You can also get into scenarios
where the consumers are Sagas. A Saga coordinates multiple
asynchronous events. Ayende and Udi have some posts about this Sagas.

as for managing the session here is how I manage it with
Rhino.ServiceBus. again I believe there is a concept of IMessageModule
in all the service bus frameworks. I'm just not aware of there name.
namespace StockBook.Core.Infrastructure.Messaging
{
public class NhibernateMessageModule : IMessageModule
{
private readonly ISessionFactory Factory;

public NhibernateMessageModule(ISessionFactory factory)
{
Factory = factory;
}

public void Init(ITransport transport)
{
transport.MessageArrived += OpenSession;
transport.MessageProcessingCompleted += CloseSession;
}

public void Stop(ITransport transport)
{
transport.MessageArrived -= OpenSession;
transport.MessageProcessingCompleted -= CloseSession;
}

private bool OpenSession(CurrentMessageInformation arg)
{
CurrentSessionContext.Bind(Factory.OpenSession());
return false;
}

private void CloseSession(CurrentMessageInformation arg1,
Exception arg2)
{
var session = CurrentSessionContext.Unbind(Factory);
if (session == null) return;
session.Dispose();
}
}
}
the CurrentSessionContext singleton is part of core NHibernate, no
need for NH Addins. the common contexts are WebSessionContext,
ThreadStaticSessionContext and MappedSessionContext. web is self
explaintory:) ThreadStatic is meant for use with a single
SessionFactory. If you have more than 1 session factory the Mapped
context will track which session belongs to which factory. This
requires that each Factory has a name.

my NH configuration looks like this
namespace StockBook.Core.Infrastructure.Facility
{
public class NhibernateForServiceFacility : AbstractFacility
{
protected override void Init()
{
var configuration = Fluently
.Configure()
.Database(MsSqlConfiguration
.MsSql2000
.AdoNetBatchSize(20)
.ProxyFactoryFactory(typeof
(ProxyFactoryFactory).AssemblyQualifiedName)
.ConnectionString(builder =>
builder.FromConnectionStringWithKey("StockBook")))
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<Category>())
.ExposeConfiguration(cfg => cfg
.SetProperty
(Environment.PrepareSql, true.ToString())
.SetProperty
(Environment.CurrentSessionContextClass, typeof
(ThreadStaticSessionContext).AssemblyQualifiedName))
.BuildConfiguration();
var factory = configuration.BuildSessionFactory();

Kernel.AddComponentInstance<Configuration>(configuration);
Kernel.AddComponentInstance<ISessionFactory>(factory);
Kernel.Register(Component
.For<ISession>()
.LifeStyle.Is(LifestyleType.Transient)
.UsingFactoryMethod(k =>
k.Resolve<ISessionFactory>().GetCurrentSession()));
}
}
}
this uses Castle Windsor, so the symantics would be different for your
container of choice. I'm using Fluent NH to build the configuration.
The key features are Defining the CurrentSessionContext. I'm using
Castle's factory facility to resolve the current session.

in the end you will end up with *many* small classes a ViewModel with
a unique POCO for each view. A message for each action. A consumer/
saga for the message. A handler for each published UI event from the
UI aggregator.

On Oct 21, 8:57 am, Everett Muniz <everettmu...@gmail.com> wrote:
> :-) with that kind of recommendation I'll be sure to check it out
>
> On Wed, Oct 21, 2009 at 8:56 AM, José F. Romaniello <
>
> joseromanie...@gmail.com> wrote:
> > Did you see the nhibernate session handling in this class (from the chinook
> > sample):
>
> >http://code.google.com/p/unhaddins/source/browse/trunk/Examples/uNHAd...
>
> > <http://code.google.com/p/unhaddins/source/browse/trunk/Examples/uNHAd...>Checkout
> > the AOP way, it is really a "Manna from heaven".
>
> > 2009/10/21 Everett Muniz <everettmu...@gmail.com>
>
> > Jason, thanks for taking the time to flesh out that approach!  I've
> >> actually been spelunking in StoryTeller just in the last week.  I've even
> >> spiked the core bits of Jeremy's approach for our situation and I like what
> >> I'm seeing.  I'm still struggling a bit to map the function pieces to the
> >> names Jeremy has chosen but until I grok it a bit better I'm sticking with
> >> what's represented in the code base.
> >> I don't have any experience with implementing one of the service bus
> >> implementations you mention but that's not necessarily a deal breaker.  I
> >> spent some time with the non-aop conversation example from the unhAddins
> >> project last night and there are several "moving parts" to the CpBT
> >> implementation.  I guess my point is that I'm looking at a learning curve
> >> regardless of the direction we choose.  I'd prefer not to have to get quite
> >> so intimate with NHibernate as the CpBT implementation seems to require but
> >> it may be unavoidable.
>
> >> Can you point me at any solid reference implementations of the kind of
> >> architecture you're describing?  I mean something that's using the service
> >> bus concept.
>

Everett Muniz

unread,
Oct 21, 2009, 11:31:05 AM10/21/09
to nhu...@googlegroups.com
Jason, that's _really_ helpful.  I appreciate you taking the time to develop your suggestion further.  I'm using Fluent NHibernate and AutoMapper as well and StructureMap has registries which seem like they may map to Castle facilities.  So, your code has a familiar feel to it.  

I was wondering if you could elaborate on something a bit further.  Does the service bus process the messages in some sort of  queue such that messages from different screens wouldn't be processed concurrently?  I ask because I don't see anything in your code or in the CurrentSessionContext implementation (via Reflector) that would prevent 2 consumers running concurrently from accessing the same session.  Just b/c I don't see it doesn't mean it's not there.  It may just be my ignorance of the approach.

Jason Meckley

unread,
Oct 21, 2009, 3:26:57 PM10/21/09
to nhusers
Service Buses rely on a messaging queue. the 3 I mentioned use MSMQ.
RSB also has an implementation for Rhino.Queues. consuming a message
is an autonomous action. it happens independent of anything else,
similar to a http request. I know RSB, and I'm pretty sure the other
2) process messages on unique threads.

the session context implementations will not share sessions. I know
threadstaticcurrentsessioncontext is just that. I believe
mappedcurrentsessioncontext uses a thread static dictionary to map a
key to specific sessions. I have used both and haven't encountered any
problems yet.

this is also the reason why the EventAggregator uses a Sync. Context
to marshal updates back to the UI.

On Oct 21, 11:31 am, Everett Muniz <everettmu...@gmail.com> wrote:
> Jason, that's _really_ helpful.  I appreciate you taking the time to develop
> your suggestion further.  I'm using Fluent NHibernate and AutoMapper as well
> and StructureMap has registries which seem like they may map to
> Castle facilities.  So, your code has a familiar feel to it.
>
> I was wondering if you could elaborate on something a bit further.  Does the
> service bus process the messages in some sort of  queue such that messages
> from different screens wouldn't be processed concurrently?  I ask because I
> don't see anything in your code or in the CurrentSessionContext
> implementation (via Reflector) that would prevent 2 consumers
> running concurrently from accessing the same session.  Just b/c I don't see
> it doesn't mean it's not there.  It may just be my ignorance of the
> approach.
>
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages