IConfiguration gebruiken in C# Class Library

Ik bouw een klassenbibliotheek met C# en Core .NET. Ik probeer een configuratie uit een config.json-bestand te gebruiken. Hier is de inhoud van dat bestand:

config.json

{
  "emailAddress":"[email protected]"
}

In een poging om config.jsonte gebruiken voor mijn configuratie, verwijs ik naar Microsoft.Framework.ConfigurationModel.Jsonin mijn project.jsonbestand. In mijn code heb ik het volgende:

MijnClass.cs

using Microsoft.Framework.ConfigurationModel;
public class MyClass
{
  public string GetEmailAddress()
  {
//    return ConfigurationManager.AppSettings["emailAddress"];  This is the approach I had been using since .NET 2.0
    return ?;  // What goes here?
  }
}

Sinds .NET 2.0 gebruik ik ConfigurationManager.AppSettings["emailAddress"]. Ik probeer nu echter te leren hoe ik dit op de nieuwe manier kan doen via IConfiguration. Mijn probleem is dat dit een klassenbibliotheek is. Om die reden weet ik niet zeker hoe, of waar, of wanneer het configuratiebestand wordt geladen. In traditioneel .NET hoefde ik alleen een bestand web.config voor ASP.NET-projecten en app.config voor andere projecten te noemen. Nu, ik weet het niet zeker. Ik heb zowel een ASP.NET MVC 6-project als een XUnit-project. Dus ik probeer erachter te komen hoe ik config.jsonin beide scenario’s kan gebruiken.

Bedankt!


Antwoord 1, autoriteit 100%

IMO-klassebibliotheken moeten onafhankelijk zijn van de gegevens van applicatie-instellingen. Over het algemeen is de bibliotheekgebruiker degene die zich met dergelijke details bezighoudt. Ja, dit is niet altijd waar (als je bijvoorbeeld een klasse hebt die RSA-codering/decodering uitvoert, wil je misschien een privéconfiguratie om de privésleutel-gen/opslag mogelijk te maken), maar voor het grootste deel is het waar.

Probeer dus in het algemeen applicatie-instellingen uit de klassenbibliotheek te houden en laat de consument dergelijke gegevens verstrekken. In uw opmerking vermeldt u een verbindingsreeks met een database. Dit is een perfect voorbeeld van gegevens die BUITEN een klassenbibliotheek moeten worden bewaard. Het zou de bibliotheek niet moeten schelen naar welke database ze belt om te lezen, alleen dat ze uit een database moet lezen. Voorbeeld hieronder (mijn excuses als er fouten zijn omdat ik dit on-the-fly uit het hoofd schrijf):

Bibliotheek

Bibliotheekklasse die een verbindingsreeks gebruikt

public class LibraryClassThatNeedsConnectionString
{
    private string connectionString;
    public LibraryClassThatNeedsConnectionString(string connectionString)
    {
        this.connectionString = connectionString;
    }
    public string ReadTheDatabase(int somePrimaryKeyIdToRead)
    {
        var result = string.Empty;
        // Read your database and set result
        return result;
    }
}

Toepassing

appsettings.json

{
  "DatabaseSettings": {
    "ConnectionString": "MySuperCoolConnectionStringWouldGoHere"
  }
}

DatabaseSettings.cs

public class DatabaseSettings
{
    public string ConnectionString { get; set; }
}

Startup.cs

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        Configuration = new ConfigurationBuilder()
                        .SetBasePath(env.ContentRootPath)
                        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                        .AddEnvironmentVariables()
                        .Build();
    }
    public IConfigurationRoot Configuration { get; }
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        // Setup logging
        // Configure app
    }
    public void ConfigureServices(IServiceCollection services)
    {
        // Configure services
        services.Configure<DatabaseSettings>(Configuration.GetSection("DatabaseSettings"));
        services.AddOptions();
        // Register our class that reads the DB into the DI framework
        services.AddTransient<IInterfaceForClass, ClassThatNeedsToReadDatabaseUsingLibrary>();
    }
}

Klasse die de bibliotheekklasse gebruikt om de database te lezen

public interface IInterfaceForClass
{
    string ReadDatabaseUsingClassLibrary(int somePrimaryKeyIdToRead);
}
public class ClassThatNeedsToReadDatabaseUsingLibrary : IInterfaceForClass
{
    private DatabaseSettings dbSettings;
    private LibraryClassThatNeedsConnectionString libraryClassThatNeedsConnectionString;
    public ClassThatNeedsToReadDatabaseUsingLibrary(IOptions<DatabaseSettings> dbOptions)
    {
        this.dbSettings = dbOptions.Value;
        this.libraryClassThatNeedsConnectionString = new LibraryClassThatNeedsConnectionString(this.dbSettings.ConnectionString);
    }
    public string ReadDatabaseUsingClassLibrary(int somePrimaryKeyIdToRead)
    {
        return this.libraryClassThatNeedsConnectionString.ReadTheDatabase(somePrimaryKeyIdToRead);
    }
}

Een controllerklasse die UI-dingen afhandelt om uit de DB te lezen

public class SomeController : Controller
{
    private readonly classThatReadsFromDb;
    public SomeController(IInterfaceForClass classThatReadsFromDb)
    {
        this.classThatReadsFromDb = classThatReadsFromDb;
    }
    // Controller methods
}

TL;DR

Probeer applicatie-instellingen in een klassenbibliotheek te vermijden. Laat uw klassenbibliotheek in plaats daarvan agnostisch zijn voor dergelijke instellingen en laat de consument deze instellingen doorgeven.

Bewerken:

Ik heb afhankelijkheidsinjectie toegevoegd aan een controllerklasse om te demonstreren met behulp van afhankelijkheidsinjectie om de klasse te bouwen die uit de DB leest. Hierdoor kan het DI-systeem de noodzakelijke afhankelijkheden oplossen (bijv. de DB-opties).

