From the Autofac documentation I can see how to get all registrations for a class T:
public T[] ResolveAll<T>()
{
return _container.Resolve<IEnumerable<T>>().ToArray();
}
But when I only have the Type available, how can I get the equivalent results?
public Array ResolveAll(Type service)
{
return _container.Resolve( ???
}
I am trying to implement a wrapper class which has a pre-defined interface.
EDIT
For quick reference, the answer from Matthew Watson (with relevant ideas from David L) is:
public Array ResolveAll(Type service)
{
var typeToResolve = typeof(IEnumerable<>).MakeGenericType(service);
return _container.Resolve(typeToResolve) as Array;
}
Here is an example. I've added asserts to prove that the types returned from ResolveAll<T>(this IContainer self) are the same (and in the same order) as those returned from ResolveAll(this IContainer self, Type type):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Autofac;
using Autofac.Core;
namespace AutofacTrial
{
public abstract class Base
{
public abstract string Name { get; }
public override string ToString()
{
return Name;
}
}
public sealed class Derived1: Base
{
public override string Name
{
get
{
return "Derived1";
}
}
}
public sealed class Derived2: Base
{
public override string Name
{
get
{
return "Derived2";
}
}
}
public sealed class Derived3: Base
{
public override string Name
{
get
{
return "Derived3";
}
}
}
static class Program
{
static void Main()
{
var builder = new ContainerBuilder();
builder.RegisterType<Derived1>().As<Base>();
builder.RegisterType<Derived2>().As<Base>();
builder.RegisterType<Derived3>().As<Base>();
var container = builder.Build();
var array1 = container.ResolveAll(typeof(Base));
var array2 = container.ResolveAll<Base>();
Trace.Assert(array1.Length == 3);
Trace.Assert(array2.Length == 3);
for (int i = 0; i < array1.Length; ++i)
{
Trace.Assert(array1[i].GetType() == array2[i].GetType());
Console.WriteLine(array1[i]);
}
}
public static T[] ResolveAll<T>(this IContainer self)
{
return self.Resolve<IEnumerable<T>>().ToArray();
}
public static object[] ResolveAll(this IContainer self, Type type)
{
Type enumerableOfType = typeof(IEnumerable<>).MakeGenericType(type);
return (object[]) self.ResolveService(new TypedService(enumerableOfType));
}
}
}
The underling implementation is the same
I also used Reflector to look at the implementation of Resolve<IEnumerable<T>>(), and it winds up doing this:
public static TService Resolve<TService>(this IComponentContext context, IEnumerable<Parameter> parameters)
{
return (TService) context.Resolve(typeof(TService), parameters);
}
which calls:
public static object Resolve(this IComponentContext context, Type serviceType, IEnumerable<Parameter> parameters)
{
return context.ResolveService(new TypedService(serviceType), parameters);
}
So the two must be equivalent, since they are implemented that way.
You can invoke _container.Resolve by calling your wrapped method via reflection (MSDN), but in doing so you will lose your compile-time type safety.
public class Container
{
public T[] ResolveAll<T>()
{
return _container.Resolve<IEnumerable<T>>().ToArray();
}
public object ResolveAllGeneric(Type t)
{
MethodInfo method = GetType().GetMethod("ResolveAll")
.MakeGenericMethod(new Type[] { t });
return method.Invoke(this, new object[] { });
}
}
Related
I'm trying to create a convenient serialized reference to asset objects. It serialized correctly, but deserialization fails with exception
"Error setting value to 'textAssetRef' on 'TestData'."
I've prepared a small test component for Unity to illustrate this:
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
public class Test : MonoBehaviour
{
public TestData testData;
public void Awake()
{
try
{
var sData = JsonConvert.SerializeObject(testData, Formatting.Indented);
UnityEngine.Debug.Log(sData);
testData = JsonConvert.DeserializeObject<TestData>(sData);
UnityEngine.Debug.Log("Done.");
}
catch (Exception x)
{
UnityEngine.Debug.LogError(x.Message);
}
}
}
[Serializable]
public class TestData
{
public TextAssetRef textAssetRef;
}
[Serializable]
[JsonConverter(typeof(Serialization))]
public class TextAssetRef : ObjectRef<TextAsset>
{
public TextAssetRef() { }
public TextAssetRef(TextAssetRef other) : base(other) { }
public TextAssetRef(TextAsset ta) : base(ta) { }
}
[Serializable]
public class ObjectRef<T> where T : UnityEngine.Object
{
public T obj;
public ObjectRef() { }
public ObjectRef(ObjectRef<T> other) { obj = other.obj; }
public ObjectRef(T obj) { this.obj = obj; }
public class Serialization : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var objRef = (ObjectRef<T>)value;
var jObject = new JObject { { "path", AssetDatabase.GetAssetPath(objRef.obj) } };
serializer.Serialize(writer, jObject);
}
public override bool CanConvert(Type objectType) { return objectType == typeof(ObjectRef<T>); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var assetPath = jObject.GetValue("path").Value<string>();
return new ObjectRef<T> { obj = AssetDatabase.LoadAssetAtPath<T>(assetPath) };
}
}
}
To reproduce the error just create a new project with JSON.Net asset package in Unity, create empty object in scene, put this Test component on it and press Play.
What am I to do to get it deserialized correctly?
Given That
Component.For<IService>().ImplementedBy<SecretService>().Named("secretService")
Component.For<IService>().ImplementedBy<PublicService>().Named("publicService")
And
class Foo{
public Foo(IService publicService){ ...... }
}
And
class Bar{
public Bar(IService secretService){ ...... }
}
Then how can i achieve the following
Foo and Bar should get instances of publicService and secretService respectively, entirely based on name of their constructor parameters.
I have now made it to work using a custom SubDependencyResolver, i added this to the container and now it injects the implementation by name
public class ByParameterNameResolver : ISubDependencyResolver
{
private readonly IKernel kernel;
public ByParameterNameResolver(IKernel kernel)
{
this.kernel = kernel;
}
public virtual bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
if (dependency.TargetItemType == null)
return false;
if (string.IsNullOrWhiteSpace(dependency.DependencyKey))
return false;
return kernel.HasComponent(dependency.DependencyKey);
}
public virtual object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model, DependencyModel dependency)
{
return kernel.Resolve(dependency.DependencyKey, dependency.TargetItemType);
}
}
Consider this code:
http://try.haxe.org/#5AD6e
class Test
{
public static function main()
{
var foo = new FluentFoo(null, { bar: 1 }).hello();
}
}
class Foo
{
public function new(options:{ bar:Int }) {}
public function hello()
{
trace("Hi there");
}
}
class Fluent
{
private var parent:Null<Fluent>;
public function new(parent:Null<Fluent>)
{
this.parent = parent;
}
public function end()
{
if(parent != null) {
return parent;
}
throw 'Top level already reached';
}
}
class FluentFoo extends Fluent
{
public var base:Foo;
public function new(parent:Null<Fluent>, options:{ bar:Int })
{
super(parent);
base = new Foo(options);
}
public function hello()
{
base.hello();
return this;
}
}
I want to generate classes such as FluentFoo automatically.
In pseudohaxe code:
import haxe.Constraints.Constructible;
class Test
{
public static function main()
{
var foo = new Fluent<Foo>(null, { bar: 1 }).hello();
}
}
class Foo
{
public function new(options:{ bar:Int }) {}
public function hello()
{
trace("Hi there");
}
}
#:generic
#:genericBuild(FluentMacro.build())
class Fluent<T:Constructible<Dynamic -> Void>>
{
private var parent:Null<Fluent>;
private var base:T;
public function new(parent:Null<Fluent>, options:Dynamic)
{
this.parent = parent;
this.base = new T(options);
}
public function end()
{
if(parent != null) {
return parent;
}
throw 'Top level already reached';
}
}
class FluentMacro
{
public static function build()
{
//Get "T" public methods
//Add them to class calling this genericBuild method (in this example to Fluent_Foo)
//Modify them so they return "this"
}
}
I know that I can't use #:build as all I'd get from Context.getLocalType would be TInst(Fluent,[TInst(Fluent.T,[])]).
However, I'm not completely understanding haxe manual on generic builds - they are under the same section "Type building macros" as normal #:build, yet the build method is expected to return ComplexType, and not an array of fields. Is it possible at all to add fields in #:genericBuild?
Thank you
That was a bit more complex than I anticipated, but I did it. For other people to use: https://github.com/Misiur/Fluent
Lets say I have a simple repository class, with one GetByNames method
public class MyRepo
{
private readonly MyDbContext _db;
public MyRepo(MyDbContext db)
{
_db = db;
}
public IQueryable<MyObject> GetByNames(IList<string> names)
{
if (names== null || !names.Any())
{
return Enumerable.Empty<MyObject>().AsQueryable();
}
return _db.MyObjects.Where(a => names.Contains(a.Name));
}
}
Now when I use it with async EntityFramework ToListAsync() extension
var myObjects = awawit new MyRepo(_db).GetByNames(names).ToListAsync();
It will blow up if I pass in empty list or null because Enumerable.Empty<MyObject>().AsQueryable() does not implement IDbAsyncEnumerable<MyObject> interface.
The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.
So my question is, how can I return an empty IQueryable<> that implements IDbAsyncEnumerable, without hitting the database?
I ended up implementing an extension method that returns wrapper which implements IDbAsyncEnumerable. It is based on this boilerplate implementation for mocking async code.
With this extension method I can use
return Enumerable.Empty<MyObject>().AsAsyncQueryable();
which works great.
Implementation:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace MyProject.MyDatabase.Extensions
{
public static class EnumerableExtensions
{
public static IQueryable<T> AsAsyncQueryable<T>(this IEnumerable<T> source)
{
return new AsyncQueryableWrapper<T>(source);
}
public static IQueryable<T> AsAsyncQueryable<T>(this IQueryable<T> source)
{
return new AsyncQueryableWrapper<T>(source);
}
}
internal class AsyncQueryableWrapper<T>: IDbAsyncEnumerable<T>, IQueryable<T>
{
private readonly IQueryable<T> _source;
public AsyncQueryableWrapper(IQueryable<T> source)
{
_source = source;
}
public AsyncQueryableWrapper(IEnumerable<T> source)
{
_source = source.AsQueryable();
}
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Expression Expression => _source.Expression;
public Type ElementType => _source.ElementType;
public IQueryProvider Provider => new AsyncQueryProvider<T>(_source.Provider);
}
internal class AsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
{
public AsyncEnumerable(IEnumerable<T> enumerable)
: base(enumerable)
{ }
public AsyncEnumerable(Expression expression)
: base(expression)
{ }
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
IQueryProvider IQueryable.Provider => new AsyncQueryProvider<T>(this);
}
internal class AsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal AsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
var t = expression.Type;
if (!t.IsGenericType)
{
return new AsyncEnumerable<TEntity>(expression);
}
var genericParams = t.GetGenericArguments();
var genericParam = genericParams[0];
var enumerableType = typeof(AsyncEnumerable<>).MakeGenericType(genericParam);
return (IQueryable)Activator.CreateInstance(enumerableType, expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new AsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute(expression));
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}
internal class AsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public AsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
public T Current => _inner.Current;
object IDbAsyncEnumerator.Current => Current;
}
}
If you don't want to hit the DB, you'll most likely have to provide your own implementation of empty IQuerable that implements IDbAsyncEnumerable. But I don't think it is too hard. In all the enumerators just return null for Current and false for MoveNext. In Dispose just do nothing. Try it. Enumerable.Empty<MyObject>().AsQueryable() has nothing to do with database, it definitely does not implement IDbAsyncEnumerable. You need an implementation that does, according to this.
I had the same problem, and didn't figure out what was happening, but I could solve the issue with this:
public IQueryable<MyObject> GetByNames(IList<string> names)
{
if (names?.Any() != true)
{
return _db.Set<MyObject>().Take(0);
//! or
return _db.MyObjects.Take(0);
}
...
}
I've read over several examples that were more complex then I needed and I'm having trouble distilling this down to a simple, concise pattern.
Let's say I have an interface names ICustomService and multiple implementations of ICustomService. I also have a class Consumer that needs to determine at run time which ICustomService to use based upon a parameter.
So I create a classes as follows:
public class Consumer
{
private CustomServiceFactory customServiceFactory;
public Consumer(CustomServiceFactory _customServiceFactory)
{
customServiceFactory = _customServiceFactory;
}
public void Execute(string parameter)
{
ICustomService Service = customServiceFactory.GetService(parameter);
Service.DoSomething();
}
}
public class CustomServiceFactory
{
private IComponentContext context;
public CustomServiceFactory(IComponentContext _context)
{
context = _context;
}
public ICustomService GetService(string p)
{
return context.Resolve<ICustomService>(p); // not correct
}
}
public class ServiceA : ICustomService
{
public void DoSomething()
{
}
}
public class ServiceB : ICustomService
{
public void DoSomething()
{
}
}
Is there an advantage to having my factory implement an interface? How do I fix my factory and register these classes with Autofac so that Consumer.Execute("A") calls DoSomething on WorkerA and Consumer.Execute("B") calls DoSomething on WorkerB?
Thank you
You would register your implementations of ICustomService with keys. For example:
builder.RegisterType<FooService>.Keyed<ICustomService>("someKey");
builder.RegisterType<BarService>.Keyed<ICustomService>("anotherKey");
and then your factory method would be:
public ICustomService GetService(string p)
{
return context.ResolveKeyed<ICustomService>(p);
}
But, you can take this a step further and decouple CustomServiceFactory from IComponentContext:
public class CustomServiceFactory
{
private Func<string, ICustomService> _create;
public CustomServiceFactory(Func<string, ICustomService> create)
{
_create = create;
}
public ICustomService GetService(string p)
{
return _create(p);
}
}
which you would register like so:
builder.Register(c => {
var ctx = c.Resolve<IComponentContext>();
return new CustomServiceFactory(key => ctx.ResolveKeyed<ICustomService>(key));
});
And at that point, assuming CustomServiceFactory doesn't have any other behavior that was omitted for the question, then you as might as well just use and register Func<string, ICustomService> directly.