Instance per matching lifetime scope, with default? - c#

I'd like to have an instance per matching lifetime scoped registration in Autofac, but occasionally need to request an instance from a global container (where there is no matching lifetime scope). In scenarios where no matching lifetime scope exists, I want to give a top-level instance instead of throwing an exception.
Is this possible?

I think you'd better extend Autofac by introducing a new lifetime option. I took the Autofac sources and modified them a bit:
public static class RegistrationBuilderExtensions
{
public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InstancePerMatchingOrRootLifetimeScope<TLimit, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> builder, params object[] lifetimeScopeTag)
{
if (lifetimeScopeTag == null) throw new ArgumentNullException("lifetimeScopeTag");
builder.RegistrationData.Sharing = InstanceSharing.Shared;
builder.RegistrationData.Lifetime = new MatchingScopeOrRootLifetime(lifetimeScopeTag);
return builder;
}
}
public class MatchingScopeOrRootLifetime: IComponentLifetime
{
readonly object[] _tagsToMatch;
public MatchingScopeOrRootLifetime(params object[] lifetimeScopeTagsToMatch)
{
if (lifetimeScopeTagsToMatch == null) throw new ArgumentNullException("lifetimeScopeTagsToMatch");
_tagsToMatch = lifetimeScopeTagsToMatch;
}
public ISharingLifetimeScope FindScope(ISharingLifetimeScope mostNestedVisibleScope)
{
if (mostNestedVisibleScope == null) throw new ArgumentNullException("mostNestedVisibleScope");
var next = mostNestedVisibleScope;
while (next != null)
{
if (_tagsToMatch.Contains(next.Tag))
return next;
next = next.ParentLifetimeScope;
}
return mostNestedVisibleScope.RootLifetimeScope;
}
}
Just add these classes to your project and register you component as:
builder.RegisterType<A>.InstancePerMatchingOrRootLifetimeScope("TAG");
I haven't tried it myself, but it should work.

Possible solution is to override registration in child lifetime scope.
Sample:
public enum Scopes
{
TestScope
}
public class Test
{
public string Description { get; set; }
}
public class Tester
{
public void DoTest()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Test>()
.OnActivating(args => args.Instance.Description = "FromRoot")
.SingleInstance();
var container = builder.Build();
var scope = container.BeginLifetimeScope(Scopes.TestScope, b => b
.RegisterType<Test>()
.InstancePerMatchingLifetimeScope(Scopes.TestScope)
.OnActivating(args => args.Instance.Description = "FromScope"));
var test1 = container.Resolve<Test>();
Console.WriteLine(test1.Description); //writes FromRoot
var test2 = scope.Resolve<Test>();
Console.WriteLine(test2.Description); //writes FromScope
Console.ReadLine();
}
}

The root container itself is a lifetime scope with the tag name: root, defined in LifetimeScope.RootTag
So you can just do:
using Autofac.Core.Lifetime;
builder.RegisterType<Service>().As<IService>()
.InstancePerMatchingLifetimeScope(LifetimeScope.RootTag, "foobar");

Related

How to make the ActivatorUtilities.CreateInstance method use a different constructor?

