简体   繁体   English

从 ASP.NET Core WebAPI 中的 appsettings.json 获取一些值

[英]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:我看到您的代码存在一些问题:

  1. 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.jsonappsettings.<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.因此无需创建自定义配置,我建议您不要创建自定义配置,除非您确实有充分的理由这样做。

  2. 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

  3. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM