是Asp.Net Core 2.0中的Configuration对象,可在类库项目中注入 [英] Is the Configuration object in Asp.Net Core 2.0, injectable in a class library project

查看:64
本文介绍了是Asp.Net Core 2.0中的Configuration对象,可在类库项目中注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在类库中设置类,在Startup.cs中的服务中将它们设置为可注入并使它们按预期工作时没有问题.

I have had no problem setting up classes in Class Libraries, setting them up in services in the Startup.cs to be injectable and having them work as expected.

在我正在使用的测试应用程序中.我有一个数据类库项目以及一个MVC应用程序项目(Core 2.0.1和EF 2.0.1和MVC6)

In a test app I am working in. I have a data class library project plus my MVC app project (Core 2.0.1 and EF 2.0.1 and MVC6)

在Startup.cs

In Startup.cs

 // *If* you need access to generic IConfiguration this is **required**
        services.AddSingleton<IConfiguration>(Configuration);

        services.AddOptions();
        // Add our class objects so they can be injected

 services.Configure<TestAppServices.ConfigurationClasses.ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
        services.Configure<TestAppServices.ConfigurationClasses.LoggingSettings>(Configuration.GetSection("Logging"));
        services.Configure<TestAppServices.ConfigurationClasses.ApplicationIconUrlSettings>(Configuration.GetSection("ApplicationIconUrls"));
        services.Configure<TestAppServices.ConfigurationClasses.DatabaseConfigurationSettings>(Configuration.GetSection("ConnectionStrings"));
        services.Configure<TestAppServices.ConfigurationClasses.SmsSettings>(Configuration.GetSection("SmsSettings"));

我可以访问已设置的各个类中的所有设置,但是以下操作无效.

I can access all the settings in the individual classes that are set up but, the following doesn't work.