Dit is een manier om het te doen (en de beste manier). Een andere manier is om de IOptions in de controller te injecteren en handmatig de klasse te vernieuwen die uit de DB leest en de opties door te geven (niet de beste praktijk, DI is een betere manier om te gaan)


Antwoord 2, autoriteit 26%

Dit zou moeten werken. Moet pakket Microsoft.Extensions.Configuration.Json installeren

public static class Config
  {
    private static IConfiguration configuration;
    static Config()
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
        configuration = builder.Build();
    }
    public static string Get(string name)
    {
        string appSettings = configuration[name];
        return appSettings;
    }
}

Antwoord 3, autoriteit 20%

Nooit gebruikt, maar een snelle zoekopdracht leidde me naar dit…

var configuration = new Configuration();
configuration.AddJsonFile("config.json");
var emailAddress = configuration.Get("emailAddress");

Misschien zou je dat kunnen proberen.


Antwoord 4, autoriteit 3%

Voeg eerst in uw .csproj-bestand een doel toe dat in het bouwproces hapert, zie de link voor meer opties als het volgende niet aan uw behoeften voldoet, zoals publicatie

<Target Name="AddConfig" AfterTargets="AfterBuild">
    <Copy SourceFiles="config.json" DestinationFolder="$(OutDir)" />
</Target>

je kunt het als volgt gebruiken

using Microsoft.Framework.ConfigurationModel;
using Microsoft.Extensions.Configuration;
using System;
public class MyClass {
    public string GetEmailAddress() {
        //For example purpose only, try to move this to a right place like configuration manager class
        string basePath= System.AppContext.BaseDirectory;
        IConfigurationRoot configuration= new ConfigurationBuilder()
            .SetBasePath(basePath)
            .AddJsonFile("config.json")
            .Build();
        return configuration.Get("emailAddress");
    }
}

Antwoord 5

AppSettings.Json Key-waarden in C# Controller lezen met IConfiguration.

Voor het geval iemand het wil zien, bijvoorbeeld voor Asp.net Core .Net 5.0. Ik heb bovenstaande antwoorden doorgenomen en mijn code een beetje aangepast voor mijn toepassing.

Als je wilt zien hoe je dit in de consoletoepassing kunt gebruiken, bezoek dan mijn antwoord op deze link, ik heb ook een voorbeeld met e-mailadres toegevoegd.


Mijn AppSettings.Json is:

{
"AppSettings": {
    "FTPLocation": "\\\\hostname\\\\c$\\\\FTPMainFolder\\\\ftpFolder\\\\Test\\",
    "FTPUri": "ftp://hostname.domainname.com/foldername/",
    "CSVFileName": "Test Load Planning.csv"  
                },
"ConnectionStrings": 
 {
 "AppDbConnString": "Server=sqlserverhostname.domainname.com;Database=DBName;Trusted_Connection=True; MultipleActiveResultSets=true"   },
 "ADSecurityGroups": { "UserSecurityGroups": "AD-DL-GROUP-NAME;AD-DL-GROUP2-NAME"},
 "Logging": 
  {
    "LogLevel": {
        "Default": "Warning"    
       }  
   }
}

Mijn LoginController.cs is:

using Microsoft.Extensions.Configuration;
public class LoginController : BaseController
{
    private readonly ILoginDataServices _loginDataServices;
    private readonly IConfiguration _configuration;
    public IActionResult Index()
    {
        return View();
    }
    public LoginController(ILoginDataServices loginDataServices, IConfiguration configuration)
    {
            _loginDataServices = loginDataServices;
            _configuration = configuration;
    }
    public bool CheckLogin(string userName, string password)
    {
        if (CheckIfValidEmployee(userName))
        {
            //////checking code here....
        }
        else
        {
            return false;
        }
    }
    bool CheckIfValidEmployee(string userName)
    {
        var securityGroups = _configuration.GetSection("ADSecurityGroups:UserSecurityGroups").Value.Split(';');
         Console.WriteLine(securityGroups);
       ////////Code to check user exists into security group or not using variable value
     }

Antwoord 6

U kunt ook eigenschappen van de klassenbibliotheek instellen door met de rechtermuisknop op een .csproject -> eigenschappen-> instellingen-> voeg een nieuwe eigenschap toe in het rechtervenster.
Zorg ervoor dat u de toegangsmodifier als openbaar selecteert in de vervolgkeuzelijst Toegangsmodifier.

Voeg nu een verwijzing naar een klassenbibliotheekproject toe aan uw .net-kernproject.

Maak appSettings.cs klasse zoals hieronder vermeld

public class AppSettings
{
    public string MyConnectionString { get; set; }
}

Stel sleutelwaarde appSettings.json in

"AppSettings": {
"MyConnectionString": "yourconnectionstring",

},

Nu moeten we alleen de verbindingsreeks ophalen van appSettings.json en
stel eigenschappen in in de klassenbibliotheek in Startup.cs zoals hieronder.

// This method gets called by the runtime. Use this method to add services to the container
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        // inject App setting
        var appSettingSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingSection);
        var appsetting = appSettingSection.Get<AppSettings>();
        // set connection string in .csproject properties.
        classLibraryProject.Properties.Settings.Default.Properties["MyConnectionString"].DefaultValue = appsetting.MyconnectionString;
    }

Opmerking:

  • Zorg voor de MyConnectionString-sleutel. Het zou in alle drie de bestanden hetzelfde moeten zijn.
  • Zorg ervoor dat u de toegangsmodifier instelt op Openbaar in het ClassLibrary-project.

Ik hoop dat dit kan helpen.

Other episodes