Specifying constructors for inaccessible instances when using Automapper and Autofac - c#

Scenario
Assume we have a class Target with the following two constructors (one objec, or two objects and an Enum).
public Target(paramOne) { ... }
public Target(paramOne, paramTwo, paramTwoConfigEnum) { ... }
We then have a ClassA which needs to perform a mapping operation from some object to an instance of Target. One version of this would be the following, which relies on existign mapping rules (for automapper), and dependency injection using AutoFac for providing the parameters to perform the mapping. This uses the last of the two constructors above (3 params):
// Behind the scenes this performs a call like: new Target(p1, p2, myEnum)
// with p1, p2 and
var result = _mapper.Map<List<Target>>(someOtherObject);
Next, we have two other classes ClassB, and ClassC. Both of these need to perform similar mapping operations, but here the resulting objects are classes that contain instances of Target; in other words, there is an behind-the-scenes, implicit mapping from someOtherObject into Target here too:
// Behind the scenes this performs calls conceptually similar to the following
// (NB: The second line here will call new Target() with 3 params, as above):
// var x = new ClassContainingTarget(..)
// x.instOfTarget = _mapper.Map<List<Target>>(someOtherObject);
var result = _mapper.Map<ClassContainingTarget>(anotherSourceObject);
The first challenge
For ClassB, the call operation requires values for all three parameters to Target, and values are provided for these via DI.
For ClassC however, paramTwo and paramTwoConfigEnum are not only not needed; they can't be provided via DI in this context. In other words, I what I would like to happen is for the other constructor in Target to be called in this case.
Attempted solution
I realized I can specify which constructor to use when setting up the rules for AutoFac, and override these in specific cases, so I've experimented with the following general setup in my ContainerBuilder:
// This specifies that the constructor that takes a single param of type ParamOne
// should be used by default:
builder.RegisterType<Target>().AsSelf().UsingConstructor(typeof(ParamOne));
With this setup, all the Map() calls above will result in the second (single-param) constructor of Target being used, including in the case of ClassC, where that is exactly what I want.
For the mapping in ClassA then, I can override this logic by replacing the Map() operation shown above with the following:
// Direct manipulation of the rules for mapping to Target, since I'm
// mapping directly to Target. As mentioned below, this does not appear
// to be possible when mapping to classes that contain Target (i.e.
// when Target is mapped implicitly).
result = _mapper.Map<List<Target>>(
someOtherObject,
options =>
options.ConstructServicesUsing(t => new Target(_p1, _p2, myEnum)));
This actualy works in part: Mapping in ClassA causes the 3-param constructor to be called, while that in ClassC causes the 1-param constructor to be called.
Remaining problem
Now the problem remains with ClassB however: I can't see any way to configure it such that it will call the 3-param constructor for Target, since that instantiation and mapping is defined at a lower level, so to speak.
So my question then: Is there any way for me to specify (either from ClassB, or somewhere else) that when Target is instantiated from ClassB, it should use some specific constructor?
Or alternatively, is there some better strategy to get around this problem?

