我正在努力解决 ASP.NET 5(vNext)中的一些概念。
其中之一是用于配置的依赖注入方法。好像我必须在堆栈中一直传递一个参数。我可能误解了某些事情或做错了。
想象一下,我有一个名为“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
传递给整个堆栈。这感觉不正确。为了进一步担心,如果我尝试使用需要访问配置设置的第三方库,这种方法将无效。第三方库如何访问配置设置?我误会了什么吗?有更好的方法吗?
答案 0 :(得分:11)
您正在纠缠2个不同的运行时资源提供程序, 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);
依赖注入的目的是管理服务的访问和生命周期。
在上一个示例中,在我们的应用程序Startup
中,我们将DI工厂配置为将IEmailService
的应用程序请求与EmailService
相关联。因此,当我们的控制器由 MVC框架实例化时,框架会注意到我们的Home Controller
期望IEmailService
,框架会检查我们的应用程序服务集合。它找到映射指令并将Singleton
EmailService
(占用接口的后代)注入我们的Home Controller。
Super Polymorphic Factorific - alodocious!
为什么这很重要?
如果您的联系电子邮件发生更改,则更改AppSetting
值并完成。来自ConfigurationManager
的所有“ContactEmail”请求都已全局更改。字符串很容易。我们可以哈希时不需要注射。
如果您的存储库,电子邮件服务,日志记录服务等发生更改,您希望使用全局方式更改对此服务的所有引用。服务引用不像不可变字符串文字那样容易转移。服务实例化应由工厂处理,以配置服务的设置和依赖关系。
所以,在一年中你开发了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>();
}