Configuring StructureMap to generate and “remember” a constructor param literal

ぐ巨炮叔叔 提交于 2020-01-05 07:58:28

问题


I have a StructureMap config that looks something like:

cfg.For<ICacheOrder>().Use<CacheOrder>().Ctor<int>().Is(context => LoginHelper.LoginID);
cfg.For<ICacheProduct>().Use<CacheProduct>().Ctor<int>().Is(context => LoginHelper.LoginID);
cfg.For<ISQLOrder>().Use<SQLOrder>().Ctor<int>().Is(context => LoginHelper.LoginID);
cfg.For<ISQLProduct>().Use<SQLProduct>().Ctor<int>().Is(context => LoginHelper.LoginID);

Via constructor injection, a chain of objects can be created, with some needing an int LoginID that is determined at the time of creation. The static LoginHelper determines the LoginID.

Presently in my config, LoginHelper is called for every created object. Is there a way, perhaps via StructureMap's IContext, for LoginID to be "remembered" and only determined once within a chain of creation?

I know that I could refactor and create an ILogin interface/concrete that StructureMap could construct and cache - but I'd prefer my various layers to be concerned only with a simple int LoginID.


回答1:


Although it's okay to inject primitive configuration values in your services, when you repetitively inject that same primitive into multiple services, you are missing an abstraction.

This is clearly the case with your configuration; you are missing an abstraction.

The solution is to let those services depend on an abstraction rather than a primitive value. For instance:

public interface ICurrentUser
{
    int LoginID { get; }
}

And you can create a rather simple implementation as follows:

public class CurrentUserImpl : ICurrentUser
{
    public CurrentUserImpl()
    {
        this.LoginID = LoginHelper.LoginID;
    }

    public int LoginID { get; private set; }
}

This means that you will have to change the constructors of CacheOrder, CacheProduct, SQLOrder and SQLProduct, but when you do this, your configuration gets much more maintainable:

cfg.For<ICacheOrder>().Use<CacheOrder>();
cfg.For<ICacheProduct>().Use<CacheProduct>();
cfg.For<ISQLOrder>().Use<SQLOrder>();
cfg.For<ISQLProduct>().Use<SQLProduct>();

The problem of "remembering a param literal" now goes away immediately, because we can now register the ICurrentUser as follows:

cfg.For<ICurrentUser>().Use<CurrentUserImpl>();

The default lifecycle in Structure Map is per request (per object graph) so the same instance is injected into all objects in a single object graph.

Another option is to register it using the HttpContext lifecycle, but this of course only works when running an ASP.NET web application.



来源:https://stackoverflow.com/questions/16652839/configuring-structuremap-to-generate-and-remember-a-constructor-param-literal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!