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),但是我调用这个服务是为了特定的控制器页面方法。
例如,在工厂、日志和存储库加载程序的构造函数接口中调用服务,这意味着当我调用控制器构造函数时,我从两个服务加载所有存储库-
- 我可以使用 C#.NET Lazy(T) 或 Func 吗?
- 我可以在所选页面的方法中使用接口作为参数吗?
- 我可以对存储库中的只读数据使用缓存吗?
- 另一个解决方案?
当我使用 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.
我使用 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),但是我调用这个服务是为了特定的控制器页面方法。
例如,在工厂、日志和存储库加载程序的构造函数接口中调用服务,这意味着当我调用控制器构造函数时,我从两个服务加载所有存储库-
- 我可以使用 C#.NET Lazy(T) 或 Func 吗?
- 我可以在所选页面的方法中使用接口作为参数吗?
- 我可以对存储库中的只读数据使用缓存吗?
- 另一个解决方案?
当我使用 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 onLazy<IExpensiveToBuildService>
orFunc<IExpensiveToBuildService>
that could be used to retrieve that expensive service only when it is needed from whatever Container originally created the parent object.