首页 > 解决方案 > 无法从类库访问 appsettings.json

问题描述

我一直在关注本教程,以便从我的类库中的 MVC 项目访问我的 appsettings.json。 极客教程

我的类库中有这样的类

using dapper;

public class SqlDataAccess : IConfigManager
{
    private readonly IConfiguration _configuration;
    public SqlDataAccess(IConfiguration configuration)
    {
        this._configuration = configuration;
    }

    public List<T> LoadData<T>(string sql)
    {
        using (IDbConnection cnn = new SqlConnection(GetConnectionString()))
        {
            return cnn.Query<T>(sql).ToList();
        }
    }

    public int SaveData<T>(string sql, T data)
    {
        using (IDbConnection cnn = new SqlConnection(GetConnectionString()))
        {
            return cnn.Execute(sql, data);
        }
    }

    public string GetConnectionString(string connectionName = "URLShortnerDB")
    {
        return this._configuration.GetConnectionString(connectionName);
    }
}

界面:

public interface IConfigManager
{
    string GetConnectionString(string connectionName);
}

services.AddSingleton<IConfigManager, SqlDataAccess>();在我的 mvc startup.cs中添加了

但是现在我想使用我的SqlDataAccess类并从另一个类调用方法,例如:

public static class ShortUrlProcessor
{
    
    public static ShortURLModel GetOriginalURL(string shortUrl)
    {        
        string sql = $@"SELECT * FROM dbo.shorturl WHERE shortUrl = '{ shortUrl }'";
        var originalURLEnum = SqlDataAccess.LoadData<ShortURLModel>(sql); //<--- problem
        return originalURLEnum.First();
    }
}

但是SqlDataAccess没有实例化,为了做到这一点,var _sqldataaccess = SqlDataAccess()我需要传入一个在类的构造函数中定义的参数。我不知道要传递什么?ShortUrlProcessor我在这个类中没有任何 IconfigurationManager 。我知道这样做的原因是依赖注入,但是我仍然不明白这一切是如何工作的?

标签: c#asp.net-mvcasp.net-coredependency-injectionasp.net-core-mvc

解决方案


你已经很接近了,但你需要解决一些问题。SqlDataAccess 实现 IConfigManager。为什么?那提供什么?相反,您应该让它实现一个接口,允许它公开其他类所依赖的功能。

public interface ISqlDataAccess
{
    List<T> LoadData<T>(string sql);

    int SaveData<T>(string sql, T data);  
}

更改您的 SqlDataAccess 类以实现此接口...

public class SqlDataAccess : ISqlDataAccess

当然,将它与您的 DI 容器连接起来。

services.AddTransient<ISqlDataAccess, SqlDataAccess>();

现在,任何需要运行 SQL 的类都可以依赖 ISqlDataAccess 接口,利用构造函数注入来获取 ISqlDataAccess 的实例。由于我们已经告诉 DI 容器在存在 ISqlDataAccess 依赖项时提供一个 SqlDataAccess 实例,因此它将在您的应用程序中很好地连接起来。

然后我们遇到了 ShortUrlProcessor 的问题。您将该类声明为静态的。这很糟糕,因为它很难使用构造函数注入来获取其依赖项,并且任何其他需要调用其方法的类都必须直接这样做,而不是通过抽象。这违反了SOLID的依赖倒置原则。由于可维护性和可测试性,我们应该始终努力编写 SOLID 代码,因此我们需要解决这个问题。

public class ShortUrlProcessor : IShortUrlProcessor
{    
    readonly ISqlDataAccess _dataAccess;

    public ShortUrlProcessor(ISqlDataAccess dataAccess)
    {
        _dataAccess = dataAccess;
    }
    
    public ShortURLModel GetOriginalURL(string shortUrl)
    {        
        string sql = $@"SELECT * FROM dbo.shorturl WHERE shortUrl = '{ shortUrl }'";
        var originalURLEnum = _dataAccess.LoadData<ShortURLModel>(sql); //<--- problem
        return originalURLEnum.First();
    }
}

我们需要一个接口,这样其他类就不必直接依赖 ShortUrlProcessor...

public interface IShortUrlProcessor
{
    ShortURLModel GetOriginalURL(string shortUrl);
}

当然,我们需要将它注册到我们的 DI 容器中。

services.AddTransient<IShortUrlProcessor, ShortUrlProcessor>();

然后任何需要访问 ShortUrlProcessor 功能的类都可以通过抽象 IShortUrlProcessor 来实现。你提到你有一个控制器调用这个,所以让我们也把它连接起来。

public class MyController()
{
    readonly IShortUrlProcessor _shortUrlProcessor;

    public MyController(IShortUrlProcessor shortUrlProcessor)
    {
        _shortUrlProcessor = shortUrlProcessor;
    }

    public ActionResult SomeActionMethod()
    {
        var model = _shortUrlProcessor.GetOriginalURL("asdf");
        return View(model);
    }
}

我们不必为控制器创建接口,因为控制器将被框架调用。而且我们不必将控制器与 DI 容器连接起来,因为框架会为我们处理这些。

通过这样做,我们可以轻松地单独测试各个方法。仍有一些改进需要改进(我在评论中提到的 SQL 注入攻击需要修复),但这是朝着正确方向迈出的良好一步。


推荐阅读