0

I am new in asp.net core and I would like to set the property value during start up in asp.net core web API. The data is fetched from Data base and I need the values through out the application and it should be called only once.

There is two states in my project lets assume it to be A and B. In A there is one set of items are shown and in the B there are different items shown. I get a application setting data from the Database and on the basis of that data i will either show the A module or the B module through out the application life.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • which version of net core do you used ? – thisisnabi May 17 '22 at 08:46
  • There are no global variables in C#, the language or .NET in general. Variables exist only inside methods. What you really ask is how to cache data. While you could use a static property for this, testing would be *very* difficult. Your code would break every time you changed how that value is loaded too. – Panagiotis Kanavos May 17 '22 at 08:47
  • Besides, that's really a configuration value. In ASP.NET Core that's handled by the Configuration middleware. You can load and store configuration data from the database in your Startup or Program file, depending on version. Another quick&dirty option is to register that data as a Singleton service. In both cases, the rest of your code won't know or be affected by how you load that data – Panagiotis Kanavos May 17 '22 at 08:49
  • dot net version is 5.0.403 @thisisnabi – tenzin yeshi May 17 '22 at 08:51
  • .NET 5 is already out of support. The current Long-Term-Support version is .NET 6 which will be supported until November 2024. .NET 5 was a single-year version, just like the upcoming .NET 7 – Panagiotis Kanavos May 17 '22 at 08:53
  • Please give some context on what you are exactly trying to achieve. And what you have tried already. (Funny how there already are 3 answer. Quite different from each other... because it's not a clear focused question) – JHBonarius May 17 '22 at 09:27
  • There is two states in my project lets assume it to be A and B. In A there is one set of items are shown and in the B there are different items shown. I get a application setting data from the Database and on the basis of that data i will either show the A module or the B module through out the application life. @JHBonarius – tenzin yeshi May 17 '22 at 09:46
  • Maybe you can find your answer here: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/ – JHBonarius May 17 '22 at 10:32
  • Possible dupe: https://stackoverflow.com/questions/39231951 – JHBonarius May 17 '22 at 10:36
  • @tenzinyeshi you just talked about application settings. Why not use the built-in configuration middleware? Although `either show the A module or the B module` is best solved by having both modules implement the same interface and register only one of them in the DI container. Which, btw, is not what you asked in the question – Panagiotis Kanavos May 17 '22 at 10:40

2 Answers2

1

There are no global variables in .NET, much less C#. Storing configuration data in global, static properties is a bad idea because it ties your code with the static class that holds those properties, making it harder to write or test code.

Configuration Middleware

ASP.NET Core solves this through the Configuration middleware which can read configuration settings from multiple providers, including files, databases and even in-memory collections. The Configuration overview article shows how to use a dictionary as a configuration source :

var builder = WebApplication.CreateBuilder(args);

var Dict = new Dictionary<string, string>
        {
           {"MyKey", "Dictionary MyKey Value"},
           {"Position:Title", "Dictionary_Title"},
           {"Position:Name", "Dictionary_Name" },
           {"Logging:LogLevel:Default", "Warning"}
        };

builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
    config.Sources.Clear();

    config.AddInMemoryCollection(Dict);

    config.AddEnvironmentVariables();

    if (args != null)
    {
        config.AddCommandLine(args);
    }
});

builder.Services.AddRazorPages();

var app = builder.Build();

After that, all classes can retrieve the configuration values, no matter where they come from, through the IConfiguration interface :

public class TestModel : PageModel
{
    // requires using Microsoft.Extensions.Configuration;
    private readonly IConfiguration Configuration;

    public TestModel(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var myKeyValue = Configuration["MyKey"];
        var title = Configuration["Position:Title"];
        var name = Configuration["Position:Name"];
        var defaultLogLevel = Configuration["Logging:LogLevel:Default"];


        return Content($"MyKey value: {myKeyValue} \n" +
                       $"Title: {title} \n" +
                       $"Name: {name} \n" +
                       $"Default Log Level: {defaultLogLevel}");
    }
}

In your case you could load the settings from a database and register them as an in-memory source in your Program.cs :

var Dict=LoadDataAsDictionary();
...
    config.AddInMemoryCollection(Dict);
...

Dependency Injection Middleware

Another option is to load the data as a strongly typed object and register it as a Signleton instance using the Dependency Injection middleware :

var builder = WebApplication.CreateBuilder(args);

MyCacheData cacheData=LoadStronglyTypedData();

builder.Services.AddSingleton(cachedata);

This class can be injected into pages and controllers just like other DI services or IConfiguration :

public class TestModel : PageModel
{

    private readonly MyCacheData Data;

    public TestModel(MyCacheData data)
    {
        Data = data;
    }
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • Why not tag a dupe... like [this](https://stackoverflow.com/questions/40397648), or [this](https://stackoverflow.com/questions/39231951), or [this](https://stackoverflow.com/questions/38114761)?? – JHBonarius May 17 '22 at 10:35
  • Because they aren't. The question didn't ask how to use the config or DI middleware, it asked how to use a "global variable" to store data. This is a more basic question. None of these questions and answers explain that there are no global variables, that this data shouldn't be stored in static properties and what the correct way to do so is. – Panagiotis Kanavos May 17 '22 at 10:39
0

A general solution to this problem would be to configure a singleton object to be registered in the ServiceCollection.

services.AddSingleton<ISingletonObject, SingletonObject>();

The constructor for such an object would load the necessary data, and then use constructor injection to load the singleton object into each class (e.g. controller).

public class SomeController(ISingletonObject singletonObject)
{
     // singleton object will be injected with it's pre-loaded data available   
}

The constructor for object SingletonObject will only be executed once, regardless of how many other constructors it is injected into by the service collection.

Ben Wesson
  • 589
  • 6
  • 16