Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.7k views
in Technique[技术] by (71.8m points)

asp.net core - Using IConfiguration in C# Class Library

I am building a class library using C# and Core .NET. I am trying to use configuration from a config.json file. Here are the contents of that file:

config.json

{
  "emailAddress":"someone@somewhere.com"
}

In an attempt to use config.json for my configuration, I'm referencing Microsoft.Framework.ConfigurationModel.Json in my project.json file. In my code, I have the following:

MyClass.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?
  }
}

Since .NET 2.0, I had been using ConfigurationManager.AppSettings["emailAddress"]. However, I'm now trying to learn how to do it the new way via IConfiguration. My problem is, this is a class library. For that reason, I'm not sure how, or where, or when, the configuration file gets loaded. In traditional .NET, I just needed to name a file web.config for ASP.NET projects and app.config for other projects. Now, I'm not sure. I have both an ASP.NET MVC 6 project and an XUnit project. So, I'm trying to figure out how to use config.json in both of these scenarios.

Thank you!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

IMO class libraries should be agnostic to application settings data. Generally, the library consumer is the one concerned with such details. Yes, this isn't always true (e.g. if you have a class that does RSA encryption/decryption, you may want some private configuration to allow for the private key gen/storage), but for the most part, it is true.

So, in general, try to keep application settings out of the class library and have the consumer provide such data. In your comment you mention a connection string to a database. This is a perfect example of data to be kept OUT of a class library. The library shouldn't care what database it's calling to to read, just that it needs to read from one. Example below (I apologize if there's some mistakes as I am writing this on the fly from memory):

Library

Library class that uses a connection string

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;
    }
}

Application

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>();
    }
}

Class that uses the library class to read the database

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);
    }
}

Some controller class that handles UI stuff to read from the DB

public class SomeController : Controller
{
    private readonly classThatReadsFromDb;

    public SomeController(IInterfaceForClass classThatReadsFromDb)
    {
        this.classThatReadsFromDb = classThatReadsFromDb;
    }

    // Controller methods
}

TL;DR

Try to avoid using application settings in a class library. Instead, have your class library be agnostic to such settings and let the consumer pass those settings in.

Edit:

I added in dependency injection into a controller class to demonstrate using dependency injection to build the class that reads from the DB. This lets the DI system resolve the necessary dependences (e.g. the DB options).

This is one way of doing it (and the best way). Another way is to inject the IOptions into the controller and manually newing up the class that reads from the DB and passing the options in (not best practice, DI is a better way to go)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...