其中之一是用于配置的依赖注入方法.似乎我必须通过一个参数通过堆栈.我可能误会某事或做错了.
想象一下,我有一个名为“contactEmailAddress”的配置属性.当订购新订单时,我将使用该配置属性发送电子邮件.考虑到这种情况,我的ASP.NET 5堆栈将如下所示:
Startup.cs
public class Startup { public IConfiguration Configuration { get; set; } public Startup(IHostingEnvironment environment) { var configuration = new Configuration().AddJsonFile("config.json"); Configuration = configuration; } public void ConfigureServices(IServiceCollection services) { services.Configure<AppSettings>(Configuration.GetSubKey("AppSettings")); services.AddMvc(); } public void Configure(IApplicationBuilder app) { app.UseErrorPage(); app.UseMvc(routes => { routes.MapRoute("default","{controller}/{action}/{id}",defaults: new { controller = "Home",action = "Index" }); } ); app.UseWelcomePage(); }
AppSettings.cs
public class AppSettings { public string ContactEmailAddress { get; set; } }
config.json
{ "AppSettings": { "ContactEmailAddress":"support@mycompany.com" } }
OrderController.cs
[Route("orders")] public class OrdersController : Controller { private IOptions<AppSettings> AppSettings { get; set; } public OrdersController(IOptions<AppSettings> appSettings) { AppSettings = appSettings; } [HttpGet("new-order")] public IActionResult OrderCreate() { var viewmodel = new Orderviewmodel(); return View(viewmodel); } [HttpPost("new-order")] public IActionResult OrderCreate(Orderviewmodel viewmodel) { return new HttpStatusCodeResult(200); } }
Order.cs
public class Order() { public void Save(IOptions<AppSettings> appSettings) { // Send email to address in appSettings } public static List<Order> FindAll(IOptions<AppSettings> appSettings) { // Send report email to address in appSettings return new List<Order>(); } }
正如上面的例子所示,我将AppSettings传递给整个堆栈.这听起来不正确.为了进一步担忧,如果我尝试使用需要访问配置设置的第三方库,则此方法将无法正常工作.第三方库如何访问配置设置?我误会了吗?有没有更好的方法来做到这一点?
解决方法
AppSettings提供运行时访问应用程序特定的值,如UICulture字符串,联系人电子邮件等.
DI容器是管理对服务及其终生范围的访问的工厂.例如,如果MVC控制器需要访问您的EmailService,您将进行配置
public void ConfigureServices(IServiceCollection services) { // Add all dependencies needed by Mvc. services.AddMvc(); // Add EmailService to the collection. When an instance is needed,// the framework injects this instance to the objects that needs it services.AddSingleton<IEmailService,EmailService>(); }
然后,如果我们的家庭控制器需要访问您的EmailService,我们通过将它作为参数添加到Controller构造函数中来添加对它的接口的依赖
public class HomeController : Controller { private readonly IEmailService _emailService; private readonly string _emailContact; /// The framework will inject an instance of an IEmailService implementation. public HomeController(IEmailService emailService) { _emailService = emailService; _emailContact = System.Configuration.ConfigurationManager. AppSettings.Get("ContactEmail"); } [HttpPost] public void EmailSupport([FromBody] string message) { if (!ModelState.IsValid) { Context.Response.StatusCode = 400; } else { _emailService.Send(_emailContact,message);
依赖注入的目的是管理服务的访问和使用寿命.
在上一个示例中,在我们的应用程序启动中,我们配置了DI Factory,将IEmailService的应用程序请求与EmailService相关联.所以当我们的控制器被MVC框架实例化时,框架注意到我们的家庭控制器期望IEmailService,框架检查我们的应用服务集合.它找到映射指令,并将一个Singleton EmailService(占位接口的后代)注入我们的主控制器.
超多形态因子 – 有恶心!
为什么这很重要?
如果您的联系人电子邮件更改,您更改AppSetting值并完成.来自ConfigurationManager的“ContactEmail”的所有请求都将全局更改.字符串很容易当我们可以只是哈希时,不需要注入.
如果您的存储库,电子邮件服务,日志记录服务等更改,您希望Global方式更改对此服务的所有引用.服务引用不像不可变字符串文字那样容易地传输.服务实例化应由工厂处理以配置服务的设置和依赖关系.
所以,在一年中你开发一个RobustMailService:
Class RobustMailService : IEmailService { .... }
只要您的新RobustMailService继承并实现了IEmailService接口,您可以通过更改以下方式替换全局邮件服务的所有引用:
public void ConfigureServices(IServiceCollection services) { // Add all dependencies needed by Mvc. services.AddMvc(); // Add RobustMailService to the collection. When an instance is needed,// the framework injects this instance to the objects that needs it services.AddSingleton<IEmailService,RobustMailService>(); }