【问题标题】:Call a C# web API service in a console application在控制台应用程序中调用 C# Web API 服务
【发布时间】:2021-08-25 21:50:04
【问题描述】:

在一个解决方案中,我有一个 .net 5 ASP.NET Core Web API,它包含一个接口 IEmailSender 和相应的 EmailSender 实现,以及一个控制台应用程序项目。 在控制台应用程序中,我创建了一个派生的计划服务,在 catch 块中,我想使用 EmailSender 发送一封电子邮件,其中包含系统中引发的错误的详细信息。

public StockOpeningValuesUpdateScheduledService(IScheduleConfig<StockOpeningValuesUpdateScheduledService> config, IHttpClientFactory factory, IServiceProvider serviceProvider)
            : base(config.CronExpression, config.TimeZoneInfo, serviceProvider)
        {
            _factory = factory;
            _serviceProvider = serviceProvider;
        }

        public override async Task DoWork(CancellationToken cancellationToken = default)
        {
            try
            {
                var client = _factory.CreateClient("trading");

                await client.PostAsync("company-buyable-shares/update-opening-values", null, cancellationToken);
            }
            catch (Exception ex)
            {
                using var serviceScope = _serviceProvider.CreateScope();

                var emailSender = serviceScope.ServiceProvider.GetRequiredService<IEmailSender>();

                await emailSender.SendAbnormalEventEmailAsync(ex);
            }
        }

我在控制台应用程序的Program.cs 中调用预定服务,并尝试将EmailSender 注册为范围服务。

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureServices((_, services) =>
            {
                services.AddHttpClient("trading", client =>
                    client.BaseAddress = new Uri("https://localhost:44395"));

                services.AddScoped<IEmailSender, EmailSender>()
                .AddScheduledService<StockOpeningValuesUpdateScheduledService>(service =>
                {
                    service.CronExpression = "*/2 * * * *";
                    service.TimeZoneInfo = TimeZoneInfo.Utc;
                });            
            });

当我在控制台应用程序中模拟错误时(为了接收有关它的电子邮件) 我得到一个例外

System.InvalidOperationException: 'Unable to resolve service for type 'StockTradingSimulator.BusinessLayer.Services.IEmailService' while attempting to activate 'StockTradingSimulator.BusinessLayer.Helpers.EmailSender'.

在 Web API 中,我在上面的 catch 块中进行了设置,用于调用范围服务方法的另一个派生计划服务。此功能正在运行,可能是因为计划服务、作用域服务及其接口在同一个项目中。

有人知道如何在我的控制台应用程序中注册并成功调用EmailSender

谢谢。

【问题讨论】:

    标签: c# api dependency-injection console-application service-provider


    【解决方案1】:

    问题是 EmailSender 有未解决的依赖关系。未解析的依赖是IEmailService

    您发布的代码和描述没有关于导致错误的接口的参考。 IEmailService 的实现在哪里?

    当您构建 IServiceProvider 时,您需要将 IEmailService 添加到 DI 容器中。比如:

    services.AddScoped<IEmailService, MyEmailService>();
    

    【讨论】:

    • 我认为这只是第一个错误,而不是在发布的代码中。所描述的服务中有很多参数也没有注入到发布的代码中。
    • 感谢两位的意见。我没有注意提到的错误IEmailService,而不是IEmailSender。对Program.cs我已经添加了EmailSender的所有依赖,其中一个是IEmailService。它们都存在于 Web API 项目中。我目前正在尝试在控制台应用程序中读取我的 API 项目 appsettings.json 文件,因为 EmailService 取决于它。我会发布更新。
    【解决方案2】:

    到控制台应用程序的Program.cs,我添加了EmailSender 的所有依赖项以及访问我的Web API 的appsettings.json 文件的AppSettings 部分的方法,该部分包含EmailService 使用的SMTP 详细信息IOptions&lt;AppSettings&gt; appSettings的依赖注入。

    public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                .ConfigureServices((_, services) =>
                {
                    var configuration = new ConfigurationBuilder()
                        .SetBasePath(Directory.GetCurrentDirectory())
                        .AddJsonFile("appsettings.json", false)
                        .Build();
    
                    services.AddHttpClient("trading", client =>
                        client.BaseAddress = new Uri("https://localhost:44395"));
    
                    services.AddSingleton(configuration)
                    .Configure<AppSettings>(configuration.GetSection("AppSettings"))
                    .AddScoped<IEmailSender, EmailSender>()
                    .AddScoped<IEmailService, EmailService>()
                    .AddDbContext<TradingDbContext>()
                    .AddAutoMapper(typeof(BusinessLayerServiceCollectionExtensions).Assembly)
                    .AddScheduledService<StockOpeningValuesUpdateScheduledService>(service =>
                    {
                        service.CronExpression = "*/1 * * * *";
                        service.TimeZoneInfo = TimeZoneInfo.Utc;
                    });           
                });
    

    更新: 从控制台应用程序访问appsettings.json 的正确方法是here。当控制台应用使用dotnet run 运行时,上述解决方案不起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多