Lately I'm playing around a bit with the IoC tool LightCore. Since the last version no named instances are allowed anymore nontheless the ServiceLocator pattern is supported(?).
One of the crucial functionalities I need from the ServiceLocator is the resolving of named instances. My first idea was to override the DoGetInstance method and implement my own code.
My last workaround was to get a instance by it's typename
_testInstanceKey = "My.Namespace.MyType, MyAssembly";
IMyType type = locator.GetInstance(typeof(IMyType), _testInstanceKey)
protected override object DoGetInstance(Type serviceType, string key)
{
return _container.ResolveAll(serviceType)
.Where(x => x.GetType() == Type.GetType(key,true,true))
.FirstOrDefault();
}
This works out but what do I need a ServiceLocator for if I hardwire my typename?!
Has anybody any suggestions how I could work around this half-baked ServiceLocator?
You can solve this problem by introducing a IMyTypeFactory interface and letting the application take a dependency on that interface:
// Factory interface:
public interface IMyTypeFactory
{
IMyType GetByName(string name);
}
// Implementation in the composition root:
public class MyTypeFactory :
Dictionary<string, Func<IRequestHandler>>, IMyTypeFactory
{
public IMyType GetByName(string name) { return this[name](); }
}
// Registration
var factory = new MyTypeFactory
{
{ "foo", () => new MyType1() },
{ "bar", () => new MyType2() },
{ "boo", () => new MyType3() },
};
builder.Register<IMyTypeFactory>(c => factory);
As I said in the comments, try to move away from the use of the Service Locator anti-pattern. It will improve the testability and maintainability of your application. When using the dependency injection (DI) pattern, you don't call the container directly and there is no way to directly ask a named instance. When applying DI, you will have to change the way to configure the container or need to apply the right abstractions in your application (as shown with the IMyTypeFactory).
Assuming you can't change the way the framework calls the locator and assuming the framework uses the Common Service Locator is used as interface between your container and itself, you can add this functionality to a custom IServiceLocator implementation:
// This adapter wraps the CSL LightCoreAdapter of LightCore itself.
public class LightCoreServiceLocatorAdapter : IServiceLocator
{
private readonly LightCoreAdapter container;
public LightCoreServiceLocatorAdapter(IContainer container)
{
// You need a reference to LightCore.CommonServiceLocator.dll.
this.container = new LightCoreAdapter(container);
}
public IEnumerable<TService> GetAllInstances<TService>()
{
return this.container.GetAllInstances<TService>();
}
public IEnumerable<object> GetAllInstances(Type serviceType)
{
return this.container.GetAllInstances(serviceType);
}
public TService GetInstance<TService>(string key)
{
if (key == null)
{
return this.container.GetInstance<TService>(null);
}
else
{
// This is custom logic
this.container.GetInstance<INamedFactory<TService>>().GetByKey(key);
}
}
public TService GetInstance<TService>()
{
return this.container.GetInstance<TService>();
}
public object GetInstance(Type serviceType, string key)
{
if (key == null)
{
return this.container.GetInstance(serviceType);
}
else
{
// This is custom logic
var facType = typeof(INamedFactory<>).MakeGenericType(serviceType);
var factory = (INamedFactory)this.container.GetInstance(facType);
return factory.GetByKey(key);
}
}
public object GetInstance(Type serviceType)
{
return this.container.GetInstance(serviceType);
}
object IServiceProvider.GetService(Type serviceType)
{
((IServiceProvider)this.container).GetService(serviceType);
}
}
This class uses the following two custom interfaces:
public interface INamedFactory
{
object GetByKey(string key);
}
public interface INamedFactory<T> : INamedFactory
{
T GetByKey(string key);
}
Using this custom LightCoreServiceLocatorAdapter and these two custom interfaces, you can create custom factories, such as this generic one:
public sealed class NamedDelegateFactory<T> : INamedFactory<T>
{
private readonly Func<string, T> factory;
public NamedDelegateFactory(Func<string, T> factory)
{
this.factory = factory;
}
public T GetByKey(string key)
{
return this.factory(key);
}
object INamedFactory.GetByKey(string key)
{
return this.factory(key);
}
}
Which can be registered in the container as follows:
var factory = new NamedDelegateFactory<IMyType>(key =>
{
if (key == "Cool") return new MyType1();
else return new MyType2();
});
var builder = new ContainerBuilder();
builder.Register<INamedFactory<IMyType>>(c => factory);
Next, a LightCoreServiceLocatorAdapter can be created as follows:
var adapter = new LightCoreServiceLocatorAdapter(builder.Build());
Microsoft.Practices.ServiceLocation.ServiceLocator
.SetLocatorProvider(() => adapter);
You can register all named instances using the INamedFactory<T> interface and use the NamedDelegateFactory<T> wrapped with a delegate or implement a custom type that implements INamedFactory<T>.
Related
I'm trying to upgrade the latest Autofac package to 5.2.0, but not really successfully becasue of interface changes,
From (Autofac 4.9.4)
public static class ResolutionExtensions
{
public static bool TryResolve<T>(this IComponentContext context, out T instance);
}
To (Autofac 5.2.0)
public static class ResolutionExtensions
{
public static bool TryResolve<T>(this IComponentContext context, out T instance)
where T : class;
}
The ServiceStack package has a IContainerAdapter interface (ServiceStack.Interfaces 5.8.0)
public interface IResolver
{
T TryResolve<T>();
}
public interface IContainerAdapter : IResolver
{
T Resolve<T>();
}
My AutofacIocAdapter implementates this IContainerAdapter
public class AutofacIocAdapter : IContainerAdapter
{
public T TryResolve<T>()
{
if (m_Container.TryResolve<Autofac.ILifetimeScope>(out var scope) &&
scope.TryResolve<T>(out var scopeComponent))
{
return scopeComponent;
}
if (m_Container.TryResolve<T>(out var component))
{
return component;
}
return default(T);
}
}
But got compiling error after upgrading Autofac
Error CS0452 The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'ResolutionExtensions.TryResolve<T>(IComponentContext, out T?)'
Any suggestion to resolve ?
You wouldn't be able to call a class with a class constraint from a method without that constraint from C#, but you could use reflection to invoke it.
But your first attempt should be to bypass the API with the constraint. Looking at AutoFac's implementation of TryResolve will show what APIs they call internally:
public static bool TryResolve<T>(this IComponentContext context, out T? instance)
where T : class
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
object? component;
// Null annotation attributes only work if placed directly in an if statement.
if (context.TryResolve(typeof(T), out component))
{
instance = (T)component;
return true;
}
else
{
instance = default;
return false;
}
}
So you would just need to bypass their generic API with constraints and call the same runtime Type API that they call, something like:
public class AutofacIocAdapter : IContainerAdapter
{
private readonly Autofac.IContainer container;
public AutofacIocAdapter(Autofac.IContainer container) =>
this.container = container;
public T TryResolve<T>()
{
if (container.TryResolve<Autofac.ILifetimeScope>(out var scope) &&
scope.TryResolve(typeof(T), out var scopeComponent))
return (T)scopeComponent;
if (container.TryResolve(typeof(T), out var component))
return (T)component;
return default;
}
public T Resolve<T>()
{
var ret = TryResolve<T>();
return !ret.Equals(default)
? ret
: throw new Exception($"Error trying to resolve '{typeof(T).Name}'");
}
}
What is the best way to create derived objects at run-time while adhering to LSP and always keeping the objects in a valid state.
I'm fairly new to construction patterns such as Factory and Builder and most of the examples I find are very simplistic. Here is my scenario:
I have one base class (some things left out for brevity):
public abstract BaseClass
{
public string Property1 { get; set ... null guard; }
public string Property2 { get; set ... conditional null guard; }
public virtual bool RequiresProperty2 => false;
protected BaseClass(string property1)
{
null guard
Property1 = property1;
}
}
I have 50+ derived classes. Some of which require prop2 some of which don't. The ones that require prop2 have a constructor that forces prop2 to be passed in, enforcing that all BaseClass derived objects are in a valid state upon construction. I'm also trying to adhere to LSP and I'm using Castle Windsor for dependency injection.
The solution I've come up with is to create a factory that returns a builder:
public interface IFactory
{
IBuilder Create(string type);
}
public interface IBuilder
{
IBuilder SetProperty1(string property);
IBuilder SetProperty2(string property);
BaseClass Build();
}
The concrete implementation of the factory loads all the types that inherit from BaseClass through reflection. When you call Factory.Create(...) you pass it a string which is the string name of the type you want to create. Then the factory creates a builder passing the appropriate Type to the builder's constructor. The builder looks like so:
public sealed class ConcreteBuilder : IBuilder
{
private static Type ClassType = typeof(BaseClass);
private static readonly ConcurrentDictionary<Type, Delegate>
ClassConstructors = new ConcurrentDictionary<Type, Delegate>();
private readonly Type type;
private string property1;
private string property2;
public ConcreteBuilder(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
if (!type.IsSubclassOf(ClassType))
{
throw new ArgumentException("Must derive from BaseClass.");
}
this.type = type;
}
public IBuilder SetProperty1(string property)
{
this.property1 = property;
return this;
}
public IBuilder SetProperty2(string property)
{
this.property2 = property;
return this;
}
public BaseClass Build()
{
var arguments = BuildArguments();
Delegate ctor;
if (ClassConstructors.TryGetValue(this.type, out ctor))
{
return (BaseClass)ctor.DynamicInvoke(arguments);
}
return (BaseClass)GetConstructor(arguments).DynamicInvoke(arguments);
}
private object[] BuildArguments()
{
var args = new List<object>();
if (!string.IsNullOrEmpty(this.property1))
{
args.Add(this.property1);
}
if (!string.IsNullOrEmpty(this.property2))
{
args.Add(this.property2);
}
return args.ToArray();
}
private Delegate GetConstructor(object[] arguments)
{
var constructors = this.type.GetConstructors();
foreach (var constructor in constructors)
{
var parameters = constructor.GetParameters();
var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
if (parameterTypes.Length != arguments.Length + 1) continue;
if (!parameterTypes.Zip(arguments, TestArgumentForParameter).All(x => x))
{
continue;
}
var parameterExpressions = parameters.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
var callConstructor = Expression.New(constructor, parameterExpressions);
var ctor = Expression.Lambda(callConstructor, parameterExpressions).Compile();
ClassConstructors.TryAdd(this.type, ctor);
return ctor;
}
throw new MissingMethodException("No constructor found");
}
private static bool TestArgumentForParameter(Type parameterType, object argument)
{
return (argument == null && !parameterType.IsValueType) || (parameterType.IsInstanceOfType(argument));
}
}
Is there a better way to do this? Am I going about this the right way? I know DynamicInvoke is slow. Should I be going about this differently?
Getting my head all banged up trying to moq the interface below. The GetOrSet has me tripped up. The service comes from here
public interface ICacheService
{
T GetOrSet<T>(string cackeKey, int expiryInMinutes, Func<T> getItemCallback) where T : class;
}
public class CacheService : ICacheService
{
public T GetOrSet<T>(string cacheKey, int expiryInMinutes, Func<T> getItemCallback) where T : class
{
T item = MemoryCache.Default.Get(cacheKey) as T;
if (item == null)
{
item = getItemCallback();
MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(expiryInMinutes));
}
return item;
}
}
Example in code:
var result = _cacheService.GetOrSet(
cacheKey,
cacheExpiry,
() => this.GetRoutes(routeType));
return result.Select(x => new Route(x));
Basic setup could look like:
public static ICacheService GetMockCacheService<T>() where T : class
{
var mock = new Mock<ICacheService>();
mock.Setup(service => service.GetOrSet(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<Func<T>>()))
.Returns(default(T));
return mock.Object;
}
Use a generic method to build your mock for whatever type you need in the implementation.
One of my colleague came across this code and we are unable to understand why _resolverThunk is needed.
Summary of the code looks like this:
private Func<IDependencyResolver> _resolverThunk;
public SingleServiceResolver()
{
_resolverThunk = () => DependencyResolver.Current;
}
private TService GetValueFromResolver()
{
TService result = _resolverThunk().GetService<TService>();
return result;
}
If you look at another internal constructor, it sets the _resolverThunk from parameter. So it makes sense.
internal SingleServiceResolver(Func<TService> staticAccessor, TService defaultValue, IDependencyResolver resolver, string callerMethodName)
: this(staticAccessor, defaultValue, callerMethodName)
{
if (resolver != null)
{
_resolverThunk = () => resolver;
}
}
Otherwise, there is no reason to do it.
I really like StructureMap as an IOC-framework especially the convention based registration. Now I try to do the following: I want to add all types that implement a specific interface when the class has a default (no parameters) constructor. And the types must be created using this constructor.
This is what I have untill now, which registers the correct types, but how do I specify that the default constructor should be used when creating an instance.
public class MyRegistry : Registry
{
public MyRegistry()
{
Scan(
x =>
{
x.AssemblyContainingType<IUseCase>();
x.Exclude(t => !HasDefaultConstructor(t));
x.AddAllTypesOf<IUseCase>();
});
}
private static bool HasDefaultConstructor(Type type)
{
var _constructors = type.GetConstructors();
return _constructors.Any(c => IsDefaultConstructor(c));
}
private static bool IsDefaultConstructor(ConstructorInfo constructor)
{
return !constructor.GetParameters().Any();
}
}
There are a few ways to force StructureMap to use a specific constructor. The simplest is to put the DefaultConstructor attribute on the constructor you want to use. Assuming you don't want to do that, you would have to create a custom RegistrationConvention.
public class UseCaseRegistrationConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (type.IsAbstract || type.IsInterface || type.IsEnum)
return;
var useCaseInterface = type.GetInterface("IUseCase");
if (useCaseInterface == null)
return;
var constructor = type.GetConstructors().FirstOrDefault(c => !c.GetParameters().Any());
if (constructor != null)
{
registry.For(useCaseInterface).Add(c => constructor.Invoke(new object[0]));
}
}
}
Then use it in your Scan call:
Scan(x =>
{
x.AssemblyContainingType<IUseCase>();
x.With(new UseCaseRegistrationConvention());
});