注入 dbContext 时返回“找不到与给定参数匹配的构造函数”
Posted
技术标签:
【中文标题】注入 dbContext 时返回“找不到与给定参数匹配的构造函数”【英文标题】:"Could not find a constructor that would match given arguments" returned when injecting a dbContext 【发布时间】:2021-08-03 20:03:23 【问题描述】:上下文
.NET 5 控制台应用程序使用 IHostedService 模式和 EntityFramework Core 5。
问题
dbContext 如下所示:
public class WeatherDbContext : DbContext, IWeatherDbContext
public WeatherDbContext(DbContextOptions<WeatherDbContext> options) : base(options)
public virtual DbSet<Observation> Observations get; set;
主机构建器是这样配置的:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
logging.ClearProviders();
)
.UseSerilog((hostContext, loggerConfiguration) =>
logConfiguration.WriteTo.File(ConfigurationManager.AppSettings["LogFile"]);
)
.ConfigureServices((services) =>
services.AddHttpClient()
.AddSingleton<CommandLineArguments>(new CommandLineArguments(args))
.AddSingleton<StringWriter>()
.AddDbContext<IWeatherDbContext, WeatherDbContext>(options =>
options.UseSqlServer(ConfigurationManager.ConnectionStrings["WeatherManagerDatabase"].ConnectionString);
)
.AddTransient<IWeatherUndergroundAPIService(x => new WeatherUndergroundAPIService(ConfigurationManager.AppSettings["StationId"],
ConfigurationManager.AppSettings["WUApiKey"],
x.GetRequiredService<IHttpClientFactory>()))
.AddHostedService<DataDownloader>();
);
...主机服务是这样构造的:
private readonly int importDayLimit;
private readonly ILogger logger;
private readonly StringWriter outputWriter;
private readonly int throttleLimit = 100;
private readonly IWeatherDbContext weatherDbContext;
private readonly IWeatherUndergroundAPIService wuApiService;
private DateTime FetchUpToDate;
private DateTime MostRecentlyRecordedObservationDate;
public DataDownloader(IWeatherUndergroundAPIService wuApiService,
ILogger logger,
IWeatherDbContext weatherDbContext,
StringWriter outputWriter,
CommandLineArguments commandLineArguments)
this.wuApiService = wuApiService;
this.weatherDbContext = weatherDbContext;
this.logger = logger;
this.outputWriter = outputWriter;
this.importDayLimit = this.ProcessCommandLineArguments(commandLineArguments.Args);
然后我有一个这样的 XUnit 测试:
public class CommandLineArgumentValidation
[Fact]
public async Task CommandLineArgumentNotAnIntegerAsync()
// Arrange
Mock<IWeatherUndergroundAPIService> mockWeatherUndergroundAPIService = new();
DbContextOptions<WeatherDbContext> dbContextOptions = new DbContextOptionsBuilder<WeatherDbContext>()
.UseInMemoryDatabase(databaseName: "testDb")
.EnableDetailedErrors()
.Options;
IWeatherDbContext weatherDbContext = new WeatherDbContext(dbContextOptions);
Mock<ILogger> mockLogger = new();
StringBuilder consoleOutput = new();
StringWriter consoleWriter = new(consoleOutput);
CommandLineArguments commandLineArguments = new(new string[] "not a positive integer" );
DataDownloader dataDownloader = new(mockWeatherUndergroundAPIService.Object,
mockLogger.Object,
weatherDbContext,
consoleWriter,
commandLineArguments);
CancellationToken cancellationToken = new(false);
// Action
await dataDownloader.StartAsync(cancellationToken);
// Assertion
Assert.Equal("Command line argument 'not a positive integer' is not a positive integer. Aborting download.", consoleOutput.ToString());
测试抛出异常
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : 可以 不实例化类的代理: WeatherManagerDataDownloader.WeatherDbContext。 找不到与给定参数匹配的构造函数:
请注意,为了清楚起见,我已经简化了代码。我 am 模拟注入到 DataDownloader 的其他服务,但我没有模拟 dBContext。 编辑:我现在添加了完整的代码,因为有人指出,即使我的简化代码没有暗示,模拟似乎正在发生。
问题
为什么会出现这个测试异常?在我看来,模拟应该与传入的 dBContext 无关。
【问题讨论】:
尝试强制转换:WeatherDbContext((WeatherDbContext)dbContextOptions) @jdweng 到底在哪里?在测试中还是在 DataDownLoader 中? 我会在调用之前添加断点并检查类型。您可能会收到一个给出问题的空响应。 错误提示您正在模拟 WeatherDbContext,但您的示例代码没有显示。 @Neil 确实如此,但我不明白为什么。我已经更新了上面的代码以显示完整的测试设置。如您所见,正在发生模拟,但 dbContext 没有。 【参考方案1】:我认为这可能是答案,当然它让我继续前进。
当使用调试器运行测试时,我意识到一切都已成功注入,并且测试代码正在成功进行。但是我正在测试无效的命令行参数情况,并且在 DataDownloader 中我已经编码
Environment.Exit(1)
在输出适当的消息后停止应用程序。显然,这不是您应该在 IHostedService 中执行的操作,删除它会使模拟错误消失。然而,为什么它会导致未模拟的东西出现模拟错误仍然令人费解。
【讨论】:
以上是关于注入 dbContext 时返回“找不到与给定参数匹配的构造函数”的主要内容,如果未能解决你的问题,请参考以下文章
注入 DbContext 时无法访问 ASP.NET Core 中已释放的对象