为了访问我的应用程序,我一直在遵循本教程。json从我的MVC项目在我的类库。geek-tutorial
在我的类库中有一个这样的类
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启动。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
类中没有任何iconfigationmanager。我理解这样做的原因是依赖注入,但我仍然没有掌握这一切是如何工作的?
你已经非常接近了,但是你需要修正一些事情。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注入攻击需要修复),但这是朝着正确方向迈出的一大步。