How do you resolve multiple dependencies using serviceKey to match parameter.name? - dryioc

I am trying to figure out how to get DryIoc to resolve ITest on ExampleClass?
This is matching the parameter name to the service key as there are multiple registrations to locate the correct service.
public class Program
{
public void Main()
{
var container = new Container();
container.Register<ITest, A>(serviceKey: "a");
container.Register<ITest, B>(serviceKey: "b");
container.Register<ExampleClass>();
var example = container.Resolve<ExampleClass>();
}
}
public interface ITest { }
public class A : ITest { }
public class B : ITest { }
public class ExampleClass
{
public ExampleClass(ITest a, ITest b)
{
}
}

Use Parameters.Of https://www.fuget.org/packages/DryIoc.dll/4.2.5/lib/netstandard2.0/DryIoc.dll/DryIoc/Parameters
public class Program
{
public void Main()
{
var c = new Container();
c.Register<ITest, A>(serviceKey: "a");
c.Register<ITest, B>(serviceKey: "b");
c.Register<ExampleClass>(made:
Made.Of(parameters: Parameters.Of
.Name("a", serviceKey: "a")
.Name("b", serviceKey: "b")));
var example = c.Resolve<ExampleClass>();
}
}
You may also omit the Made.Of(parameters: because ParameterSelector returned by Parameters.Of is implicitly convertable to Made:
c.Register<ExampleClass>(made:
Parameters.Of
.Name("a", serviceKey: "a")
.Name("b", serviceKey: "b"));
You may apply more generic matching of parameter name to service key without explicitly listing the parameters, but it will be more fragile given you will add non-keyed parameter later:
c.Register<ExampleClass>(made:
Parameters.Of.Details(
(req, parInfo) => ServiceDetails.Of(serviceKey: parInfo.Name)));
Another type-safe option is directly specifying the constructor via delegate expression (Linq.Expressions.Expression<T>) describing its positional arguments - this option will inform you with compilation error when constructor is changed:
c.Register<ExampleClass>(made:
Made.Of(() =>
new ExampleClass(
Arg.Of<ITest>(serviceKey: "a"),
Arg.Of<ITest>(serviceKey: "b"))));
The above ways applied on the specific registration, but the same may be done on Container level using Rules:
var c = new Container(rules =>
rules.With(parameters:
Parameters.Of.Details(
(req, parInfo) => req.ServiceType == typeof(ExampleClass)
? ServiceDetails.Of(serviceKey: parInfo.Name)
: null)
));
Note: The last option affects performance because the rule need to be checked for all registrations.
The same approaches can be applied for specifying the property injection using PropertiesAndFields.Of.

Related

How to register IEnumerable<IService> In DryIoc Mvc Controller like Autofac Enumeration (IEnumerable<B>, IList<B>, ICollection<B>)

Test Code With Autofac is Ok,but with DryIoc is error. How to make this work.
public class HomeController : Controller
{
private readonly ITestAppService _testAppService;
private readonly IEnumerable<ITestAppService> _testAppServiceList;
public HomeController(ITestAppService testAppService, IEnumerable<ITestAppService> testAppServiceList)
{
_testAppService = testAppService;
_testAppServiceList = testAppServiceList;
}
}
public class Test1AppService : ITestAppService{}
public class Test2AppService : ITestAppService{}
public interface ITestAppService: IAppService{}
The error 'Make sure that the controller has a parameterless public constructor ' is caused by field ITestAppService in controller not the field IEnumerable.Following is my register code.
var impls =
typeof(IAppService).Assembly
.GetTypes()
.Where(type =>
type.IsPublic &&
!type.IsAbstract &&
type.GetInterfaces().Length != 0 && typeof(IAppService).IsAssignableFrom(type));
foreach (var type in impls)
{
container.Register(type.GetInterfaces().First(), type, Reuse.Transient);
}
Resolved by dadhi's suggestion,My container is
DryIoc.IContainer container = new DryIoc.Container(
rules =>
{
return rules.WithFactorySelector(Rules.SelectLastRegisteredFactory())
.WithResolveIEnumerableAsLazyEnumerable();
}
);
The dryioc wiki about Resolving from multiple default services may need some update. Rules.SelectLastRegisteredFactory is a method.
The problem is that consdering two implementations of ITestAppService container doesn't know which to select for the first dependency. But you may explicitly define the convention:
var container = new Container(rules => rules
.WithFactorySelector(Rules.SelectLastRegisteredFactory));

Registering simple types in a specific example

Consider the following
ClassA has a constructor that takes an instance of MasterClass and a string and exposes a property called Names of type string[].
ClassB has a constructor that takes an IJuicePresser and a IEnumerable<string>.
ClassC has a constructor that takes an IEnumerable<string>.
Manually I would do something like this to tie them together.
var masterClass = new MasterClass();
var juicePresser = JuicePresser.Create("default");
var classA = new ClassA(masterClass, "string");
var names = classA.Names;
var classB = new ClassB(juicePresser, names as IEnumerable<string>);
var classC = new ClassC(Array.Reverse(names));
How can I set up DryIoc to handle these registrations/resolutions for me?
It might be better to move all these run-time names from constructors to corresponding methods. But here is the matching DryIoc setup as-is:
Live on .NET Fiddle
using System;
using System.Collections.Generic;
using System.Linq;
using DryIoc;
public class Program
{
public static void Main()
{
var c = new Container();
c.Register<MasterClass>();
c.Register<JuicePresser>(Made.Of(() => JuicePresser.Create("default")));
// an example how to inject a primitive value: "string" in this case
c.Register<ClassA>(made: Parameters.Of.Type<string>(_ => "string"));
// service key is optional, just to distinguish the list of strings for consumer.
c.Register<string[]>(
Made.Of(_ => ServiceInfo.Of<ClassA>(), factory => factory.Names),
serviceKey: "names");
// register reverse names using ReverseHelper method
c.Register<string[]>(
Made.Of(() => ReverseHelper(Arg.Of<string[]>("names"))),
serviceKey: "reverse-names");
// specify the names and required type (string[]) for injection
c.Register<ClassB>(made: Parameters.Of.Type<IEnumerable<string>>(typeof(string[]), serviceKey: "names"));
// specify reverse names for injection
c.Register<ClassC>(made: Parameters.Of.Type<string[]>(serviceKey: "reverse-names"));
var classB = c.Resolve<ClassB>();
var classC = c.Resolve<ClassC>();
Console.WriteLine(string.Join(" - ", classB.Names.ToArray()));
// outputs: a - string - z
Console.WriteLine(string.Join(" - ", classC.Names));
// outputs: z - string - a
}
public static T[] ReverseHelper<T>(T[] target) {
Array.Reverse(target);
return target;
}
public class MasterClass {}
public class JuicePresser
{
public readonly string Name;
private JuicePresser(string name) { Name = name; }
public static JuicePresser Create(string name)
{
return new JuicePresser(name);
}
}
public class ClassA
{
public readonly string[] Names;
public ClassA(MasterClass master, string name) {
Names = new[] { "a", name, "z" }; // for example
}
}
public class ClassB
{
public readonly JuicePresser Presser;
public readonly IEnumerable<string> Names;
public ClassB(JuicePresser presser, IEnumerable<string> names) {
Presser = presser;
Names = names;
}
}
public class ClassC
{
public readonly string[] Names;
public ClassC(string[] names) {
Names = names;
}
}
}
Update:
Explaining a bit the part with:
c.Register<string[]>(
Made.Of(_ => ServiceInfo.Of<ClassA>(), factory => factory.Names),
serviceKey: "names");
DryIoc has support for using not only constructors for service creation, but also static and instance methods (factory methods), properties and fields. Here is the wiki topic.
In example above we use Names property of ClassA object as factory method to register service type "string[]" with service key "names".
Let's see in detail:
// Registering service of ClassA. It means that it can be resolved / injected directly,
// or/and we can use it as a factory for resolving further services
c.Register<ClassA>(made: Parameters.Of.Type<string>(_ => "string"));
// Registering service of type "string[]"
c.Register<string[]>(
// Made.Of enables specifying factory method to use for "string[]" resolution, instead default constructor selection rules.
Made.Of(
// 1) Specifying what factory object should be used,
// Here we say to use ClassA service registered in container
requestNotUsedHere => ServiceInfo.Of<ClassA>(),
// 2) Specify that Names property of resolved ClassA object
// should be used for "string[]" resolution
classA => classA.Names),
// As the "string[]" is not very distinctive (unique) service type
// (you might register other "string[]" with different meaning),
// we identify the names with "names" service key. So when injected or
// resolved, you need to specify the service key in addition to type.
serviceKey: "names");
If you want to register with static factory method, property, field, then you don't need to specify request => ServiceInfo.Of<TFactory>() part. BTW, request parameter can be used for conditional selection of factory.

Creating a fallback container/resolver DryIoc

Current working on creating a Prism.DryIoc.Forms project to try out DryIoc (first time!).
In Xamarin.Forms there is a native DependencyService and to provide a nice way to migrate towards using Prism I would like to add it as a fallback container in case the requsted service type can't be resolved from the main container.
Current I have created a FallbackContainer and pass the instance of IContainerand overrides the methods for IResolver and delegates the rest of the IContainer calls to the instance passed during creation.
So after the default container is created and configured and then do
Container = CreateContainer();
ConfigureContainer();
Container.Rules.WithFallbackContainer(new DependencyServiceContainer(Container));
Is this the preferred method or is there any way just to attach a default IResolver?
Current implementation
public class FallbackDependencyServiceContainer : IContainer
{
private readonly IContainer container;
public FallbackDependencyServiceContainer(IContainer container)
{
this.container = container;
}
public object Resolve(Type serviceType, bool ifUnresolvedReturnDefault)
{
return ResolveFromDependencyService(serviceType);
}
public object Resolve(Type serviceType, object serviceKey, bool ifUnresolvedReturnDefault,
Type requiredServiceType,
RequestInfo preResolveParent, IScope scope)
{
return ResolveFromDependencyService(serviceType);
}
public IEnumerable<object> ResolveMany(Type serviceType, object serviceKey, Type requiredServiceType,
object compositeParentKey,
Type compositeParentRequiredType, RequestInfo preResolveParent, IScope scope)
{
return new[] { ResolveFromDependencyService(serviceType) };
}
private static object ResolveFromDependencyService(Type targetType)
{
if (!targetType.GetTypeInfo().IsInterface)
{
return null;
}
var method = typeof(DependencyService).GetTypeInfo().GetDeclaredMethod("Get");
var genericMethod = method.MakeGenericMethod(targetType);
return genericMethod.Invoke(null, new object[] { DependencyFetchTarget.GlobalInstance });
}
....
}
Thanks and looking forward to test DryIoc since I've read it's supposed to be the fastest out there
Updated answer:
You may directly use WithUnknownServiceResolvers returning DelegateFactory:
var c = new Container(Rules.Default.WithUnknownServiceResolvers(request =>
new DelegateFactory(_ => GetFromDependencyService(request.ServiceType))));
No need to implement IContainer just for that.
I think it may be optimized regarding performance by replacing DelegateFactory with ExpressionFactory. But I need some time to play with the idea.

Verify method was called with certain linq expression (moq)

Can't figure out the syntax.
//class under test
public class CustomerRepository : ICustomerRepository{
public Customer Single(Expression<Func<Customer, bool>> query){
//call underlying repository
}
}
//test
var mock = new Mock<ICustomerRepository>();
mock.Object.Single(x=>x.Id == 1);
//now need to verify that it was called with certain expression, how?
mock.Verify(x=>x.Single(It.Is<Expression<Func<Customer, bool>>>(????)), Times.Once());
Please help.
Hmmm, you can verify that the lambda is being called by creating a mock for an interface that has a method matching the lambda parameters and verifying that:
public void Test()
{
var funcMock = new Mock<IFuncMock>();
Func<Customer, bool> func = (param) => funcMock.Object.Function(param);
var mock = new Mock<ICustomerRepository>();
mock.Object.Single(func);
funcMock.Verify(f => f.Function(It.IsAny<Customer>()));
}
public interface IFuncMock {
bool Function(Customer param);
}
The above might or might not work for you, depending on what Single method does with the Expression. If that expression gets parsed into SQL statement or gets passed onto Entity Framework or LINQ To SQL then it'd crash at runtime. If, however, it does a simple compilation of the expression, then you might get away with it.
The expression compilation that I spoke of would look something like this:
Func<Customer, bool> func = Expression.Lambda<Func<Customer, bool>>(expr, Expression.Parameter(typeof(Customer))).Compile();
EDIT If you simply want to verify that the method was called with a certain expression, you can match on expression instance.
public void Test()
{
Expression<Func<Customer, bool>> func = (param) => param.Id == 1
var mock = new Mock<ICustomerRepository>();
mock.Object.Single(func);
mock.Verify(cust=>cust.Single(func));
}

How do you test an extension method on an Interface which calls another method in that Interface with a mock created by Rhino Mocks?

I'm testing an extension method on an interface 'ISomeInterface'. The extension method actually calls to another method in the interface.
How do I set up a mock and the appropriate expectations (i want to set the expectation that 'SomeMethod', which is an defined method in the interface with a different signature then this extension method, will be called with 'someDifferentParam')
// Extension Method
public static ISomeInterface SomeMethod(this ISomeInterface someInterface, string someParam)
{
// do work, then call the defined method in the interface
someInterface.SomeMethod(int someDifferentParam)
return someInterface;
}
// tried to do the following but it errors
[Test]
public void SomeMethod_WithSomeInterface_CallsOtherSomeMethod()
{
const string someParam = "something";
const int someOtherParam = 1;
var mock = MockRepository.GenerateMock<ISomeInterface>();
mock.SomeMethod(someParam);
mock.AssertWasCalled(x => x.SomeMethod(someOtherParam));
}
EDIT
I finally got it working, but I'm open to suggestions/criticism. I'm just learning the ins/outs of Rhino Mocks myself =)
here is the real thing that I was testing. Since you can't compare two NHibernate.Criterion.Order objects by doing an Is.Equal or Is.SameAs I had to capture the arguments passed to the method call and then Assert on the ToString of the Order object because there are no public properties exposed on it.
// Extension Method
public static class NHibernateExtensions
{
public static ICriteria AddOrder(this ICriteria criteria, params OrderBy[] orderBys)
{
foreach (var b in orderBys)
{
var arr = b.Property.Split(',');
for (var i = 0; i < arr.Length; i++)
{
criteria.AddOrder(b.Direction == OrderDirection.Ascending
? Order.Asc(arr[i])
: Order.Desc(arr[i]));
}
}
return criteria;
}
}
// here is the test that works
[TestFixture]
public class NHibernateExtensionsTester : TestBase
{
[Test]
public void AddOrder_1OrderBy_CallsAddOrderOnICriteriaWithCorrectOrder()
{
const string testProperty = "SomeProperty";
var expected = (Order.Asc(testProperty)).ToString();
var orderBys = new[]
{
new OrderBy
{
Direction = OrderDirection.Ascending,
Property = testProperty
}
};
var mockCriteria = M<ICriteria>();
mockCriteria.AddOrder(orderBys);
var orderArgument = (Order)((mockCriteria.GetArgumentsForCallsMadeOn(x => x.AddOrder(null)))[0][0]);
Assert.That(orderArgument.ToString(), Is.EqualTo(expected));
}
}
Jon, since in effect you're just testing your extension method I see nothing wrong and this. I tried your code out and worked fine for me. Here is the exact code that I ran (using xunit.net and TD.Net). The test passed.
What error are you getting?