在使用依赖注入(inject)时,我在装饰器模式的实现中遇到了 StackoverflowException。我认为这是因为我对 DI/IoC 的理解“遗漏”了一些东西。
例如,我目前有 CustomerService 和 CustomerServiceLoggingDecorator。这两个类都实现了 ICustomerService,装饰器类所做的只是使用注入(inject)的 ICustomerService 但添加了一些简单的 NLog 日志记录,这样我就可以在不影响 中的代码的情况下使用日志记录CustomerService 同时也不违反单一职责原则。
但是这里的问题是,因为 CustomerServiceLoggingDecorator 实现了 ICustomerService,它还需要注入(inject) ICustomerService 的实现才能工作,Unity将继续尝试将其解析回自身,这会导致无限循环,直到它溢出堆栈。
这些是我的服务:
public interface ICustomerService
{
IEnumerable<Customer> GetAllCustomers();
}
public class CustomerService : ICustomerService
{
private readonly IGenericRepository<Customer> _customerRepository;
public CustomerService(IGenericRepository<Customer> customerRepository)
{
if (customerRepository == null)
{
throw new ArgumentNullException(nameof(customerRepository));
}
_customerRepository = customerRepository;
}
public IEnumerable<Customer> GetAllCustomers()
{
return _customerRepository.SelectAll();
}
}
public class CustomerServiceLoggingDecorator : ICustomerService
{
private readonly ICustomerService _customerService;
private readonly ILogger _log = LogManager.GetCurrentClassLogger();
public CustomerServiceLoggingDecorator(ICustomerService customerService)
{
_customerService = customerService;
}
public IEnumerable<Customer> GetAllCustomers()
{
var stopwatch = Stopwatch.StartNew();
var result = _customerService.GetAllCustomers();
stopwatch.Stop();
_log.Trace("Querying for all customers took: {0}ms", stopwatch.Elapsed.TotalMilliseconds);
return result;
}
}
我目前有这样的注册设置(这个 stub 方法是由 Unity.Mvc 创建的):
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
// Register the database context
container.RegisterType<DbContext, CustomerDbContext>();
// Register the repositories
container.RegisterType<IGenericRepository<Customer>, GenericRepository<Customer>>();
// Register the services
// Register logging decorators
// This way "works"*
container.RegisterType<ICustomerService, CustomerServiceLoggingDecorator>(
new InjectionConstructor(
new CustomerService(
new GenericRepository<Customer>(
new CustomerDbContext()))));
// This way seems more natural for DI but overflows the stack
container.RegisterType<ICustomerService, CustomerServiceLoggingDecorator>();
}
所以现在我不确定实际创建具有依赖注入(inject)的装饰器的“正确”方法。我的装饰器基于 Mark Seemann 的回答 here .在他的示例中,他正在更新几个传递到类中的对象。这就是我的它“工作”* 片段的工作方式。但是,我认为我错过了一个基本步骤。
为什么要像这样手动创建新对象?这是否否定了让容器为我解析的意义?或者我应该在这个方法中执行 contain.Resolve()(服务定位器),以获取仍然注入(inject)的所有依赖项?
我对“复合根”概念略微熟悉,您应该将这些依赖项连接到一个且仅一个位置,然后向下级联到应用程序的较低级别。那么 Unity.Mvc 生成的 RegisterTypes() 是 ASP.NET MVC 应用程序的组合根吗?如果是这样,直接在此处更新对象实际上是正确的吗?
我的印象是,通常使用 Unity 您需要自己创建组合根,但是,Unity.Mvc 是一个异常(exception),因为它创建了自己的组合根,因为它似乎能够在构造函数中将依赖项注入(inject)到具有接口(interface)(例如 ICustomerService)的 Controller 中,而无需我编写代码来实现这一点。
问题:我认为我遗漏了一条关键信息,由于循环依赖,这导致我出现StackoverflowExceptions。如何在仍然遵循依赖注入(inject)/控制反转原则和约定的同时正确实现我的装饰器类?
第二个问题:如果我决定只想在某些情况下应用日志装饰器呢?因此,如果我有 MyController1,我希望有一个 CustomerServiceLoggingDecorator 依赖项,但是 MyController2 只需要一个普通的 CustomerService,如何创建两个单独的注册?因为如果我这样做:
container.RegisterType<ICustomerService, CustomerServiceLoggingDecorator>();
container.RegisterType<ICustomerService, CustomerService>();
然后一个将被覆盖,这意味着两个 Controller 都将注入(inject)装饰器或注入(inject)普通服务。我如何允许两者兼顾?
编辑:这不是一个重复的问题,因为我在循环依赖方面遇到了问题,并且对此缺乏正确的 DI 方法的理解。我的问题适用于整个概念,而不仅仅是像链接问题那样的装饰器模式。
最佳答案
每当您在使用 DI 容器(Unity 或其他)时遇到问题,问问自己:is using a DI Container worth the effort?
在大多数情况下,答案应该是否。使用 Pure DI反而。用 Pure DI 回答你所有的答案都是微不足道的。
如果您必须使用 Unity,也许以下内容会对您有所帮助。自 2011 年以来我就没有使用过 Unity,所以从那以后情况可能发生了变化,但在 my book 的第 14.3.3 节中查找问题。 ,这样的事情可能会成功:
container.RegisterType<ICustomerService, CustomerService>("custSvc");
container.RegisterType<ICustomerService, CustomerServiceLoggingDecorator>(
new InjectionConstructor(
new ResolvedParameter<ICustomerService>("custSvc")));
或者,您也可以这样做:
container.RegisterType<ICustomerService, CustomerServiceLoggingDecorator>(
new InjectionConstructor(
new ResolvedParameter<CustomerService>()));
此替代方案更易于维护,因为它不依赖命名服务,但具有(潜在的)缺点,即您无法通过 ICustomerService 接口(interface)解析 CustomerService .无论如何你可能不应该这样做,所以这应该不是问题,所以这可能是一个更好的选择。
关于c# - 依赖注入(inject)组合根和装饰器模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36048646/
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl