How to inject different instance(s) for different

2020-02-15 08:11发布

We are using classes inheriting from Registry to configure our StructureMap container in our ASP.NET MVC 4 application startup.

Some excerpt from one of the registry-classes:

For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeImplementation>();

We would like use different instances of our interfaces depending on the context. (For example switching from database "online" mode to "maintenance" mode where everything is saved on filesystem; therefore using other interfaces (i.e. repositories) all over the place in our application)

For example by default it should use SomeImplementation but when passing some kind of querystring in the url (to name a simple "context" scenario) it should use SomeOtherImplementation.

How can this be achieved for multiple interfaces/types?

Should we use named instances for this? Like:

For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeOtherImplementation>().Named("other");

I read about StructureMap Profiles but i'm not sure if this is the right way to go. Should we use profiles for this? Like i.e.:

Profile("other", profileExpression =>
  {
     For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeOtherImplementation>();
  });

How can we switch different configurations on the fly?

ObjectFactory.Container.SetDefaultsToProfile("other");

This way? (At what stage in mvc "life-cycle" this can happen at the earliest?)

Can this be a temporary switch for just the current request or current users session?

Thanks in advance!

1条回答
放荡不羁爱自由
2楼-- · 2020-02-15 08:23

From my experience, runtime configuration like this is best achieved using an abstract factory that is responsible for creating your dependency during runtime.

This dependency can then be registered with StructureMap like so:

Your registry:

public class StorageRegistry : Registry
{
    public StorageRegistry()
    {
        ...
        this.For<IDataStoreInstance>().Use(ctx => ctx.GetInstance<DataStoreAbstractFactory>().ConfigureStorage());
        ...
    }
}

Now your DataStoreAbstractFactory is responsible for creating and configure the necessary storage instance based on your configuration. As DataStoreAbstractFactory is now registered with StructureMap you're able to inject the necessary dependencies into it for determining which storage method to use.

Implementation example:

public class DataStoreAbstractFactory
{
    public DataStoreAbstractFactory()
    {
        // Dependencies to figure out data storage method can be injected here.
    }

    public IDataStoreInstance ConfigureStorage()
    {
        // This method can be used to return type of storage based on your configuration (ie: online or maintenance)
    }
}

public interface IDataStoreInstance
{
    void Save();
}

public class DatabaseStorage : IDataStoreInstance
{
    public void Save()
    {
        // Implementation details of persisting data in a database
    }
}

public class FileStorage : IDataStoreInstance
{
    public void Save()
    {
        // Implementation details of persisting data in a file system
    }
}

Usage:

Your controller/services or whatever are now completely unaware of what storage method they're using when accessing and persisting data.

public class UpdateController : Controller
{
    public IDataStoreInstance StorageInstance { get; set; }

    public UpdateController(IDataStoreInstance storageInstance)
    {
        StorageInstance = storageInstance;
    }

    [HttpPost]
    public ActionResult Index()
    {
        ...

        this.StorageInstance.Save();

        ...
    }

    ...

}
查看更多
登录 后发表回答