我在玩依赖注入设计模式,在这种模式中存在一个短暂的生存期,它在每个请求上创建一个新对象。然而,当我尝试将它应用于C#的启动示例WebApi时,它似乎并没有像预期的那样工作。例如,它生成相同的随机数,而原始请求在每个请求上生成一个随机整数。我有两个问题
- 为什么它没有像我预期的那样运行
- 容器如何知道
WeatherForecastController
类需要一个类型为IWeatherForecast
的实例,该实例为用于IEnumerable<IWeatherForecast> Get()
方法?否则,我会得到以下错误
System.InvalidOperationException: Unable to resolve service for type 'WebApplication2.IWeatherForecast' while attempting to activate 'WebApplication2.Controllers.WeatherForecastController'.
WeatherForecastController.cs
using Microsoft.AspNetCore.Mvc;
namespace WebApplication2.Controllers;
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly IWeatherForecast _weatherForecast;
public WeatherForecastController(IWeatherForecast weatherForecast)
{
_weatherForecast = weatherForecast;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<IWeatherForecast> Get()
{
var returnValue= Enumerable.Range(1, 5).Select(index => _weatherForecast).ToArray();
return returnValue;
/*
nearly original one, working as expected
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = "testing"
})
.ToArray();
*/
}
}
WeatherForecast.cs
namespace WebApplication2;
public class WeatherForecast : IWeatherForecast
{
public WeatherForecast()
{
Date = DateTime.Now.AddDays(0);
TemperatureC = Random.Shared.Next(-20, 55);
Summary = "testing";
}
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF() => 32 + (int)(TemperatureC / 0.5556);
}
public interface IWeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF();
}
Program.cs,仅注册
...
builder.Services.AddTransient<IWeatherForecast, WeatherForecast>();
...
它确实按预期工作。
两个请求会给你不同的结果:
请求1:
[
{
"date": "2022-10-09T09:01:36.408982+02:00",
"temperatureC": 4,
"summary": "testing"
},
{
"date": "2022-10-09T09:01:36.408982+02:00",
"temperatureC": 4,
"summary": "testing"
},
{
"date": "2022-10-09T09:01:36.408982+02:00",
"temperatureC": 4,
"summary": "testing"
},
{
"date": "2022-10-09T09:01:36.408982+02:00",
"temperatureC": 4,
"summary": "testing"
},
{
"date": "2022-10-09T09:01:36.408982+02:00",
"temperatureC": 4,
"summary": "testing"
}
]
请求2:
[
{
"date": "2022-10-09T09:02:01.6052197+02:00",
"temperatureC": 46,
"summary": "testing"
},
{
"date": "2022-10-09T09:02:01.6052197+02:00",
"temperatureC": 46,
"summary": "testing"
},
{
"date": "2022-10-09T09:02:01.6052197+02:00",
"temperatureC": 46,
"summary": "testing"
},
{
"date": "2022-10-09T09:02:01.6052197+02:00",
"temperatureC": 46,
"summary": "testing"
},
{
"date": "2022-10-09T09:02:01.6052197+02:00",
"temperatureC": 46,
"summary": "testing"
}
]
对于瞬态生命周期,每次请求时都会创建一个新对象,而这正是正在发生的事情。您在构造函数中只请求一次,因此每次创建一个控制器实例时只创建一个实例。您看到相同的对象重复了5次,因为您在行上使用了相同的实例:
var returnValue = Enumerable.Range(1, 5).Select(index => _weatherForecast).ToArray();
您不是在上面的行中请求IWeatherForecast
,而是在构造函数中使用您请求的实例。
如果WeatherForecastController
如在其构造函数上所述具有IWeatherForecast
的依赖关系。IWeatherForecast
必须注册到集装箱中
builder.Services.AddTransient<IWeatherForecast, WeatherForecast>();
否则你会得到错误:
System.InvalidOperationException:无法解析类型的服务尝试激活时出现"WebApplication2.IWeatherForecast"'WebApplication2.Controllers.WeatherForecastController'
依赖注入基础结构知道控制器,因为您使用注册了它
builder.Services.AddControllers();
通过使用反射检查控制器构造函数,它知道它依赖于IWeatherForecast
。