You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于ASP.NET Core中AddTransient依赖注入的两个技术疑问

问题解答

1. 为什么Transient生命周期未按预期工作?

你注册的AddTransient<IWeatherForecast, WeatherForecast>配置是正确的,问题出在控制器的Get方法实现逻辑上:

var returnValue= Enumerable.Range(1, 5).Select(index => _weatherForecast).ToArray();

这里的_weatherForecast是控制器构造时DI容器注入的单个实例,你在循环中只是重复返回这个已有的对象,并没有每次从DI容器中请求新的Transient实例。

Transient的核心规则是:每次向DI容器请求服务时,都会创建一个全新的实例。而你当前的逻辑是复用了控制器初始化时拿到的那一个实例,自然所有返回项的随机数都完全相同。

修正方法

要获取5个不同的Transient实例,你需要每次都从DI容器中请求新实例。推荐两种实现方式:

方式一:注入IServiceProvider直接获取

修改控制器代码:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace WebApplication2.Controllers;

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly IServiceProvider _serviceProvider;
    
    public WeatherForecastController(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<IWeatherForecast> Get()
    {
        return Enumerable.Range(1, 5)
            .Select(_ => _serviceProvider.GetRequiredService<IWeatherForecast>())
            .ToArray();
    }
}

方式二:使用工厂模式(更符合依赖注入原则)

  1. 在Program.cs中注册工厂:
builder.Services.AddTransient<IWeatherForecast, WeatherForecast>();
builder.Services.AddTransient<Func<IWeatherForecast>>(sp => sp.GetRequiredService<IWeatherForecast>);
  1. 控制器注入工厂并使用:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace WebApplication2.Controllers;

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly Func<IWeatherForecast> _weatherForecastFactory;
    
    public WeatherForecastController(Func<IWeatherForecast> weatherForecastFactory)
    {
        _weatherForecastFactory = weatherForecastFactory;
    }

    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<IWeatherForecast> Get()
    {
        return Enumerable.Range(1, 5)
            .Select(_ => _weatherForecastFactory())
            .ToArray();
    }
}

两种方式都能保证每次获取新的Transient实例,返回结果的随机数就会各不相同。

2. DI容器如何知晓控制器的依赖需求?

ASP.NET Core的DI系统通过构造函数注入机制解析依赖:

  • 当HTTP请求到达时,框架需要实例化对应的WeatherForecastController来处理请求。
  • 框架会通过反射检查控制器的构造函数,发现它需要一个IWeatherForecast类型的参数。
  • 随后框架向DI容器请求解析IWeatherForecast服务:如果该服务已通过AddTransient等方法注册,容器会创建对应的实例并注入到控制器中;如果没有注册,就会抛出你看到的InvalidOperationException错误。

简单来说,DI容器通过分析控制器的构造函数参数列表,识别它需要的依赖服务,这是构造函数注入的核心工作原理。


相关代码参考

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>();
...

内容的提问来源于stack exchange,提问作者Soner from The Ottoman Empire

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 01:50:25