Is there a way the tell the ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider); method to try to use other constructors if the first one can't be constructed?
I have a class with multiple constructors:
public ViewModelB(SomeDependency someDependency): this one only takes SomeDependency which is registered in a DI container
public ViewModelB(SomeDependency someDependency, GetUserRequest request): this one takes SomeDependency which is registered in a DI container and a GetUserRequest which has to be passed in manually
And I'm trying to activate them and resolve dependencies like so:
IServiceProvider serviceProvider; //this gets passed from somewhere
Guid userId; //this gets passed manually by the caller
//works
var instanceAWithoutParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider);
//works
var instanceAWithParams = ActivatorUtilities.CreateInstance<ViewModelA>(serviceProvider, new[] { new GetUserRequest { UserId = userId } });
//does NOT work, it tries to use the first constructor and fails
var instanceBWithoutParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider);
//works
var instanceBWithParams = ActivatorUtilities.CreateInstance<ViewModelB>(serviceProvider,, new[] { new GetUserRequest { UserId = userId } });
The activation of instanceBWithoutParams fails because it can't resolve the request parameter. It tries to use the first constructor and doesn't check other ones when the activation fails.
Here's what the services look like, they're the same with one difference: the order of the constructors.
public class ViewModelA
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelA(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public ViewModelA(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
}
public class ViewModelB
{
private readonly SomeDependency _someDependency;
private readonly GetUserRequest? _request;
public ViewModelB(SomeDependency someDependency, GetUserRequest request)
{
_someDependency = someDependency;
_request = request;
}
public ViewModelB(SomeDependency someDependency)
{
_someDependency = someDependency;
}
}
public class GetUserRequest
{
public Guid UserId { get; set; }
}
Thanks.
I struggled with the same issue. Eventually I came up with this solution:
I would use something like a factory which is able to construct ServiceB by calling a method.
For example:
var serviceBFactory = ActivatorUtilities.CreateInstance<ServiceBFactory>(serviceProvider);
var instanceBWithoutParams = serviceBFactory.CreateServiceB();
var instanceBWithParams = serviceBFactory.CreateServiceB(new Request());
This way you keep you DI clean. But this means that the ServiceBFactory need to know which services need to be injected in a ServiceB. (so that will be a tight coupling) They come as a package.
I've chosen to re-design the view models instead of trying to pass optional parameters next to services from DI (thanks to Steven for the helpful articles: 1 and 2).
There also seems to be no way of making the ActivatorUtilities.CreateInstance<T>(IServiceProvider serviceProvider); method try other constructors after one fails, so here's what my edited solution looks like.
I've moved the initialization of the optional parameter out of the constructor, that way I only have one constructor that only takes injectables. The parameter is then passed separately via the TakeParameter method. The only downside I can think of is that the parameter can no longer be readonly and I can live with that.
My custom activator utility:
public interface IAcceptParameter<T>
{
void TakeParameter(T parameter);
}
public static class CustomActivator
{
public static T CreateInstance<T>()
{
return ActivatorUtilities.CreateInstance<T>(_serviceProvider);
}
public static T CreateInstanceWithParam<T, K>(K parameter) where T : IAcceptParameter<K>
{
var instance = ActivatorUtilities.CreateInstance<T>(_serviceProvider);
instance.TakeParameter(parameter);
return instance;
}
}
Changed view model
public class SomeViewModel : IAcceptParameter<Guid>
{
private readonly SomeDependency _someDependency;
private Guid? _userId;
public SomeViewModel(SomeDependency someDependency)
{
_someDependency = someDependency;
}
public void TakeParameter(Guid parameter){
_userId = parameter;
}
}
How I use it
var instanceWithoutParam = CustomActivator.CreateInstance<SomeViewModel>(serviceProvider);
Guid userId;
var instanceWithParam = CustomActivator.CreateInstanceWithParam<SomeViewModel, Guid>(serviceProvider, userId);
Let say you have a class like this:
public class a
{
public string p { get; set; }
public a()
{
p = "default constructor";
}
public a(string pv)
{
p = pv;
}
}
You can use .GetConstructor method to use a specific constructor:
public class Program
{
static void Main(string[] args)
{
var c = typeof(a).GetConstructor(new Type[] { typeof(string) });
if (c != null)
{
var myA = (a)c.Invoke(new object[] { "new value" });
Console.WriteLine($"Value of p is {myA.p}");
}
}
}

AutoFac NamedParameter not resolving correctly

Im messing round in autofac and im having some issues binding to a specific constructor.
I have the following code:
var builder = new ContainerBuilder();
builder
.RegisterType<GenericIocFactory>()
.As<IGenericIocFactory>();
builder
.RegisterType<Product>()
.As<IProduct>()
.PropertiesAutowired();
IContainer Container = builder.Build();
IGenericIocFactory Fac = Container.Resolve<IGenericIocFactory>();
_product = Fac.Get<IProduct>(new Dictionary<string,object>() { {"returnEmpty" , false} }) as Product;
Then in the factory:
public interface IGenericIocFactory
{
T Get<T>(Dictionary<string,object> options) where T: class;
}
public class GenericIocFactory : IGenericIocFactory
{
private readonly IComponentContext _icoContext;
private object _options;
public GenericIocFactory(IComponentContext icoContext,bool isInjected = true)
{
_icoContext= icoContext;
}
public T Get<T>(Dictionary<string,object> options) where T: class
{
var _parameters = new List<Parameter>();
foreach (var parameter in options)
{
_parameters.Add(new NamedParameter(parameter.Key, parameter.Value));
}
return _icoContext.Resolve<T>(_parameters);
//operate on new object
// tried this as well
//return _icoContext.Resolve<T>(
//new NamedParameter("returnEmpty" , false)
//new TypedParameter(typeof(bool),false)
//);
}
}
This resolves a product but not with the constructor i expect.
Target constructor
public Product(bool returnEmpty)
Resolving constructor
public Product(IList<string> productCodes, string fields = "", string orderBy = "ProductCode")
There is a total of 23 constructors and the one resolving is not the biggest(so i don't think its being greedy)
ie
public Product(string strFields, string strFrom, string strFilter, string strOrderBy, string whseCode,
bool addExistsInWharehouse, string additionalAfterorderBy, bool forceUniqueRecords = false)
Nor is it the first or last in or of definition.
Im stumped can anyone see what im doing wrong.
Unfortunately Autofac doesn't provide this mechanism.
You could have implemented IConstructorSelector which select a constructor when more than one constructor is available and set it to the registration by using the UsingSelector method but unfortunately there is no way to access the available parameters of the current resolve operation.
Another solution would be to implement IInstanceActivator which is responsible of creating the instance based on the type and parameters. to use a custom IInstanceActivator you also need to implement IRegistrationBuilder which is quite difficult. To guarantee good performance, I would also recommend the use of ConstructorParameterBinding which will create an optimized factory using dynamic compiled expression.
If you can't change your constructor, the only solution I can see is to implement your own factory. Because your object don't have any dependencies, you can create them without using Autofac.
public class GenericIocFactory : IGenericIocFactory
{
public GenericIocFactory(ILifetimeScope scope)
{
this._scope = scope;
}
private readonly ILifetimeScope _scope;
public T Get<T>(params object[] args) where T: class
{
ConstructorInfo ci = this.GetConstructorInfo(args);
if (ci == null)
{
throw ...
}
var binder = new ConstructorParameterBinding(ci, args, this._scope);
T value = binder.Instanciate() as T;
if (value == null)
{
throw ...
}
if(value is IDisposable)
{
this._scope.Disposer.AddInstanceForDisposal(value);
}
return value;
}
protected virtual ConstructorInfo GetConstructorInfo<T>(params object[] args)
{
// TODO
}
}
So having read up again on the doco. I needed to bind the constructor at the start. But this wont fix my problem so I made another container ever single time an instance is requested and construct it based on the params. Its a little bit incorrect but this is a real world solution to anyone who is transitioning to autofac for a very large existing solution.
Hope this helps someone.
public interface IGenericIocFactory
{
T Get<T>(params object[] constructorParams) where T: class;
}
public interface ICustomAutoFacContainer
{
IContainer BindAndReturnCustom<T>(IComponentContext context, Type[] paramsList);
}
public class CustomAutoFacContainer : ICustomAutoFacContainer
{
public IContainer BindAndReturnCustom<T>(IComponentContext context, Type[] paramsList)
{
if (context.IsRegistered<T>())
{
// Get the current DI binding type target
var targetType = context
.ComponentRegistry
.Registrations
.First(r => ((TypedService) r.Services.First()).ServiceType == typeof(T))
.Target
.Activator
.LimitType;
// todo: exception handling and what not .targetType
var builder = new ContainerBuilder();
builder
.RegisterType(targetType)
.As<T>()
.UsingConstructor(paramsList)
.PropertiesAutowired();
return builder.Build();
}
return null;
}
}
public class GenericIocFactory : IGenericIocFactory
{
private ICustomAutoFacContainer _iCustomContainer;
private readonly IComponentContext _icoContext;
public GenericIocFactory(ICustomAutoFacContainer iCustomContainer, IComponentContext icoContext)
{
_iCustomContainer = iCustomContainer;
_icoContext = icoContext;
}
public T Get<T>(params object[] constructorParams) where T: class
{
//TODO handle reflection generation? ?? ?not needed?? ??
var parameters = constructorParams
.Select((t, index) => new PositionalParameter(index, t))
.Cast<Parameter>()
.ToList();
var parameterTypes = constructorParams
.Select((t, index) => t.GetType())
.ToArray();
return _iCustomContainer
.BindAndReturnCustom<T>(_icoContext,parameterTypes)
.Resolve<T>(parameters);
}
}
Setup and usage looks something like this:
var builder = new ContainerBuilder();
// Usually you're only interested in exposing the type
// via its interface:
builder
.RegisterType<GenericIocFactory>()
.As<IGenericIocFactory>();
builder
.RegisterType<CustomAutoFacContainer>()
.As<ICustomAutoFacContainer>();
builder
.RegisterType<Product>()
.As<IProduct>()
.PropertiesAutowired();
var container = builder.Build();
var factory = container.Resolve<IGenericIocFactory>();
_product = factory.Get<IProduct>(false) as Product;
_product = factory.Get<IProduct>("","") as Product;

View Unity Dependency Configuration in .NET

We have a lot of registrations within out Unity Container. About 800 lines long in fact.
As Unity does not have a validate method, we introduced a Unit Test to verify the configuration before we test the application which looks like something as follows which works very well and has picked up lots of issues within the configuration:
IUnityContainer container = UnityContainerBuilder.Build();
foreach (ContainerRegistration mapping in container.Registrations)
{
container.Resolve(mapping.RegisteredType, mapping.Name);
}
However, we have lots of classes that follow the decorator pattern in there where we use named registrations. These named registrations are then used to build up the InjectionConstructor for other registrations, for example:
container.RegisterType<IMyType2, Concrete1MyType2>("Concrete1MyType2", new ContainerControlledLifetimeManager());
container.RegisterType<IMyType2, Concrete2MyType2>("Concrete2MyType2", new ContainerControlledLifetimeManager());
container.RegisterType<IMyType1, Concrete1MyType1>(
"Concrete1MyType1",
new ContainerControlledLifetimeManager(),
new InjectionConstructor(
new ResolvedParameter<IMyType2>("Concrete2MyType2")));
Is it possible to access through some code what you have configured in the InjectionConstructor's for your registrations?
This article seems to suggest you can.
The example given is:
void DisplayContainerRegistrations(IUnityContainer theContainer)
{
string regName, regType, mapTo, lifetime;
Console.WriteLine("Container has {0} Registrations:",
theContainer.Registrations.Count());
foreach (ContainerRegistration item in theContainer.Registrations)
{
regType = item.RegisteredType.Name;
mapTo = item.MappedToType.Name;
regName = item.Name ?? "[default]";
lifetime = item.LifetimeManagerType.Name;
if (mapTo != regType)
{
mapTo = " -> " + mapTo;
}
else
{
mapTo = string.Empty;
}
lifetime = lifetime.Substring(0, lifetime.Length - "LifetimeManager".Length);
Console.WriteLine("+ {0}{1} '{2}' {3}", regType, mapTo, regName, lifetime);
}
}
OK, after not getting much info on this, I had a look at the internals of Unity as I could not see any public way of doing it. I came up with the following which uses Reflection to access the private members of the various parts of Unity.
The main reasoning for this is that injecting Transient instances into Singletons is a bit of a mismatch. Transient should only last a short time whilst Singletons will probably remain throughout the life of the DI Container. There is some nice information on Simple Injector here. This was one of the reasons for trying to get the Injection information as Unity does not have a verify like Simple Injector.
So, here are my service interfaces and classes I am registering. There are 3 interfaces and 3 concrete implementations with exception to IService2 which has 2 implementations.
public class Service1 : IService1
{
private readonly IService2 _service2;
private readonly IService3 _service3;
public Service1(IService2 service2, IService3 service3)
{
_service2 = service2;
_service3 = service3;
}
public int DoSomethingForService1()
{
return 1;
}
}
public interface IService1
{
int DoSomethingForService1();
}
public class Service2 : IService2
{
public int DoSomethingForService2()
{
return 1;
}
}
public class Service3 : IService3
{
public int DoSomethingForService3()
{
return 1;
}
}
public interface IService3
{
int DoSomethingForService3();
}
public class Service2_1 : IService2
{
public int DoSomethingForService2()
{
return 1;
}
}
public interface IService2
{
int DoSomethingForService2();
}
Now the Unity Container is built up. We tend to use a separate project for this as we don't want all references to be held in the UI. We are using 2 named registrations of IService2.
public static class UnityContainerBuilder
{
public static IUnityContainer BuildDirectInUnity()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IService2, Service2>("Service2OneAndOnly", new ContainerControlledLifetimeManager());
container.RegisterType<IService2, Service2_1>("Service2_1", new ContainerControlledLifetimeManager());
container.RegisterType<IService3, Service3>(new ContainerControlledLifetimeManager());
container.RegisterType<IService1, Service1>(new ContainerControlledLifetimeManager(),
new InjectionConstructor(
new ResolvedParameter<IService2>("Service2OneAndOnly"),
new ResolvedParameter<IService3>()));
}
}
Now the fun part. Here we get the Unity Configuration:
static void Main(string[] args)
{
Console.WriteLine("Building Unity Container...");
var container = (UnityContainer)UnityContainerBuilder.BuildDirectInUnity();
Console.WriteLine("Listing Registrations...");
FieldInfo policiesField = typeof(UnityContainer).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "policies");
FieldInfo parameterValuesField = typeof(SpecifiedConstructorSelectorPolicy).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "parameterValues");
FieldInfo paramNameField = typeof(ResolvedParameter).GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance).First(f => f.Name == "name");
var policies = (PolicyList)policiesField.GetValue(container);
// build up a dictionary for loop below to use to get the lifetime manager
var typeToRegistration = new Dictionary<Tuple<Type, string>, ContainerRegistration>();
foreach (ContainerRegistration registration in container.Registrations)
{
typeToRegistration.Add(new Tuple<Type, string>(registration.RegisteredType, registration.Name), registration);
}
// now output the list
foreach (ContainerRegistration registration in container.Registrations)
{
Console.WriteLine("{0} to {1}, {2}, {3}",
registration.RegisteredType.Name,
registration.MappedToType.Name,
registration.Name ?? "[default]",
registration.LifetimeManagerType.Name);
// need to check for our InjectionConstructor - I need local = false
IConstructorSelectorPolicy constructorPolicy = policies.Get<IConstructorSelectorPolicy>(
new NamedTypeBuildKey(registration.MappedToType, registration.Name), false);
// and I need SpecifiedConstructorSelectorPolicy as we are not using the default constructor
if (constructorPolicy is SpecifiedConstructorSelectorPolicy)
{
var specifiedConstructorPolicy = constructorPolicy as SpecifiedConstructorSelectorPolicy;
// now output the ResolvedParameters for type, name, lifetime manager
var paramValues = (InjectionParameterValue[])parameterValuesField.GetValue(specifiedConstructorPolicy);
foreach (var param in paramValues)
{
if (param is ResolvedParameter)
{
var resolvedParam = param as ResolvedParameter;
var name = (string)paramNameField.GetValue(resolvedParam);
string lifeTimeManagerName =
typeToRegistration[new Tuple<Type, string>(resolvedParam.ParameterType, name)].LifetimeManagerType.Name;
Console.WriteLine("\t{0}, {1}, {2}", param.ParameterTypeName, name ?? "[default]", lifeTimeManagerName);
}
else
{
Console.WriteLine("\t{0}", param.ParameterTypeName);
}
}
}
}
Console.WriteLine("Complete");
Console.ReadLine();
}
The drawbacks of this is that it is purely reflection based hacking and that it does not support the InjectionFactory where you can configure a new instance of a type.