If you want to resolve Target parameters from DI, you'll have to have them registered in container as well (you probably have this, just double-checking):
builder.RegisterType<ParamOne>().AsSelf().UsingConstructor(() => new ParamOne());
builder.RegisterType<ParamTwo>().AsSelf().UsingConstructor(() => new ParamTwo());
builder.RegisterType<ParamTwoEnum>().AsSelf().UsingConstructor(() => ParamTwoEnum.Default);
Then you can use ConstructUsingServiceLocator() as Lucian suggested and a type converter to which you can inject parameters via DI. Mapping configuration:
CreateMap<ClassA, Target>();
CreateMap<ClassB, Target>()
.ConvertUsing<ClassBToTargetTypeConverter>();
CreateMap<ClassC, Target>()
.ConstructUsingServiceLocator();
The ClassBToTargetTypeConverter:
public class ClassBToTargetTypeConverter : ITypeConverter<ClassB, Target>
{
private readonly ParamOne _paramOne;
private readonly ParamTwo _paramTwo;
private readonly ParamTwoEnum _paramTwoConfigParamTwoEnum;
public ClassBToTargetTypeConverter(ParamOne paramOne, ParamTwo paramTwo, ParamTwoEnum paramTwoConfigParamTwoEnum)
{
_paramOne = paramOne;
_paramTwo = paramTwo;
_paramTwoConfigParamTwoEnum = paramTwoConfigParamTwoEnum;
}
public Target Convert(ClassB source, Target destination, ResolutionContext context)
{
return new Target(_paramOne, _paramTwo, _paramTwoConfigParamTwoEnum);
}
}
Summary:
ClassA to Target is mapped normally using source object properties
ClassB to Target is mapped using type converter which in turn construct Target using constructor with three parameters which are resolved from container
ClassC to Target is mapped directly using DI, where Target is registered as to be constructed using constructor with only one parameter
Side note: using Autofac you have the freedom to switch between using the type converter for ClassC or for ClassB and use DI for the other. But! If you were to use default .NET Core DI engine, you'll have to use the type converter for ClassC to Target mapping as DI is designed to be greedy and chooses the constructor with the most parameters it can fill. What that means is if you let .NET Core DI to construct Target by itself having all three parameters registered in service collection, then it would choose constructor with three parameters over constructor with only one parameter, because it's greedy.

I eventually ended up using a different approach to solve this problem. This explains more or less what I did:
Making the second parameter default to null allows this constructor to be used in all cases. Note that I'm leaving out the third parameter altogether; instead, I'll be relying on Automapper to populate it's property instead (that is precisely what I was not able to do originally, and why I was trying to use specific constructors; the next section of code shows how I managed to set that up in th end).
public Target(ParamOne, ParamTwo = null) { ... }
public MyEnumType ConfigEnum {get; set;}
Now when setting upt the mapping from e.g. ClassB to Target, I specify that it should pick up the value for ConfigEnumProp from a value passed in via context (an item with they key "MyConfigEnum"):
// Map to ConfigEnum in Target NOT from the source, but from a value
// passed in via context by the caller:
CreateMap<ClassB, SectionsDTO>()
.ForMember(dest => dest.ConfigEnum,
opt => opt.MapFrom((src, dest, destMember, context) =>
context.Items["MyConfigEnum"]))
This allows me to pass the required enum value as one value when mapping from ClassA...
var result = _mapper.Map<List<Target>>(instanceOfClassA,
options => options.Items["MyConfigEnum"] = valueWhenMappingFromA);
...and as a different value when mapping from ClassB:
var result = _mapper.Map<List<Target>>(instanceOfClassB,
options => options.Items["MyConfigEnum"] = someOtherValue);
Finally, in cases where ParamTwo and ConfigEnum are not required, they can simply be left out - the constructor will work fine and the property will retain its default value (as Enums do) and otherwise be ignored.

Related

How do I set up this unit test to test some types explicitly?