private static IConfiguration _configuration { get; set; }
    private const string AppSettingsConnectionsHeader = "ConnectionStrings";

    public DatabaseHelpers(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public static ConnectionStrings GetConnections()
    {
        var cs = new ConnectionStrings();
        _configuration.GetSection(AppSettingsConnectionsHeader).Bind(cs);
        return cs;
    }

我遇到了常见错误

System.NullReferenceException:对象引用未设置为对象的实例.在TestAppServices.DatabaseHelpers.GetConnections()

System.NullReferenceException: Object reference not set to an instance of an object. at TestAppServices.DatabaseHelpers.GetConnections()

_configuration为空,因此不会被注入.

_configuration is null, therefore it is not getting injected.

像这样从控制器调用GetConnections方法

The GetConnections method is being called from a controller like so

 var cs = DatabaseHelpers.GetConnections();

是否有一种特殊的方法来设置实际的Configuration对象,以便它可以在类库项目中注入?

Is there a special way of setting up the actual Configuration object so it is injectable in class library projects?

更新:

按照serpent5的回答,我将类库项目重新配置为以下内容

Per serpent5's answer I reconfigured my class library project to the following

public static class ConnectionStrings
{
    public static string DefaultConnection => "DefaultConnection";
    public static string TestingConnection => "TestingConnection";
    public static string StagingConnection => "StagingConnection";
    public static string ProductionConnection => "ProductionConnection";
    public static string DevelopmentConnection => "DevelopmentConnection";       
}

public class ConfigurationSettings
{
    private readonly IConfiguration _configuration;

    public ConfigurationSettings(IConfiguration config)
    {
        _configuration = config;
    }

    public DatabaseConfigurationSettings GetConnectionStringFor(DatabaseIsFor dbfor)
    {
        var dbcs = new DatabaseConfigurationSettings();
        switch (dbfor)
        {
            case DatabaseIsFor.Development:
                if (!string.IsNullOrEmpty(_configuration.GetConnectionString(ConnectionStrings.DevelopmentConnection)))
                {
                    dbcs.CompleteConnectionString = _configuration.GetConnectionString(ConnectionStrings.DevelopmentConnection);
                    dbcs.ConnectionName = ConnectionStrings.DevelopmentConnection;  //== _connections.Value.DevelopmentConnection.ToString();
                    return dbcs;
                }
                break;

            case DatabaseIsFor.Testing:
                if (!string.IsNullOrEmpty(_configuration.GetConnectionString(ConnectionStrings.TestingConnection)))
                {
                    dbcs.CompleteConnectionString = _configuration.GetConnectionString(ConnectionStrings.TestingConnection);
                    dbcs.ConnectionName = ConnectionStrings.TestingConnection;  //== _connections.Value.TestingConnection.ToString();
                    return dbcs;
                }
                break;

            case DatabaseIsFor.Staging:
                if (!string.IsNullOrEmpty(_configuration.GetConnectionString(ConnectionStrings.StagingConnection)))
                {
                    dbcs.CompleteConnectionString = _configuration.GetConnectionString(ConnectionStrings.StagingConnection);
                    dbcs.ConnectionName = ConnectionStrings.StagingConnection;  //== _connections.Value.TestingConnection.ToString();
                    return dbcs;
                }
                break;

            case DatabaseIsFor.Production:
                if (!string.IsNullOrEmpty(_configuration.GetConnectionString(ConnectionStrings.ProductionConnection)))
                {
                    dbcs.CompleteConnectionString = _configuration.GetConnectionString(ConnectionStrings.ProductionConnection);
                    dbcs.ConnectionName = ConnectionStrings.ProductionConnection;  //== _connections.Value.TestingConnection.ToString();
                    return dbcs;
                }
                break;

        }
        dbcs.CompleteConnectionString = _configuration.GetConnectionString(ConnectionStrings.DefaultConnection);
        dbcs.ConnectionName = ConnectionStrings.DefaultConnection;  //== _connections.Value.DefaultConnection.ToString();
        return dbcs;
    }
}

然后按如下所示在控制器中使用它

And I use it in the controller as follows

public class HomeController : Controller
{
    private IConfiguration Configuration { get; set; }

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

    public IActionResult Index()
    {
       // test view to check that this works
        var cs = new ConfigurationSettings(Configuration);            
        var dbcs = cs.GetConnectionStringFor(DatabaseIsFor.Production);

        var svm = SettingsViewModel(dbcs);
        return View(svm);
    }
}

它工作得很好,除了,我不明白为什么在更新ConfigurationSettings时为什么必须通过Configuration.自从我在Startup.cs ConfigureServices中添加它以来,该位置那里已经不可用了吗?

And it works perfectly fine, Except I don't understand why I should have to pass Configuration when newing up ConfigurationSettings. Shouldn't that already be available there since I added it in Startup.cs ConfigureServices?

// Access to generic IConfiguration 
services.AddSingleton(Configuration);

推荐答案

您不能使用如果您不打算实例化类的实例,请使用构造函数注入.在您提供的代码中,您已设置DatabaseHelpers以通过其构造函数注入IConfiguration的实例,但是该类本身不参与

You can't use Constructor Injection if you're not going to instantiate an instance of your class. In the code you've provided, you've set up DatabaseHelpers to have an instance of IConfiguration injected via its constructor, but the class itself does not take part in Dependency Injection and therefore its constructor never needs to be called.

您的特定示例的一种解决方法是以某种方式显式初始化静态类.您可以向DatabaseHelpers添加一个新方法,如下所示:

One workaround for your particular example would be to explicitly initialize your static class in some way. You could add a new method to DatabaseHelpers, something like this:

public static Initialize(IConfiguration configuration)
{
    _configuration = configuration;
}

然后,您可以在应用启动时在某个地方进行设置-也许在ConfigureServices中.例如:

You'd then just set this up somewhere at app startup - perhaps in ConfigureServices. e.g.:

services.AddSingleton<IConfiguration>(Configuration);
DatabaseHelpers.Initialize(Configuration);

尽管这是解决问题的技术方法,但我还是鼓励您考虑使用静态助手来解决此问题是否是最佳选择.我假设DatabaseHelpers的实际实现比这里显示的要复杂,并且不能仅将ConnectionStrings的实例添加到Dependency Injection服务集合中并使用它.

Although this a technical workaround for your problem, I'd encourage you to consider whether using a static helper for this is the best option. I'm assuming that your actual implementation of DatabaseHelpers is more complex than what you've shown here and that you can't just add an instance of ConnectionStrings to your Dependency Injection service collection and use that instead.

更新:依赖注入实际上不是魔术,它只是一个模式.当您将创建类的职责委派给其他实体(通常是MVC世界中的控制器激活过程)时,它很好用,但是当您控制自己创建时,它就无法工作.在更新的示例中,您对创建ConfigurationSettings负有全部责任.因此,您必须提供其构造函数参数.

UPDATE: Dependency Injection is not actually magic, it's just a pattern. It works well when you delegate the responsibility of creating classes to some other entity (generally it's the controller activation process in the MVC world), but it can't work when you take control of creation yourself. In your updated example, you have taken full responsibility for the creation of ConfigurationSettings; therefore, you must provide its constructor arguments.

如果您不想自己处理此问题,可以将ConfigurationSettings添加到服务集合中,并让DI容器为您解析依赖的Configuration.

If you don't want to handle this yourself, you can add ConfigurationSettings to your collection of services and let the DI container the resolve the dependent Configuration for you.

这篇关于是Asp.Net Core 2.0中的Configuration对象,可在类库项目中注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