Interception and InjectionFactory

Aug 27, 2010 at 5:23 PM
Edited Aug 27, 2010 at 5:37 PM

when i saw another post with pretty much the same title, i thought my question had already been asked, but alas, it was not the same.

i am using an injection factory because i want to have all the the dependencies for a single interface in the chain for a given class i resolve from my container return the same instance.  in other words, for a given instance of a service, i want to use the same instance of a particular dependency all the way down the dependency chain of the service, in which there may be multiple classes dependent on this same dependency.  i also want to use interception on the methods of this service.  i have accomplished this and i think this is a pretty good way to do it (if this belief is flawed, i'd be open to suggestions):

 

			_container = new UnityContainer();
			_container.AddNewExtension<Interception>();
			_container.RegisterType<IDependency1, Dependency1>();
			_container.RegisterType<IDependency2, Dependency2>();
			_container.RegisterType<IService>(new Interceptor<InterfaceInterceptor>(),
											  new InterceptionBehavior<ServiceInterceptionBehavior>(),
			                                  new InjectionFactory(
			                                  	c =>
			                                  	c.Resolve<Service>(
			                                  		new DependencyOverride<IDependency2>(c.Resolve<IDependency2>()))));

 

this works as i expect.

but i also want my interception behavior instance to have access to the same instance of the dependency.  this is where i am getting stuck and can't seem to figure out any way to do this.

here is the full test fixture code that (hopefully) conveys what i am trying to do.  please forgive the static variable hack to gain access to my interception behavior instance in the test.  any suggestion on how i might accomplish this would be appreciated.

 

using System;
using System.Collections.Generic;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using NBehave.Spec.NUnit;
using NUnit.Framework;

namespace UnityTests
{
	[TestFixture]
	public class InterceptionTest
	{
		private IUnityContainer _container;
		private IService _serviceInstance;
		public static ServiceInterceptionBehavior Interceptor { get; set; }

		[TestFixtureSetUp]
		public void ContainerSetup()
		{
			_container = new UnityContainer();
			_container.AddNewExtension<Interception>();
			_container.RegisterType<IDependency1, Dependency1>();
			_container.RegisterType<IDependency2, Dependency2>();
			_container.RegisterType<IService>(new Interceptor<InterfaceInterceptor>(),
							new InterceptionBehavior<ServiceInterceptionBehavior>(),
			                                  new InjectionFactory(
			                                  	c =>
			                                  	c.Resolve<Service>(
			                                  		new DependencyOverride<IDependency2>(c.Resolve<IDependency2>()))));
			_serviceInstance = _container.Resolve<IService>();
			_serviceInstance.SampleMethod();
		}

		[Test]
		public void Service_and_dependency1_should_get_same_instance_of_dependency2()
		{
			_serviceInstance.Dependency2.ShouldEqual(_serviceInstance.Dependency1.Dependency2);
		}

		[Test]
		public void Service_and_interceptor_should_get_same_instance_of_dependency2()
		{
			_serviceInstance.Dependency2.ShouldEqual(Interceptor.Dependency2);
		}
	}

	public interface IService
	{
		IDependency1 Dependency1 { get; }
		IDependency2 Dependency2 { get; }
		void SampleMethod();
	}

	public class Service : IService
	{
		public IDependency1 Dependency1 { get; set; }
		public IDependency2 Dependency2 { get; set; }
		public void SampleMethod() { }

		public Service(IDependency1 dependency1, IDependency2 dependency2)
		{
			Dependency1 = dependency1;
			Dependency2 = dependency2;
		}
	}

	public interface IDependency1
	{
		IDependency2 Dependency2 { get; }
	}

	public interface IDependency2 { }

	public class Dependency1 : IDependency1
	{
		public IDependency2 Dependency2 { get; set; }

		public Dependency1(IDependency2 dependency2)
		{
			Dependency2 = dependency2;
		}
	}

	public class Dependency2 : IDependency2 { }

	public class ServiceInterceptionBehavior : IInterceptionBehavior
	{
		public IDependency2 Dependency2 { get; set; }

		public ServiceInterceptionBehavior(IDependency2 dependency2)
		{
			Dependency2 = dependency2;
		}

		public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
		{
			InterceptionTest.Interceptor = this;
			return getNext()(input, getNext);
		}

		public IEnumerable GetRequiredInterfaces()
		{
			return Type.EmptyTypes;
		}

		public bool WillExecute
		{
			get { return true; }
		}
	}
}

 

Aug 27, 2010 at 8:50 PM

Why not use the PerResolveLifetimeManager for Dependency2? Won't that accomplish the same thing you're trying to do?

 

Aug 27, 2010 at 9:32 PM

wow.  yes, it does.  brilliant.  i didn't know about that one.  thanks very much for the simple and effective answer to a longwinded question.

Aug 27, 2010 at 9:51 PM

That's why they pay me the moderately sized bucks. :-)

Glad it helped.

-Chris