[英]Getting some values from appsettings.json in ASP.NET Core WebAPI
I am creating a scheduled Task in ASP.NET Core WebAPI.我正在 ASP.NET Core WebAPI 中创建计划任务。 I am trying to get 5 URLs from appsettings.json which are not in a section, just in the root of appsettings.json.我试图从 appsettings.json 获取 5 个 URL,它们不在一个部分中,只是在 appsettings.json 的根目录中。 If I hardcode the strings in the Final class (mentioned in the last of this question), it works fine, but如果我在 Final 类中对字符串进行硬编码(在本问题的最后一个中提到),它工作正常,但是
This is my Program.cs:这是我的Program.cs:
public static void Main(string[] args)
{
var configuration = GetConfiguration();
var host = BuildWebHost(configuration, args);
host.Run();
//CreateWebHostBuilder(configuration,args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(IConfiguration _configuration,string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseConfiguration(_configuration);
private static IConfiguration GetConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
return builder.Build();
}
Following is my Startup.cs:以下是我的Startup.cs:
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ScheduledTaskSettings>(Configuration);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSingleton<IOrderSchedulerTask, OrderSchedulerTask>();
services.AddScheduler((sender, args) =>
{
Console.Write(args.Exception.Message);
args.SetObserved();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
}
I have also created ScheduledTaskSettings.cs with the following class.我还使用以下类创建了ScheduledTaskSettings.cs 。 The string names are identical to the names in appsettings.json.字符串名称与appsettings.json 中的名称相同。
public class ScheduledTaskSettings
{
public string ConnectionString { get; set; }
public string CustomersApiEndpointUrl { get; set; }
public string SubscriptionsApiEndpointUrl { get; set; }
public string ProductsApiEndpointUrl { get; set; }
public string SubscribersApiEndpointUrl { get; set; }
public string CronScheduleTime { get; set; }
}
I have an interface IOrderSchedulerTask.cs:我有一个接口IOrderSchedulerTask.cs:
public interface IOrderSchedulerTask
{
string Schedule { get; }
Task ExecuteAsync(CancellationToken cancellationToken);
}
And the final class OrderSchedulerTask.cs最后一个类 OrderSchedulerTask.cs
public class OrderSchedulerTask : IOrderSchedulerTask
{
// Implementing IOrderScheduler
// Scheduled for every one minute
public string Schedule => "*/1 * * * *";
public async Task ExecuteAsync(CancellationToken cancellationToken)
{
var httpClient = new HttpClient();
OrderScheduler.GenerateOrders();
}
}
public class OrderScheduler
{
public static ScheduledTaskSettings _scheduledTaskSettngs;
public OrderScheduler(ScheduledTaskSettings scheduledTaskSettings)
{
_scheduledTaskSettngs = scheduledTaskSettings;
}
private static string CustomerApiUrl = _scheduledTaskSettngs.CustomersApiEndpointUrl;
private static string SubscriptionApiUrl = _scheduledTaskSettngs.SubscriptionsApiEndpointUrl;
private static string CatalogApiUrl = _scheduledTaskSettngs.ProductsApiEndpointUrl;
private static string SubscriberUrl = _scheduledTaskSettngs.SubscribersApiEndpointUrl;
private static string _connectionString = _scheduledTaskSettngs.ConnectionString;
private static List<Customer> customers = null;
private static List<Subscription> subscriptions = null;
private static List<CatalogItem> products = null;
private static List<Subscriber> subscribers = null;
private static List<Order> orders = new List<Order>();
/// <summary>
/// Generate the orders for next day
/// </summary>
public static async void GenerateOrders()
{
// Get Customers Data
GetCustomers();
//Get Subscription Data
GetSubscriptions();
//Get Products Data
GetProducts();
//Get Subscribers Data
GetSubscribers();
var order = new Order();
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
foreach (var item in subscriptions)
{
//
}
}
}
private static async void GetCustomers()
{
//Uses CustomerApiUrl String
}
private static async void GetSubscriptions()
{
//Uses SubscriptionApiUrl String
}
private static async void GetProducts()
{
//Uses CatalogApiUrl String
}
private static async void GetSubscribers()
{
//Uses SubscriberUrl String
}
}
If I hardcode the strings, it works fine, but it throws the following exception when I use the configuration method:如果我对字符串进行硬编码,它可以正常工作,但是当我使用配置方法时会抛出以下异常:
Unhandled Exception:
Unhandled Exception:
Unhandled Exception:
Unhandled Exception: System.TypeInitializationException: The type initializer for
'Ordering.ScheduledTask.Tasks.OrderScheduler' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at Ordering.ScheduledTask.Tasks.OrderScheduler..cctor() in ... OrderSchedulerTask.cs Line 22
Can someone please guide me through about what should I be doing to correct it.有人可以指导我了解我应该做些什么来纠正它。
There are a few issues I see with your code:我看到您的代码存在一些问题:
Why are you creating a custom ConfigurationBuilder
in your Program.cs
?为什么要在Program.cs
创建自定义ConfigurationBuilder
? The default builder that you create with WebHost.CreateDefaultBuilder
will already set up a configuration that uses both appsettings.json
and appsettings.<Environment>.json
, as well as other sources like the environment variables or command line arguments.您使用WebHost.CreateDefaultBuilder
创建的默认构建器将设置使用appsettings.json
和appsettings.<Environment>.json
以及其他来源(如环境变量或命令行参数)的配置。
So there is no need to create a custom configuration and I would advise you against creating one unless you actually have a good reason to do so.因此无需创建自定义配置,我建议您不要创建自定义配置,除非您确实有充分的理由这样做。
services.Configure<ScheduledTaskSettings>(Configuration)
is a method of the Options framework . services.Configure<ScheduledTaskSettings>(Configuration)
是Options 框架的一种方法。 You configure an IOptions<ScheduledTaskSettings>
that way.您可以通过这种方式配置IOptions<ScheduledTaskSettings>
。 So in order to consume that, you will have to inject IOptions<ScheduledTaskSettings>
into your OrderScheduler
;因此,为了使用它,您必须将IOptions<ScheduledTaskSettings>
注入您的OrderScheduler
; not just ScheduledTaskSettings
.不仅仅是ScheduledTaskSettings
。
In OrderScheduler
, you inject the task settings (again, this should be options), but you use that to statically set _scheduledTaskSettngs
which would be shared between all instances.在OrderScheduler
,您注入任务设置(同样,这应该是选项),但您使用它来静态设置将在所有实例之间共享的_scheduledTaskSettngs
。 That is generally a bad idea in applications that make use of DI: You explicitly want this to stay an instance member so that it belongs to the lifetime of the object.在使用 DI 的应用程序中,这通常是一个坏主意:您明确希望 this 保持实例成员,以便它属于对象的生命周期。
What's ultimately causing your errors is the following part:最终导致您的错误的是以下部分:
private static string CustomerApiUrl = _scheduledTaskSettngs.CustomersApiEndpointUrl; private static string SubscriptionApiUrl = _scheduledTaskSettngs.SubscriptionsApiEndpointUrl; private static string CatalogApiUrl = _scheduledTaskSettngs.ProductsApiEndpointUrl; private static string SubscriberUrl = _scheduledTaskSettngs.SubscribersApiEndpointUrl; private static string _connectionString = _scheduledTaskSettngs.ConnectionString;
Since these are all static fields, they will be initialized statically when the type is first used.由于这些都是静态字段,当第一次使用该类型时,它们会被静态初始化。 At that point, no instance will have been created yet, so the static _scheduledTaskSettngs
will not be initialized yet.那时,还没有创建任何实例,因此静态_scheduledTaskSettngs
还不会被初始化。 So it's null
, explaining the NullReferenceException
s you get.所以它是null
,解释了你得到的NullReferenceException
。
This approach also prevents you from reacting to changes of that configuration since the values are only read once and then stored statically.这种方法还可以防止您对该配置的更改做出反应,因为这些值仅读取一次然后静态存储。
You should make your OrderScheduler
a singleton and properly inject it into other things, so that you can use it as an instance that has a well-defined lifetime:您应该将OrderScheduler
单例,并将其正确注入其他事物,以便您可以将其用作具有明确定义生命周期的实例:
public class OrderScheduler
{
public readonly ScheduledTaskSettings _scheduledTaskSettings;
public OrderScheduler(IOptions<ScheduledTaskSettings> scheduledTaskSettings)
{
_scheduledTaskSettings = scheduledTaskSettings.Value;
}
// using read-only properties instead
private string CustomerApiUrl => _scheduledTaskSettngs.CustomersApiEndpointUrl;
private string SubscriptionApiUrl => _scheduledTaskSettngs.SubscriptionsApiEndpointUrl;
private string CatalogApiUrl => _scheduledTaskSettngs.ProductsApiEndpointUrl;
private string SubscriberUrl => _scheduledTaskSettngs.SubscribersApiEndpointUrl;
private string _connectionString => _scheduledTaskSettngs.ConnectionString;
// …
// instance members only, no “static”
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.