Structuremap interception for registry scanned types

I have a ASP MVC 4 app that uses Structuremap. I'm trying to add logging to my application via Structuremap interception.
In a Registry, I scan a specific assembly in order to register all of it's types with the default convention:
public class ServicesRegistry : Registry
{
public ServicesRegistry()
{
Scan(x =>
{
x.AssemblyContainingType<MyMarkerService>();
x.WithDefaultConventions();
});
}
}
The interceptor:
public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var watch = Stopwatch.StartNew();
invocation.Proceed();
watch.Stop();//log the time
}
}
I can add the interceptor for one specific plugin type like this:
var proxyGenerator = new ProxyGenerator();
container.Configure(x => x.For<IServiceA>().Use<ServiceA>().DecorateWith(instance => proxyGenerator.CreateInterfaceProxyWithTarget(instance, new LogInterceptor())));
but I want to make structuremap create logging proxies for all the types that were scanned in the registry.
Is there a way to achieve this?
It doesn't look like there's an easy extension point for this, but I got it working with a fairly decent solution using a custom convention. In order to help you understand the decisions I made I'll walk you through a few steps (skipping the many, many missteps I made on my way).
First lets look at the DefaultConvention which you are already using.
DefaultConvention:
public class DefaultConventionScanner : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (!TypeExtensions.IsConcrete(type))
return;
Type pluginType = this.FindPluginType(type);
if (pluginType == null || !TypeExtensions.HasConstructors(type))
return;
registry.AddType(pluginType, type);
this.ConfigureFamily(registry.For(pluginType, (ILifecycle)null));
}
public virtual Type FindPluginType(Type concreteType)
{
string interfaceName = "I" + concreteType.Name;
return Enumerable.FirstOrDefault<Type>((IEnumerable<Type>)concreteType.GetInterfaces(), (Func<Type, bool>)(t => t.Name == interfaceName));
}
}
Pretty simple, we get the type and interface pairs and check to make sure they have a constructor, if they do we register them. It would be nice to just modify this so that it calls DecorateWith, but you can only call that on For<>().Use<>(), not For().Use().
Next lets look at what DecorateWith does:
public T DecorateWith(Expression<Func<TPluginType, TPluginType>> handler)
{
this.AddInterceptor((IInterceptor) new FuncInterceptor<TPluginType>(handler, (string) null));
return this.thisInstance;
}
So this creates a FuncInterceptor and registers it. I spent a fair bit of time trying to create one of these dynamically with reflection before deciding it would just be easier to make a new class:
public class ProxyFuncInterceptor<T> : FuncInterceptor<T> where T : class
{
public ProxyFuncInterceptor() : base(x => MakeProxy(x), "")
{
}
protected ProxyFuncInterceptor(Expression<Func<T, T>> expression, string description = null)
: base(expression, description)
{
}
protected ProxyFuncInterceptor(Expression<Func<IContext, T, T>> expression, string description = null)
: base(expression, description)
{
}
private static T MakeProxy(T instance)
{
var proxyGenerator = new ProxyGenerator();
return proxyGenerator.CreateInterfaceProxyWithTarget(instance, new LogInterceptor());
}
}
This class just makes it easier to work with when we have the type as a variable.
Finally I've made my own Convention based on the Default convention.
public class DefaultConventionWithProxyScanner : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (!type.IsConcrete())
return;
var pluginType = this.FindPluginType(type);
if (pluginType == null || !type.HasConstructors())
return;
registry.AddType(pluginType, type);
var policy = CreatePolicy(pluginType);
registry.Policies.Interceptors(policy);
ConfigureFamily(registry.For(pluginType));
}
public virtual Type FindPluginType(Type concreteType)
{
var interfaceName = "I" + concreteType.Name;
return concreteType.GetInterfaces().FirstOrDefault(t => t.Name == interfaceName);
}
public IInterceptorPolicy CreatePolicy(Type pluginType)
{
var genericPolicyType = typeof(InterceptorPolicy<>);
var policyType = genericPolicyType.MakeGenericType(pluginType);
return (IInterceptorPolicy)Activator.CreateInstance(policyType, new object[]{CreateInterceptor(pluginType), null});
}
public IInterceptor CreateInterceptor(Type pluginType)
{
var genericInterceptorType = typeof(ProxyFuncInterceptor<>);
var specificInterceptor = genericInterceptorType.MakeGenericType(pluginType);
return (IInterceptor)Activator.CreateInstance(specificInterceptor);
}
}
Its almost exactly the same with one addition, I create an interceptor and interceptorType for each type we register. I then register that policy.
Finally, a few unit tests to prove it works:
[TestFixture]
public class Try4
{
[Test]
public void Can_create_interceptor()
{
var type = typeof (IServiceA);
Assert.NotNull(new DefaultConventionWithProxyScanner().CreateInterceptor(type));
}
[Test]
public void Can_create_policy()
{
var type = typeof (IServiceA);
Assert.NotNull(new DefaultConventionWithProxyScanner().CreatePolicy(type));
}
[Test]
public void Can_register_normally()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.WithDefaultConventions();
}));
var serviceA = container.GetInstance<IServiceA>();
Assert.IsFalse(ProxyUtil.IsProxy(serviceA));
Console.WriteLine(serviceA.GetType());
}
[Test]
public void Can_register_proxy_for_all()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.Convention<DefaultConventionWithProxyScanner>();
}));
var serviceA = container.GetInstance<IServiceA>();
Assert.IsTrue(ProxyUtil.IsProxy(serviceA));
Console.WriteLine(serviceA.GetType());
}
[Test]
public void Make_sure_I_wait()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.Convention<DefaultConventionWithProxyScanner>();
}));
var serviceA = container.GetInstance<IServiceA>();
serviceA.Wait();
}
}
}
public interface IServiceA
{
void Wait();
}
public class ServiceA : IServiceA
{
public void Wait()
{
Thread.Sleep(1000);
}
}
public interface IServiceB
{
}
public class ServiceB : IServiceB
{
}
There's definitely room for some clean up here (caching, make it DRY, more tests, make it easier to configure) but it works for what you need and is a pretty reasonable way of doing it.
Please ask if you have any other questions about it.

