Autofac子依赖链注册
题
如何构造AutoFac ContainerBuilder,以便正确解析我的子依赖关系(假设接口的多个具体实现)? 默认注册/解析将不起作用,因为我有多个子依赖项的具体实现,并且子依赖项解析依赖于主对象的分辨率。 在所有情况下,我希望使用构造函数注入。
脚本
例如,假设我需要打印收据,因此我创建了一个名为IReceipt的接口,其中一个方法称为PrintReceipt()。
但我需要打印3种收据
- 标准收据
- 礼品收据
- 电子邮件收据
所有收据类型都有不同的格式,电子邮件收据根本不打印,而是通过电子邮件发送。 所以我希望我的IReceipt能够依赖格式化器和处理器。 假设我使用Process()方法创建IProcessor,它可以是打印机处理器,也可以是电子邮件处理器(打印机处理器负责打印机通信,电子邮件处理器负责与SMTP服务器通信) 。 此外,我创建了一个IFormatter,它可以将输入提供给处理器对象,格式化为标准收据,或礼品收据,甚至是电子邮件收据的HTML。 因此,关于IReciept的任何具体实现的构造函数现在需要两个依赖项–IFormatter和IProcessor。
现在,根据我需要决定的根构成,我是否正在解决用于标准收据,礼品收据或电子邮件收据的IReceipt。 我想调用容器Resolve()方法传递必要的参数,以便它解析正确的IReceipt。 此外,我希望注册ContainerBuilder知道,如果我尝试解决IReceipt标准收据的具体实现,它需要使用正确的标准收据IFormatter解决子依赖关系,并更正标准收据IProcessor。 对于礼品收据方案和电子邮件收据方案也是如此。
概括
所以 – 在所有这些 – 我的问题是 – 我如何构造ContainerBuilder,以便在设计时定义子依赖,并且单次调用Resolve()将正确识别所需的具体实现? 我不是在寻求与打印机对话或发布HTML的解决方案。 此问题严格适用于Autofac注册和解决方法。 在不同的客户端,我使用CastleWindsor使用了这个确切的策略,但我当前的客户端使用的是Autofac。
好的,所以我想出了一种执行子依赖链接的方法。 同样,希望每个根组合对象调用一次解析,并使所有子依赖关系满足整个链。 不打算就最佳实践进行宗教辩论 – 无论是否应实施工厂方法,服务定位器等。 我故意遗漏了IoC范围,因为它不是我原来问题的主题。
这个人为的例子没有实现电子邮件或打印机function,但它现在已被删除。 重点是展示如何预定义整个依赖关系链。 现在,自动化unit testing将更容易实现。
码
主体计划
using System; using System.Collections.Generic; using Autofac; namespace MyAutoFacTest { class Program { static void Main(string[] args) { // CREATE THE IOC ENGINE AND CONTAINER var builder = new Autofac.ContainerBuilder(); Autofac.IContainer container; // CREATE THE DEPENDENCY CHAIN REGISTRATION builder.RegisterType() .Named("My Default Printer"); builder.RegisterType() .Named("PrinterProcessor") .WithParameter(Autofac.Core.ResolvedParameter.ForNamed("My Default Printer")); builder.RegisterType() .Named("EmailProcessor"); builder.RegisterType() .Named("StandardReceiptFormatter"); builder.RegisterType() .Named("GiftReceiptFormatter"); builder.RegisterType() .Named("EmailReceiptFormatter"); builder.RegisterType() .Named("StandardReceipt") .WithParameter(Autofac.Core.ResolvedParameter.ForNamed("PrinterProcessor")) .WithParameter(Autofac.Core.ResolvedParameter.ForNamed("StandardReceiptFormatter")); builder.RegisterType() .Named("GiftReceipt") .WithParameter(Autofac.Core.ResolvedParameter.ForNamed("PrinterProcessor")) .WithParameter(Autofac.Core.ResolvedParameter.ForNamed("GiftReceiptFormatter")); builder.RegisterType() .Named("EmailReceipt") .WithParameter(Autofac.Core.ResolvedParameter.ForNamed("EmailProcessor")) .WithParameter(Autofac.Core.ResolvedParameter.ForNamed("EmailReceiptFormatter")); // COMPILE THE AUTOFAC REGISTRATION container = builder.Build(); // SETUP INITIALIZATION STUFF - THINGS THAT WOULD ORDINARILY HAPPEN AS PART OF EXTERNAL SYSTEMS INTEGRATION int someBogusDatabaseIdentifier = 1; var standardReceipt = container.ResolveNamed("StandardReceipt"); standardReceipt.PrintReceipt(someBogusDatabaseIdentifier); var giftReceipt = container.ResolveNamed ("GiftReceipt"); giftReceipt.PrintReceipt(someBogusDatabaseIdentifier); var emailReceipt = container.ResolveNamed ("EmailReceipt"); emailReceipt.PrintReceipt(someBogusDatabaseIdentifier); Console.ReadLine(); } } }
接口
IPrinter
namespace MyAutoFacTest { public interface IPrinter { void Print(); } }
IReceipt
namespace MyAutoFacTest { public interface IReceipt { void PrintReceipt(int id); } }
IProcessor
namespace MyAutoFacTest { public interface IProcessor { void Process(string formattedString); } }
IFormatter
namespace MyAutoFacTest { public interface IFormatter { string GetFormattedString(int id); } }
具体实施
将首先显示叶依赖…
打印机
using System; namespace MyAutoFacTest { public class Printer : IPrinter { public void Print() { Console.WriteLine("Printer is printing"); } } }
打印机处理器
using System; namespace MyAutoFacTest { public class PrinterProcessor : IProcessor { private IPrinter _printer; public PrinterProcessor(IPrinter printer) { this._printer = printer; } public void Process(string formattedString) { Console.WriteLine("Printer processor sending receipt to printer."); this._printer.Print(); } } }
邮件处理器
using System; namespace MyAutoFacTest { public class EmailProcessor : IProcessor { public void Process(string formattedString) { Console.WriteLine("Email Processor sending out an email receipt"); } } }
标准收据格式化程序
namespace MyAutoFacTest { public class StandardReceiptFormatter : IFormatter { public string GetFormattedString(int id) { return "StandardReceiptFormatter formatted string"; } } }
礼品收据格式化程序
namespace MyAutoFacTest { public class GiftReceiptFormatter : IFormatter { public string GetFormattedString(int id) { return "GiftReceiptFormatter formatted string"; } } }
电子邮件收据格式化程序
namespace MyAutoFacTest { public class EmailReceiptFormatter : IFormatter { public string GetFormattedString(int id) { return "EmailReceiptFormatter formatted string"; } } }
收据
using System; namespace MyAutoFacTest { public class Receipt : IReceipt { private IFormatter _formatter; private IProcessor _processor; public Receipt(IFormatter formatter, IProcessor processor) { this._formatter = formatter; this._processor = processor; } public Receipt(IFormatter formatter) { this._formatter = formatter; } public Receipt(IProcessor processor) { this._processor = processor; } public void PrintReceipt(int id) { var formattedString = this._formatter.GetFormattedString(id); Console.WriteLine(formattedString); this._processor.Process(formattedString); } } }
结论
与需要创建的对象相关联的大多数噪声被捆绑到一个位置。 在实践中,我可能会将注册移动到自己的代码块(也许是静态类)。 将噪声排除在函数类之外会产生漂亮的干净代码,并且关注function意图。 所有的电汇都是在这个过程的早期,现在已经不在了。
特别是看注册,我设计的例子有4层依赖。
- 主要
- 收据对象
- 处理器和格式化程序
- 打印机(仅用于打印机处理器)(可能表示电子邮件服务器依赖,但我认为这个例子相当清楚)。
通过使用Autofac.Core.ResolvedParameter,我们可以引用其他注册对象(按名称)。 这将保持注册时间长,但持平。 任何层次结构都表示(浅 – 如果这是一个单词)仅作为父子,并且非常可重用。 Resolve仅在根组合对象上调用 – 3个收据引擎(标准,礼品和电子邮件)。 对于每个根组合对象,整个依赖关系链现在都是可解析的。
上述就是C#学习教程:Autofac子依赖链注册分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1038682.html