具有接口的构造函数的StructureMap和延迟初始化
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了具有接口的构造函数的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作为参数吗?
- 我可以将Cache用于存储库中的只读数据吗?
- 另一种方法?
当我使用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();
- 我可以将Cache用于存储库中的只读数据吗?
我使用.NET lib使用静态System.Web.HttpRuntime;并在存储库类的构造函数中调用的方法中使用下面的代码
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
充当工厂代表,只有在需要时才会延迟依赖项的初始化/激活。
因此,在上面的示例中,如果请求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具有一些内置的“懒惰”已解析依赖项功能,因此您可以使用可以用于检索的
IExpensiveToBuildService
或Lazy<IExpensiveToBuildService>
依赖于结构映射,而不是您的应用程序服务直接依赖于Func<IExpensiveToBuildService>
。只有在最初创建父对象的任何Container需要它时才需要昂贵的服务。
以上是关于具有接口的构造函数的StructureMap和延迟初始化的主要内容,如果未能解决你的问题,请参考以下文章
如何使用StructureMap的AutoMocker模拟没有接口的类?