Custom Service Locator with MEF and IOC container from galasoft

I've a requirement where I've to support two types of container in my application. Therefore I've created a custom ServiceLocator that serves 2 types of containers i.e.
SimpleIoc (Galasoft)
MefServiceLocatorAdapter
Therefore I've created a common service locator class i.e.
public class CommonServiceLocator : ServiceLocatorImplBase
{
private IServiceLocator _iocContainer, _mefContainer;
public CommonServiceLocator(IServiceLocator iocLocator, IServiceLocator mefLocator)
{
_iocContainer = iocLocator;
_mefContainer = mefLocator;
}
protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
{
IEnumerable<object> services;
try
{
services = _iocContainer.GetAllInstances(serviceType);
}
catch (Exception)
{
//Current assumption is that if IocContainer doesn't contain an instance then
//it should look for MefContainer for values
services = _mefContainer.GetAllInstances(serviceType);
}
return services;
}
protected override object DoGetInstance(Type serviceType, string key)
{
object service;
try
{
service = _iocContainer.GetInstance(serviceType, key);
}
catch (Exception)
{
//Current assumption is that if IocContainer doesn't contain an instance then
//it should look for MefContainer for values
service = _mefContainer.GetInstance(serviceType, key); //<== This fails to get an instance
}
return service;
}
public override object GetInstance(Type serviceType, string key)
{
return DoGetInstance(serviceType, key);
}
public override object GetInstance(Type serviceType)
{
return GetInstance(serviceType, null);
}
}
Now, the problem is when I try to get a class instance through IOC container using GetInstance() method it works fine. However, obtaining a class instance through MefContainer throws some error ("A first chance exception of type 'System.InvalidOperationException' occurred in System.Core.dll"). I've created a test class to test this scenario:
public class ServiceLocatorTest
{
public void CommonServiceLocatorInstanceTest()
{
var serviceLocator = new SimpleIoc();
serviceLocator.Register<GalaSoftIocData>();
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(MefCompositionAddin).Assembly));
CompositionContainer compContainer = new CompositionContainer(catalog);
CompositionBatch batch = new CompositionBatch();
batch.AddPart(AttributedModelServices.CreatePart(new MefCompositionAddin()));
compContainer.Compose(batch);
var vl = compContainer.GetExportedValue<MefCompositionAddin>(); // <== This gives instance correctly
var mefserviceLocator = new MefServiceLocatorAdapter(compContainer);
var commonServiceLocator = new CommonServiceLocator(serviceLocator, mefserviceLocator);
var galaSoftData = commonServiceLocator.GetInstance(typeof(GalaSoftIocData));
var mefData = commonServiceLocator.GetInstance(typeof(MefCompositionAddin));
}
}
[Export]
class MefCompositionAddin
{
public string MyData { get { return "Mef's Data composed"; } }
[Import]
public MefCompositionAddin MyObj { get; set; }
}
class MefCompositionData
{
[Import]
public MefCompositionAddin MyAddin { get; set; }
}
class GalaSoftIocData
{
public string MyData { get { return "Galasoft's Data composed"; } }
}
Kindly let me know if i've missed anything. and what could be the possible cause. Thanks everyone for your help in advance.
I believe that you are using the MefServiceLocatorAdapter provided in the Prism library. This is the code for its DoGetInstance method:
protected override object DoGetInstance(Type serviceType, string key)
{
IEnumerable<Lazy<object, object>> exports = this.compositionContainer.GetExports(serviceType, null, key);
if ((exports != null) && (exports.Count() > 0))
{
// If there is more than one value, this will throw an InvalidOperationException,
// which will be wrapped by the base class as an ActivationException.
return exports.Single().Value;
}
throw new ActivationException(
this.FormatActivationExceptionMessage(new CompositionException("Export not found"), serviceType, key));
}
As you can see in the comment, if you have more than one type exported for the corresponding service type and key it will thrown the exception you are describing due to the Single method.
You can either review the exports in you app to see if there is some type mapped to multiple classes (or the same class exported multiple times,) or rewrite that method so that it doesn't throw an exception (for example, using FirstOrDefault instead of Single.)
Note: I did not add the aforementioned comment, it is included in the library's code.

Categories