I have a test fixture for my CompositionRoot static class that pretty much just enumerates my Autofac IContainer's services and attempts to instantiate them. If it can instantiate them, that's a test pass. The goal is to ensure I did not forget to register new interfaces with my Autofac container.
However, some types that are registered consume types in their constructors that are not intended to be, or cannot be, registered with Autofac. For example I have a class that takes a string in its constructor. The way I inject this class into my code base is:
Func<string, ITypeThatRequiresAFactory>
Here is my test fixture (using NUnit3 + FluentAssertions):
[TestFixture]
[Parallelizable(ParallelScope.All)]
public class CompositionRootTest
{
private sealed class ConcreteTypeEnumerator : IEnumerable
{
private readonly IContainer _container;
public ConcreteTypeEnumerator()
{
_container = CompositionRoot.Setup();
}
public IEnumerator GetEnumerator()
{
return _container.ComponentRegistry.Registrations
.SelectMany(x => x.Services)
.OfType<TypedService>()
.GetEnumerator();
}
}
[TestCaseSource(typeof(ConcreteTypeEnumerator))]
public void Service_should_be_instantiable(Service service)
{
using var container = CompositionRoot.Setup();
container.Invoking(c => c.ResolveService(service))
.Should().NotThrow()
.And.NotBeNull();
}
}
The test Service_should_be_instantiable will fail when it tries to instantiate the service implementing ITypeThatRequiresAFactory because of that string parameter in its constructor.
How can I refactor my test fixture to:
Express a list of explicitly-tested types
Which are excluded from the list of types tested by Service_should_be_instantiable
And must have a manual test case written to verify they can be resolved (most likely using a special case composite type, like Func<>)?
The goal is to use Autofac's implicit relationship type for automatic factories (Func<>) and possibly other implicit relationships later (like Lazy<>), so a solution requiring me to explicitly register hand-written factories, for instance, is a non-starter.
What you'll need to do is:
Resolve types instead of services so you can exclude the types you want.
Remove duplicates (so if you have two things registered .As<IFoo>() you won't run that test twice).
Exclude Autofac types (because ILifetimeScope and IComponentContext are inherently registered and that shouldn't be part of your tests).
That LINQ looks like:
var exclude = new []
{
typeof(ThingToSkip),
typeof(OtherThingToSkip),
};
// Get all the registrations
// Pull out the services
// Only look at typed (reflection) services
// Get the actual type from the service
// Filter down to unique types
// Exclude the types you don't want to test
// Exclude the Autofac types
var typesToTest = container.ComponentRegistry.Registrations
.SelectMany(x => x.Services)
.OfType<TypedService>()
.Select(t => t.ServiceType)
.Distinct()
.Except(exclude)
.Where(t => !t.FullName.StartsWith("Autofac."));
Your resolve line will change to:
container.Resolve(type);
...because you'll resolve based on a type rather than a service.
I think that should get you where you're going.
Note this won't cover things like...
Open generics
IEnumerable<T>, Func<T>, or any of the other "built-in relationships" supported by Autofac
Anything registered as a lambda
Service location that might be done inside a constructor after resolving an ILifetimeScope or IComponentContext
...and so on. I mean, you probably got that because you're already filtering by TypedService but I figured I'd be explicit. That's the primary reason something like this isn't built into Autofac - folks would assume we have the ability to check all the registrations and that's not really possible.

How to make Ninject use a custom construction logic for a specific type while keeping the resolution process?

I have a class which accepts dependencies as constructor arguments. This class may be inherited by some other classes and due to technical reasons (about constructor order and so) I have to use a factory method and dynamic invocation using Activator.CreateInstance. The factory method is not purely infrastructural, but it has some kind of initialization logic inside.
public class Foo {
protected Foo(IService service, IOtherService otherService) { ... }
...
public Foo Create(Type fooType, params object[] constructorArgs) {
var instance (Foo)Activator.CreateInstance(fooType, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, constructorArgs, null, null); // or something similar...
instance.SetDefaultValues(); // for example...
instance.StartChangeNotifications();
return instance;
}
The possible descendants can take even more dependencies, etc. I would like to still use Ninject to resolve dependencies and create the object tree.
However, using ToMethod binding I have to create to whole sub-tree myself. Is there any way when I could customize only the construction of a specific type in the resolution process?
I'd like to use it like this.
kernel.Bind<ConcreteFoo>().ConstructWith(ctx => Foo.Create(ctx.Request.Service, ctx.Arguments));
where ConstructWith and ctx.Arguments are fictional parts. I hope my problem is clear.
These are your options (with some examples):
ToMethod(ctx => Foo.Create(ctx.Kernel.Get<IDependency>())
ToConstructor(s => new Foo(s.Inject<IDependency1>(), s.Inject<IDependency2>())
WithConstructorArgument(typeof(string), "someParameter") to just specify single arguments and use default resolution for the rest (or other, custom, paremeters)
OnActivation(o => o.SetDefaultValues()) to perform your post-activation logic like SetDefaultValues.
alternatively: OnActivation((IContext ctx, Foo instance) => foo.Initialize(ctx.Kernel.Get<Settings>()))

Using AutoMapper to map Wrapper<T> to T' by convention

I have a service which wraps enum-values in a SafeEnum type, to enable addition of new enum values without breaking the contract.
Here's an example:
public class Customer
{
public int Id { get; set; }
public SafeEnum<CustomerType> Type { get; set; }
}
public class CustomerModel
{
public int Id { get; set; }
public CustomerModelType Type { get; set; }
}
When mapping from Customer to CustomerModel using AutoMapper, is there a way to automatically map from SafeEnum<T> to T', where T is the wrapped type and T' is the matching type in the model?
I know this can be fixed by configuring for each relevant enum-type, but I am looking for a more elegant solution.
I have stumbled with the same problem recently. From what i've gather there is no official support from Automapper for this kind of scenario (there's no mention of generic wrappers or anything similar on the documentation and i couldn't find any web resource with how to do it), but it can be accomplished with a little bit of work.
First you need to create a class that implements the IObjectMapper interface. This interface has two methods IsMatch(ResolutionContext context) and Map(ResolutionContext context, IMappingEngineRunner mapper)
When mapping two objects, the IsMatch method is used internally by Automapper to determine if a given instance of IObjectMapper can be used to map from the source type to the destination type. On the ResolutionContext object you have the SourceType, DestinationType, SourceValue, DestinationValue, an instance of MappingEngine among other things that can help you determine if you can map the two types with your current mapper.
The Map method is responsible for the actual mapping between the two types.
So, on the IsMatch method you should check if the source or destination type are instances of your wrapper class. And then, on the Map method, when mapping from the wrapped value, you could unwrap the value with reflection, and use the mapping engine provided on the ResolutionContext to map the unwrapped value to it's destination type, and then returning it.
Similarly, when mapping from any type to a wrapped type, you could get the type argument of the closed generic wrapper, use the mapping engine provided on the resolution context to map from the source type, to the type enclosed by your generic wrapper, and wrap the result on an instance of the wrapper class of the appropiate type.
Finally, you need to include this mapper when configuring your MappingEngine on the application startup (This doesn't work with with the static method of the Mapper class, since you can't change the default mappers on it), like this:
var configuration = new ConfigurationStore(new TypeMapFactory(), new IObjectMapper[] { new WrapperMapper()}.Union(MapperRegistry.Mappers));
var engine = new MappingEngine(configuration);
The MapperRegistry.Mappers static property is a collection of all the default Automapper mappers. If you don't include these, you'll lose all the default functionality.
Finally, here's a working fiddle:
https://dotnetfiddle.net/vWmRiY
It'll probably need some work to adapt it to your particular use case, but the general idea is there. This could be used to wrap primitive types, complex types, or anything that is supported by automapper.

ResetDefaults() method doesn't work in StructureMap

I'm using StructureMap 2.6.4.0. My primary goal of using it is to simplify my testing. According to StructureMap documentation (here) it has a great feature for temporary mock injection (ObjectFactory.Inject<>()).
Correct me if I'm wrong but here is my understanding of that feature:
You have your code for container configuration in one place with all "real" implementation mapped to their interfaces.
Before every test run you initialize your ObjectFactory based on the same code as your application does.
If any test needs to replace some "real" implementation with a "test" one it injects "test" implpementation with an Inject method on ObjectFactory.
To restore original mapping and to remove injected mocks you need to call ResetDefaults().
And my problem is in 4th step.
Here is a code example, which figures my problem:
public interface IValueProvider
{
string GetValue();
}
public class ValueProvider : IValueProvider
{
public string GetValue()
{
return "Value provider";
}
}
public class TestValueProvider : IValueProvider
{
public string GetValue()
{
return "Test value provider";
}
}
class Program
{
static void Main(string[] args)
{
ObjectFactory.Initialize(x => x.For<IValueProvider>().Use<ValueProvider>());
var valueProvider = ObjectFactory.GetInstance<IValueProvider>();
Console.WriteLine(valueProvider.GetValue());
// I will see expected "Value provider"
ObjectFactory.Inject<IValueProvider>(new TestValueProvider());
valueProvider = ObjectFactory.GetInstance<IValueProvider>();
Console.WriteLine(valueProvider.GetValue());
// I will see expected "Test value provider"
ObjectFactory.ResetDefaults();
valueProvider = ObjectFactory.GetInstance<IValueProvider>();
Console.WriteLine(valueProvider.GetValue());
// I will see NOT expected "Test value provider".
// Doesn't ResetDefaults() have to restore a ValueProvider implementation?
}
}
So, could anybody tell me where I'm wrong? Or maybe it is a bug in StructureMap?
The ResetDefaults() method switches the profile to String.Empty. Which in your case it already was. This doesn't remove plugin types registered through Inject<T>(T object).
The Inject<T>(T object) method registers the object as the default for the PluginType "T". In other words it overrides your current default which was the concrete type ValueProvider.
The documentation of StructureMap is dated so my guess is that in earlier versions it worked the way it's described in the documentation but that is no longer the case.
So use the Inject<T>(T object) method only if you want to override the default of a configured plugin type at run-time or use StructureMap profiles.
StructureMap does provide some ways to remove "eject" types from the container. One of them is:
ObjectFactory.Model.EjectAndRemoveTypes(match =>
match != null &&
match == typeof (TestValueProvider)
);
This code does remove the registration made by the Inject<T>(T object) method but doesn't revert the default instance of type IValueProvider. This means there is no longer a default instance for IValueProvider.
Therefor ObjectFactory.GetInstance<IValueProvider>() will throw an StructureMap Exception Code: 202
No Default Instance defined for PluginFamily ... exception.
ObjectFactory.GetAllInstances<IValueProvider>().First() will give you back the instance of ValueProvider. The one you expect.
I am not really sure what your are trying to test here, but if they are unit-tests you should try to avoid the need for an IoC container (which also means depending on ObjectFactory). If you do need an container use an abstraction of IContainer which you can manage and create yourself. Some links to other SO questions backing this are:
Using StructureMap with unit tests
StructureMap is not reset between NUnit tests

Can't grasp the difference between Freeze/Inject/Register

Before starting, I'm a big fan of AutoFixture, I'm still in the curve of learning how to use the tool. So thanks for having developed Autofixture Mr Ploeh and all the contributors.
So let's start with my question.
According to
AutoFixture/AutoMoq ignores injected instance/frozen mock
The interesting part of the above link is given this code
Mock<ISettings> settingsMock = new Mock<ISettings>();
settingsMock.Setup(s => s.Get(settingKey)).Returns(xmlString);
ISettings settings = settingsMock.Object;
fixture.Inject(settings);
To which Mark answer it can be rewritten to
fixture.Freeze<Mock<ISettings>>()
.Setup(s => s.Get(settingKey)).Returns(xmlString);
It looks like a syntaxic sugar, using Freeze method is a way to write in fluent interface the creation of the mock, the configuration, and the injection in autofixture container.
After doing some research on the web, there're actually a functional difference between Freeze and Inject. I found this question:
https://github.com/AutoFixture/AutoFixture/issues/59
which point the answer to
How can I Freeze a null instance in AutoFixture
The author of the link above describe Freeze method as the following:
Internally, Freeze creates an instance of the requested type (e.g.
IPayPalConfiguration) and then injects it so it will always return
that instance when you request it again
I understand that when we do
var customer = fixture.Freeze<Order>();
it will always use the same instance of Order whenever our code request an Order type. But what if I specify in Freeze constructor that I want it to use a specific instance ?
Here's a little code example:
[Fact]
public void MethodeName()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
fixture.Freeze<OrderLine>(new OrderLine("Foo"));
var order = fixture.Create<Order>();
}
public class Order
{
private readonly OrderLine _line;
public Order(OrderLine line)
{
_line = line;
}
}
public class OrderLine
{
private readonly string _name;
public OrderLine(string name)
{
_name = name;
}
}
Shouldn't the name of OrderLine be equal to "Foo" instead of namefe48163a-d5a0-49a5-b349-7b11ba5f804b ? The documentation of Freeze method say:
<typeparam name="T">The type to freeze.</typeparam>
<param name="fixture">The fixture.</param>
<param name="seed">Any data that adds additional information when creating the anonymous object. Hypothetically, this value might be the value being frozen, but this is not likely.</param>
why is the author not sure when the value is returned ? If I specify, my instance in the constructor of Freeze, I'm expecting autofixture to use this instance ?
then
Please notice that the isn't likely to be used as the frozen value, unless you've customized to do this. If you wish to inject a specific value into the Fixture, you should use the method instead.`
It seems like I have to customize the seed parameter. Can anyone clarify ? The solution pointed by documentation is to use Inject method. And indeed, it works in my code example with OrderLine.
I'm looking for your help to understand the difference between Freeze, Inject, and also Register which, according to the source code, is just called by Inject method but it takes a lambda.
Register and Inject
Once upon a time, there was no Inject and no Freeze; Register ruled the code.
Back then, there was a Register overload defined thusly:
public static void Register<T>(this IFixture fixture, T item)
However, it had to share the API with this close relative:
public static void Register<T>(this IFixture fixture, Func<T> creator)
The creator of AutoFixture thought that this was good, but alas: users were stricken with confusion. Most grievously, a user could write:
fixture.Register(() => universe.LightUp());
but also
fixture.Register(universe.LightUp);
which means the exact same thing, because universe.LightUp is a reference to a method, and thus matches a delegate.
However, that syntax looks like a property reference, so if LightUp had been a property instead of a method, the first overload would be selected by the compiler.
This caused much confusion, so the Register<T>(this IFixture fixture, T item) overload was renamed to Inject<T>(this IFixture fixture, T item).
Freeze
Freeze has a different history. A long time ago, when I still used AutoFixture in an imperative way, I noticed that I repeatedly wrote code like this:
var foo = fixture.Create<Foo>();
fixture.Inject(foo);
So I decided that this was a concept and named it Freeze. The Freeze method is only shorthand for those two lines of code.
I'm looking for your help to understand the difference between Freeze, Inject, and also Register which, according to the source code, is just called by Inject method but it takes a lambda
In general, it shouldn't be too hard to distinguish between Inject and Register, since their signatures don't collide. Thus, if you try to accomplish a goal with one of those two methods, and your code compiles, you probably chose the right version.
This would also be the case for Freeze if it wasn't for the overload used in the OP:
[EditorBrowsable(EditorBrowsableState.Never)]
public static T Freeze<T>(this IFixture fixture, T seed)
Notice that this overload actually has EditorBrowsableState.Never, because it always confuses people. However, despite that, apparently people still find that overload, so I think it should be moved in AutoFixture 4. It's one of those features that exist because it was easy to implement...
Freeze, Inject, and Register all are customizing the creation algorithm.
With Inject and Register you are specifying explicitly that an object should be created in a particular way, in your example by supplying new OrderLine("Foo") manually.
With Freeze you are not specifying how an object should be created - you ask AutoFixture to supply an instance for you.
In the end, all the above methods use the same lower-level API:
fixture.Customize<T>(c => c.FromFactory(creator).OmitAutoProperties());
The reason why fixture.Freeze<OrderLine>(new OrderLine("Foo")); does not create an OrderLine instance with the specified seed value is because by default the seed is ignored.
To favor seed values of a particular type, you can create a SeedFavoringRelay<T>:
public class SeedFavoringRelay<T> : ISpecimenBuilder where T : class
{
public object Create(object request, ISpecimenContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var seededRequest = request as SeededRequest;
if (seededRequest == null || !seededRequest.Request.Equals(typeof(T)))
return new NoSpecimen(request);
var seed = seededRequest.Seed as T;
if (seed == null)
return new NoSpecimen(request);
return seed;
}
}
Then you may use it as below:
fixture.Customizations.Add(
new SeedFavoringRelay<OrderLine>());
fixture.Freeze<OrderLine>(new OrderLine("Foo"));
// -> Now fixture.Create<Order>() creates an Order with OrderLine's Name = "Foo".
I modified your test (which doesn't assert anything currently, BTW) and if you step through its execution, you'll see an OrderLine with "Foo" as its private _line member value is injected into Order.
I had another version of the test where I added readonly properties for OrderLine in Order and Name in OrderLine so that you could make assertions about these objects, but that's neither here nor there.
This test sets up the fixture using the FromFactory method directly, which may be helpful sometimes:
[Fact]
public void MethodName()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
const string expected = "Foo";
fixture.Customize<OrderLine>(o => o
.FromFactory(() =>
new OrderLine(expected)));
var order = fixture.Create<Order>();
}

Categories

Resources