0

I'm using DryIoc and ExpressMapper.

I wrap ExpressMapper inside another class and at some point it should be use to map to a type with a parametrized constructor. Actually it's when I map a view model to a business model. The parameter is an instance of a repository class.

Using TDD, my Mapper class cended up like this (note the constructor accepting a Func).

public class Mapper<T1, T2> : IMapper<T1, T2>
{
    private readonly MappingServiceProvider _mapper;

    public Mapper()
    {
        _mapper = new MappingServiceProvider();
        _mapper.Register<T1, T2>();
    }

    public Mapper(Func<T2> func)
    {
        _mapper = new MappingServiceProvider();
        _mapper.Register<T1, T2>().Instantiate((t1) => func());
    }

    public T2 Map(T1 t)
    {
        return _mapper.Map<T1, T2>(t);
    }
}

Thus I tried to use the Ioc like this :

        Func<IActivitiesModel>factoryActivitiesModel = () => container.Resolve<IActivitiesModel>();
        container.Register(Made.Of(() => factoryActivitiesModel));
        // () => new ActivitiesModel(container.Resolve<IActivityRepository>(IfUnresolved.Throw)
        container.Register<IMapper<ActivitiesViewModel, IActivitiesModel>, Mapper<ActivitiesViewModel, IActivitiesModel>>(Reuse.Singleton, Made.Of(
            () => new Mapper<ActivitiesViewModel, IActivitiesModel>(Arg.Of<Func<IActivitiesModel>>())
        ));

But it didn't do.

Unable to use null factory object with factory method ActivitiesMVC.Ioc.<>c__DisplayClass4_0::System.Func`1[ActivitiesLogic.Models.IActivitiesModel] factoryActivitiesModel when resolving: Func<ActivitiesLogic.Models.IActivitiesModel>.

Anyway, I tried different approaches afterward but none seemed to work.

I'd like to avoid to store the container as a static singleton and having the mapper relies on it (I'd like the mapper to remain Ioc agnostic).

How can it be achieved?

EDIt : current solution (with bad static singleton)

public class Ioc
{
    public class Factory<T> : IFactory<T>
    {
        public T Create()
        {
            return Container.Resolve<T>();
        }
    }

    private static Lazy<Container> _container;

    public static Container Container => _container.Value;

    static Ioc()
    {
        _container = new Lazy<Container>(GetContainer);
    }

    static private Container GetContainer()
    {
        var container = new Container(rules => rules
            //.WithoutThrowOnRegisteringDisposableTransient()
            .WithTrackingDisposableTransients());
        container.Register(Made.Of(() => new ActivityController(Arg.Of<IMapper<ActivitiesViewModel, IActivitiesModel>>())));
        container.Register<ILabContext, LabContext>(new SingletonReuse());
        container.Register<IActivityRepository, ActivityRepository>(new SingletonReuse());
        container.Register<IActivitiesModel>(made: Made.Of(() => new ActivitiesModel(Arg.Of<IActivityRepository>())));
        container.Register(typeof(IFactory<>), typeof(Factory<>), new SingletonReuse());
        container.Register<IMapper<ActivitiesViewModel, IActivitiesModel>, Mapper<ActivitiesViewModel, IActivitiesModel>>(Reuse.Singleton, Made.Of(
            () => new Mapper<ActivitiesViewModel, IActivitiesModel>(Arg.Of<IFactory<IActivitiesModel>>())
        ));
        container.Register<IMapper<ActivitiesModel, ActivitiesEntity>, Mapper<ActivitiesModel, ActivitiesEntity>>(new SingletonReuse(), Made.Of(
            () => new Mapper<ActivitiesModel, ActivitiesEntity>()
        ));

        return container;
        ;
    }
}
Serge Intern
  • 2,669
  • 3
  • 22
  • 39

1 Answers1

1

First, I am not familiar with ExpressMapper, so will try to help based on your sample code alone.

As I understood you want to register activities model, repository, vm, etc., as well as IMapper / Mapper implementation which relies on Func dependency. Another detail is mapper has two constructors, that why you probably tried to use Made.Of.

But Made.Of works with Expression>, not with Func delegate. That is the reason for exception I believe.

Try this setup:

container.Register(typeof(IMapper<,>), typeof(Mapper<,>), Reuse.Singleton,
    // will select second constructor with Func parameter
    made: FactoryMethod.ConstructorWithResolvableArguments);

// normal model registrations, no need to use Made.Of
// if implementations have single constructor,
// othetwise try use the same made as for Mapper.
container.Register<IActivitiesModel, ActivitiesModel>();
// ... the same way register repository, vm, etc. 

If the situation with multiple constructors is common in your code (May be it is a requirement of ExpressMapper to have a default ctor?) Then you may configure automatic constructor selection globally per container:

container = new Container(rules => rules
    .With(FactoryMethod.ConstructorWithResolvableArguments));
dadhi
  • 4,807
  • 19
  • 25
  • Additionally, you may register MappingServiceProvider in container as well, and add corresponding parameter to Mapper constructor. – dadhi Mar 03 '16 at 20:23
  • The issue then is the parameter of the constructor isn't an ActivitiesModel but a (factory-like) Func which returns a new ActivitiesModel each times. I think I could create a Factory class which relies on the container instance but then I'll have to make the container instance accessible from there (feels like static singleton would be the only way). Is there any way to pass arround some specific object (here the container itself) with DryIoc. – Serge Intern Mar 04 '16 at 07:58
  • Func is naturally supported by DryIoc, as well as other wrappers: https://bitbucket.org/dadhi/dryioc/wiki/Wrappers. – dadhi Mar 04 '16 at 10:15
  • It is not a good practice to use container / resolver directly, as you've mentioned. But just in case IResolver, IRegistrator and IContainer are automatically injected as parameters starting from DryIoc 2.2. Here is the more details: https://bitbucket.org/dadhi/dryioc/wiki/RulesAndDefaultConventions#markdown-header-container-interfaces But I do not see why it may be required in your case. – dadhi Mar 04 '16 at 10:18
  • Because, what need to be injected is a factory (be it a Func or a some actual factory pattern implementation). NOTE: Register is a function of DryIoc and ExpressMapper (I hope it didn't cause confusion). – Serge Intern Mar 04 '16 at 11:02