5

We're migrating from StructureMap to Lamar but I could not find the "Lamar version" for passing arguments at runtime.

We have a class that requires a string argument (pseudo code):

public class MyRepository {
  public MyRepository(string accountId) {}
}

… and a factory

public class MyRepoFactory(Container container) {
  public MyRepository GetRepositoryForAccount(string accountId) => 
     container
        // With() is not available in Lamar?
        .With("accountId").EqualTo(accountId)
        .GetInstance<IMyRepository>();
}

In reality there are additional dependencies.

How can a say Lamar GetInstance() for IMyRepository and use value xy for constructor argument named accountId?

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Christoph Lütjen
  • 5,403
  • 2
  • 24
  • 33

2 Answers2

2

I see two approaches with Lamar.

Using properties

While Lamar doesn't offer With(), a workaround might be to make the account a property you set in the factory method, or to have the factory simply get all the repository's dependencies manually from the container. It is, after all, a factory, so tying it closely to the type it produces seems fine from a design standpoint.

Using Contexts

A nicer approach might be to set the accountId in a context and use the context in the repository:

public class ExecutionContext
{
    public Guid AccountId { get; set; } = Guid.NewGuid();
}

The repository looks like this

public class MyRepository
{
    public ExecutionContext Context { get; }

    public MyRepository(ExecutionContext context)
    {
        Context = context;
    }
}

Make the context injectable...

var container = new Container(_ =>
{
    _.Injectable<ExecutionContext>();
});

and then, in your factory...

public MyRepository GetRepositoryForAccount(string accountId) {
    var nested = container.GetNestedContainer();
    var context = new ExecutionContext{ AccountId = accountId };
    nested.Inject(context);
    return nested.GetInstance<IMyRepository>()
}

Documentation: https://jasperfx.github.io/lamar/documentation/ioc/injecting-at-runtime/

You also might want to consider if you really need the factory in this scenario, of if using the nested, injectable container directly perhaps makes for a cleaner design.

adhominem
  • 1,104
  • 9
  • 24
  • Thanks @adhominem. While this answer shows good ways to solve the problem, I'm still hoping that someone has an "as easy as it was with StructureMap" solution. – Christoph Lütjen Dec 14 '18 at 12:15
0

Rude but easy solution could be next code:

var type = container.Model.DefaultTypeFor(typeof(IMyRepository));
var constructor = type.GetConstructor(new[] { typeof(string) });
var instance = constructor.Invoke(new object[] { accountId });
return (IMyRepository)instance;