InCustomScope(), scoping services to application areas

121 views
Skip to first unread message

Tom R

unread,
Dec 30, 2011, 6:45:07 AM12/30/11
to ninject
Hi All,

We are building a WPF application using Ninject, we have a requirement
that we can scope our EventAggregator/MessageBus services to specific
parts of the application e.g. each window might want its own
aggregator so it only gets relevant messages. If we were using Unity
then this would simply be a case of using a ChildContainer and
overriding the binding for IEventAggregator, unfortunately Ninject's
ChildKernel isn't equivalent as a child's bindings won't override the
binding in the parent when a service is resolved by the parent kernel.

I've been working with scopes to see if I can achieve the required
effect and came up with the following:

var kernel = new StandardKernel();

kernel.Bind<IEventAggregator>()To<EventAggregator>().InCustomScope();

var eventAgg0 = kernel.Get<IEventAggregator>();

IResolutionRoot scope1 = new CustomScope(kernel);
var eventAgg1 = scope1.Get<IEventAggregator>();

IResolutionRoot scope2 = new CustomScope(kernel);
var eventAgg2 = scope2.Get<IEventAggregator>();

Assert.That(eventAgg0, Is.Not.SameAs(eventAgg1))
Assert.That(eventAgg0, Is.Not.SameAs(eventAgg2))
Assert.That(eventAgg1, Is.Not.SameAs(eventAgg2))

The scope is passed on the request as an inherited Parameter so newly
instantiated dependencies will also inherit the same instance.

var eventAgg0 = kernel.Get<IEventAggregator>();

IResolutionRoot scope1 = new CustomScope(kernel);
var windowVM = scope1.Get<IWindowViewModel>();

Assert.That(windowVM.EventAggregator, Is.Not.SameAs(eventAgg0))
Assert.That(windowVM.Child.EventAggregator,
Is.Not.SameAs(eventAgg0))
Assert.That(windowVM.EventAggregator,
Is.SameAs(windowVM.Child.EventAggregator))

If IResolutionRoot is also bound as follows then a CustomScope will
inject itself allowing services to be resolved later in the same
scope.


kernel.Bind<IResolutionRoot>().ToMethod(CustomScope.ResolutionRootFromRequest);

IResolutionRoot scope1 = new CustomScope(kernel);
var windowVM = scope1.Get<IWindowViewModel>();

Assert.That(windowVM.EventAggregator,

Is.SameAs(windowVM.ResolutionRoot.Get<IEventAggregator>()))

Code is here:
https://github.com/chillitom/CustomScope/blob/master/CustomScope.cs
https://github.com/chillitom/CustomScope/blob/master/CustomScopeTests.cs
https://github.com/chillitom/CustomScope/blob/master/BindingExtensions.cs

- What does the Ninject community think of this approach?
- Are there any serious issues or shortcomings?
- Can this be achieved more easily in another way?
- If this is useful, could it be named better? Any suggestions?

Thanks,

Tom.

Remo Gloor

unread,
May 18, 2012, 10:42:05 AM5/18/12
to nin...@googlegroups.com
Hi Tom

I expect that the objects will never be GCd resulting in a memory leak. I haven't checked though.

You can do this quite simply using a named scope by declaring that your VM is the scope for your event aggregator.

Remo

Tom R

unread,
May 28, 2012, 9:51:34 AM5/28/12
to nin...@googlegroups.com
Thanks Remo, good spot - You were right it was leaking.

Making the scope parameter hold a weak reference fixes the leak.

        class ScopeParameter : Parameter
        {
            private readonly WeakReference _scope;
            public IResolutionRoot Scope { get { return _scope.Target as IResolutionRoot; } }

            public ScopeParameter(IResolutionRoot scope) 
                : base("£$%^", (c,t) => null, true)
            {
                _scope = new WeakReference(scope);
            }
        }

I still think this technique has merit as it allows objects to be scoped at request time.  We currently have many situations where the named binding approach wouldn't work or would require dozens of WhenInjectedInto directives.

Remo Gloor

unread,
May 29, 2012, 3:16:20 AM5/29/12
to nin...@googlegroups.com

I don’t see any difference between your approach and the NamedScope except that you don’t need to create the CustomScope

 

So instead of

 

  IResolutionRoot scope1 = new CustomScope(kernel);
  var windowVM = scope1.Get<IWindowViewModel>();

 

You write

 

  var windowVM = kernel.Get<IWindowViewModel>();  

 

Thus you are able to use a view model factory and get rid of any IoC container references in your code. Making it a much better approach.

--
You received this message because you are subscribed to the Google Groups "ninject" group.
To view this discussion on the web visit https://groups.google.com/d/msg/ninject/-/NRe_g41Aqv4J.
To post to this group, send email to nin...@googlegroups.com.
To unsubscribe from this group, send email to
ninject+u...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/ninject?hl=en.

Reply all
Reply to author
Forward
0 new messages