依赖注入:在 ASP.NET Core 中设置和共享作用域服务的属性
Dependency Injection: setting and sharing properties of scoped service in ASP.NET Core
我想在控制器中的一些注入服务中设置 属性 以便稍后在同一请求期间将此服务注入其他地方时滥用它,所以我希望这个 属性 不会改变就服务注入范围而言。
这种方法安全吗?或者您建议如何实现这种行为?
MyController(IServiceWithProperty serviceWithProperty) {
_serviceWithProperty = serviceWithProperty;
}
public IActionResult Get(int settingToSet) {
_serviceWithProperty.SetProperty(settingToSet);
return Ok(_anotherService.GetSomething());
}
正如我所说,AnotherService
也会注入 ServiceWithProperty
。
public class AnotherService : IAnotherService {
public AnotherService(IServiceWithProperty serviceWithProperty) {
_serviceWithProperty = serviceWithProperty;
}
public string GetSomething() {
int prop = _serviceWithProperty.GetProperty(); //here I expect to get property which has been set in controller, would that work and is it fine to do it like that?
}
}
它会起作用,因为这两个服务在请求的生命周期内都是单例,所以 属性 也将保持其价值。
但是我建议不要将这些值作为属性来共享,而是作为服务函数的参数来共享,例如:
public IActionResult Get(int settingToSet)
{
return Ok(_anotherService.GetSomething(settingToSet));
}
public class AnotherService : IAnotherService
{
public AnotherService(ISomeAnotherService service)
{
_service = service;
}
public string GetSomething(int inputValue)
{
int serviceResult = _service.GetSomething(inputValue);
}
}
这使代码更加清晰,并降低了您在 5 个月后调查 属性 在哪里和谁设置了您当时不期望的值的可能性。
一旦代码库的规模变大,这两个服务之间的交互将很难跟踪。即使给出了这个简单的示例(很好地将问题归结为本质,顺便说一句),我也不得不查看代码几分钟以了解发生了什么。
此外,这样的设计似乎接近于违反 Liskov Substitution Principle (LSP),因为它只有在使用特定的具体实现时才会起作用。根据 LSP,您应该能够在不改变系统正确性的情况下将一种子类型与另一种子类型交换。这可能吗?你能用另一个什么都不做的实现替换你想到的 IServiceWithProperty
实现吗?
相反,遵循 Dependency Inversion Principle,客户应该从中定义抽象。所以,如果 MyController
需要一个可以将 int
转换为其他东西的抽象,那么这就是它需要的抽象:
MyController(ITranslator translator) {
_translator = translator;
}
public IActionResult Get(int setting) {
return Ok(_translator.Translate(setting));
}
那么,下一步就是弄清楚如何实现 ITranslator
接口。
我想在控制器中的一些注入服务中设置 属性 以便稍后在同一请求期间将此服务注入其他地方时滥用它,所以我希望这个 属性 不会改变就服务注入范围而言。
这种方法安全吗?或者您建议如何实现这种行为?
MyController(IServiceWithProperty serviceWithProperty) {
_serviceWithProperty = serviceWithProperty;
}
public IActionResult Get(int settingToSet) {
_serviceWithProperty.SetProperty(settingToSet);
return Ok(_anotherService.GetSomething());
}
正如我所说,AnotherService
也会注入 ServiceWithProperty
。
public class AnotherService : IAnotherService {
public AnotherService(IServiceWithProperty serviceWithProperty) {
_serviceWithProperty = serviceWithProperty;
}
public string GetSomething() {
int prop = _serviceWithProperty.GetProperty(); //here I expect to get property which has been set in controller, would that work and is it fine to do it like that?
}
}
它会起作用,因为这两个服务在请求的生命周期内都是单例,所以 属性 也将保持其价值。
但是我建议不要将这些值作为属性来共享,而是作为服务函数的参数来共享,例如:
public IActionResult Get(int settingToSet)
{
return Ok(_anotherService.GetSomething(settingToSet));
}
public class AnotherService : IAnotherService
{
public AnotherService(ISomeAnotherService service)
{
_service = service;
}
public string GetSomething(int inputValue)
{
int serviceResult = _service.GetSomething(inputValue);
}
}
这使代码更加清晰,并降低了您在 5 个月后调查 属性 在哪里和谁设置了您当时不期望的值的可能性。
一旦代码库的规模变大,这两个服务之间的交互将很难跟踪。即使给出了这个简单的示例(很好地将问题归结为本质,顺便说一句),我也不得不查看代码几分钟以了解发生了什么。
此外,这样的设计似乎接近于违反 Liskov Substitution Principle (LSP),因为它只有在使用特定的具体实现时才会起作用。根据 LSP,您应该能够在不改变系统正确性的情况下将一种子类型与另一种子类型交换。这可能吗?你能用另一个什么都不做的实现替换你想到的 IServiceWithProperty
实现吗?
相反,遵循 Dependency Inversion Principle,客户应该从中定义抽象。所以,如果 MyController
需要一个可以将 int
转换为其他东西的抽象,那么这就是它需要的抽象:
MyController(ITranslator translator) {
_translator = translator;
}
public IActionResult Get(int setting) {
return Ok(_translator.Translate(setting));
}
那么,下一步就是弄清楚如何实现 ITranslator
接口。