2

Structuremap experts,

I found this post on stackoverflow ...

Passing constructor arguments when using StructureMap

Someone suggested to use the StructureMap configuration with runtime value like this

For<IProductProvider>().Use<ProductProvider>.Ctor<string>("connectionString").Is(someValueAtRunTime);

But example is not adequate enough to understand its declaration and usage. I try to find on StructureMap site as well but not much help ...

In my situation, I want to pass on the dependency of concrete DbContext (IDbContext) to the constructor of the class with connection string dynamically created during run time within that class.

Community
  • 1
  • 1
microchip78
  • 2,040
  • 2
  • 28
  • 39

2 Answers2

2

Finally I managed to make it working ...

Here how I did it ...

Hope it will help someone, and thanks to PHeiberg for answer me before and showing me right direction.


Interface Definition

public interface ICreditCard
{
    string GetName();
}

public interface IAdditionalCreditCard : ICreditCard
{
}

public class AdditionalCreditCard : IAdditionalCreditCard
{
    private readonly string _name;

    public AdditionalCreditCard(string name)
    {
        _name = name;
    }

    public string GetName()
    {
        return _name;
    }
}

Define function in Structure map config code

Func<string, IAdditionalCreditCard> additionalCreditCard = value =>
  ObjectFactory.With("name").EqualTo(value).GetInstance<AdditionalCreditCard>();

Add following configuration in ObjectFactory.Configure

ObjectFactory.Configure(config =>
{
    config.For<Func<string, IAdditionalCreditCard>>().Use(additionalCreditCard);
});

And in code ...

public class PaymentSystem
{
    private readonly Func<string, IAdditionalCreditCard> _addtionalCreditCard;
    private IAdditionalCreditCard _addCreditCard;

    public PaymentSystem(Func<string, IAdditionalCreditCard> additionalCredit)
    {
        _addtionalCreditCard = additionalCredit;
    }

    public string AddtionalSystemType()
    {
        _addCreditCard = _addtionalCreditCard("American Express");
        return _addCreditCard.GetName();
    }
}

microchip78
  • 2,040
  • 2
  • 28
  • 39
1

The code you are posting is supposed to go in the setup code for StructureMap, which can go in the Initialize/Configure method or a Registry. The setup code is normally executed only once in the application's life cycle. So if you know the connection string value when the application is stared and you configure StructureMap, you can put the code you posted in the initialization of StructureMap. If the value is not known until later on, you need some kind of factory approach.

A factory approach could be done like this (in your StructureMap configuration code):

Func<string, IDbContext> createContext = value => { 
    /* create context based on value */ 
};
ObjectFactory.Initialize(c => {
    For<Func<string, IDbContext>>().Use(createContext);  
    // The rest of you configuration ...
});

You can now use the Func to create an instance of the context when you need it:

public class ProductProvider : IProductProvider
{
    private readonly Func<string, IDbContext> _contextCreator;
    public ProductProvider(Func<string, IDbContext> contextCreator)
    {
        _contextCreator = contextCreator;
    }

    public IEnumerable<Product> GetProducts(string someValue)
    {
        using(var context = contextCreator(someValue))
        {
            return SomeOperationOnThe(context);
        }
    }
}
PHeiberg
  • 29,411
  • 6
  • 59
  • 81
  • @pheiberg and microship78 thank you for posting this helpful answer. but in the latest version of structure map objectfactory has been dropped can you please provide an update to the answer for the latest structuremap lib. thank you very much – wandos Mar 28 '17 at 18:52
  • @Pheiberg i have another question please in the Func createContext = value => {// create dbcontext } how i am going to initialize the dbcontext if in the constructor of the class the dbcontext require a connection string? – wandos Mar 28 '17 at 20:45