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

时间:2018-09-07 08:35:40

标签: c# asp.net-mvc architecture lazy-loading structuremap

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

 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),但是我为特定的控制器页面方法调用此服务。

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

  • 我可以使用C#.NET Lazy(T)还是Func?
  • 我可以在所选页面的方法中使用interface作为参数吗?
  • 我可以将缓存用于存储库中的只读数据吗?
  • 另一种解决方案?

当我使用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();

我的解决方案:

  • 我可以在所选页面的方法中使用interface作为参数吗?

在类构造函数中,我使用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();
  • 我可以将缓存用于存储库中的只读数据吗?

我使用静态System.Web.HttpRuntime;的.NET库 ,并在存储库类的构造函数中调用的方法中使用以下代码

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;

谢谢

1 个答案:

答案 0 :(得分:2)

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

您可以使用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充当工厂委托,仅在需要时才延迟依赖项的初始化/激活。

因此在上面的示例中,如果请求了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具有一些内置功能,可以解决“懒惰”的已解决依赖关系,因此,您的应用程序服务可以代替让结构映射实现对{{ 1}}或IExpensiveToBuildService,仅当需要从最初创建父对象的任何Container中获取该昂贵的服务时,才可以使用它。