StructureMap 和通过带有接口的构造函数进行延迟初始化

StructureMap & Lazy Initialization via Constructor with Interfaces

我使用 StructureMap v4.6.1.0 并且我有一个结构,在该结构中我使用构造函数创建了一个实例,我在其中插入了那个 class 的接口,这个 class 通常调用我的在他们使用的服务中有其参数的构造函数

 private readonly IFirstService _firstService;
 private readonly ISecondService _secondService;

 private readonly ILog _log;

 public ProductController(IFirstService firstService, ISecondService secondService, ILog log)
 {
       _firstService = firstService;
       _secondService = secondService;

       _log = log;
 }

 [Route("Default")]
 public ActionResult First()
 {
       var model = _firstService.DoIt();
       return View("~/Views/First/index.cshtml", model);
 }

 [Route("Default")]
 public ActionResult Second()
 {
       var model = _secondService.DoIt();
       return View("~/Views/Second/index.cshtml", model);
 }

这个解决方案的主要问题是我调用 Controller 然后它创建了 2 个实例(一个用于 firstService,第二个用于 secondService),但是我调用这个服务是为了特定的控制器页面方法。

例如,在工厂、日志和存储库加载程序的构造函数接口中调用服务,这意味着当我调用控制器构造函数时,我从两个服务加载所有存储库-

当我使用 Lazy 时,我收到消息,然后调用的过程未定义

我正在寻找最佳的架构解决方案,我尝试了一些 Lazy 和代码优化,但我总是遇到一个问题

编辑:

StructureMap 容器注册

Scan(
    scan =>
    {
           scan.TheCallingAssembly();
           scan.WithDefaultConventions();
           scan.With(new ControllerConvention());
    });

For<ILog>().Use(c => LogManager.GetLogger(GetType())).Singleton();

For<IFirstService>().Use<FirstService>().Singleton();
For<ISecondService>().Use<SecondService>().Singleton();

我的解决方案:

在class构造函数中我使用了StructureMap的接口

private readonly IContainer _container;
private readonly ILog _log;

public ProductController(IContainer container, ILog log)
{
       _container = container;
       _log = log;
}

而在我使用的方法中

var model = _container.GetInstance<IFirstService>().DoIt();

我使用 .NET lib using static System.Web.HttpRuntime; 并在存储库构造函数中调用的方法中使用下面的代码 class

if (!(Cache[_cacheName] is IEnumerable<YourObject> result)) // Cache is empty
            {
                _log.Info("-- Loading from DB --");
                lock (CacheLockObject)
                {
                    result = Cache[_cacheName] as IEnumerable<YourObject>;
                    if (result == null)
                    {
                        result = LoadAll(); // load data from DB
                        Cache.Insert(_cacheName, result, null,
                            DateTime.Now.AddMinutes(10), TimeSpan.Zero);
                    }

                    return result;
                }
            }

            _log.Info("-- Loading from Cache --");
            return result;

谢谢

当前的依赖注入解决方案是使用服务定位器反模式。容器不应作为依赖项传递。这样做是服务定位器的明确指标。

您可以使用 Lazy<T>Func<T>

推迟初始化

例如下面使用Func<T>

private readonly Func<IFirstService> _firstService;
private readonly Func<ISecondService> _secondService;    
private readonly ILog _log;

public ProductController(Func<IFirstService> firstService, Func<ISecondService> secondService, ILog log) {
    _firstService = firstService;
    _secondService = secondService;    
    _log = log;
 }

[Route("Default")]
public ActionResult First() {
    IFirstService service = _firstService();//invoke delegate to get service
    var model = service.DoIt();
    return View("~/Views/First/index.cshtml", model);
}

[Route("Default")]
public ActionResult Second() {
    ISecondService service = _secondService();
    var model = service.DoIt();
    return View("~/Views/Second/index.cshtml", model);
}

Func 充当工厂委托,仅在需要时才延迟 initialization/activation 依赖项。

因此在上面的示例中,如果请求 First(),则只会为该请求调用 _firstService() 委托,而不是两个服务。

你可以用 Lazy<T>

做同样的事情
private readonly Lazy<IFirstService> _firstService;
private readonly Lazy<ISecondService> _secondService;    
private readonly ILog _log;

public ProductController(Lazy<IFirstService> firstService, Lazy<ISecondService> secondService, ILog log) {
    _firstService = firstService;
    _secondService = secondService;    
    _log = log;
 }

[Route("Default")]
public ActionResult First() {
    IFirstService service = _firstService.Value;//lazy load service
    var model = service.DoIt();
    return View("~/Views/First/index.cshtml", model);
}

[Route("Default")]
public ActionResult Second() {
    ISecondService service = _secondService.Value;
    var model = service.DoIt();        
    return View("~/Views/Second/index.cshtml", model);
}

StructureMap Documentation: Lazy Resolution

StructureMap has some built in functionality for "lazy" resolved dependencies, so that instead of your application service taking a direct dependency on IExpensiveToBuildService that might not be necessary, you could instead have StructureMap fulfill a dependency on Lazy<IExpensiveToBuildService> or Func<IExpensiveToBuildService> that could be used to retrieve that expensive service only when it is needed from whatever Container originally created the parent object.