我在.Net 8.0上创建了一个asp .net core mvc,
在这里,我创建了AppDbContext类:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<User> Users { get; set; }
}
DbRepo 类:
public class DbRepo
{
internal readonly AppDbContext db;
internal DbRepo(AppDbContext context)
{
this.db = context;
}
}
这是一个用户存储库,我需要在其中使用数据库上下文,可能有多个存储库:
public class UserRepository : DbRepo, IUser<User, User, string>
{
public async Task<bool> Create(User user)
{
try
{
if (!await IsExist(user))
{
await db.AddAsync(user);
}
return db.SaveChanges() > 0;
}
catch (Exception)
{
return false;
}
}
}
这里是用于松散耦合依赖项的 DataAccessFactory 类:
public class DataAccessFactory
{
public static IUser<User, User, string> UserData()
{
return new UserRepository();
}
}
现在服务将调用 dataAccessfactory 来存储库方法:
public class UserService
{
public static Task<bool> CreateUser(UserDTO newUser)
{
User user = UserMapping(newUser);
return DataAccessFactory.UserData().Create(user);
}
}
然后该服务将从控制器调用。问题是,应该为每个存储库提供一个继承 DbRepo 类的参数。
我该如何解决。
我在 Program.cs 中添加了这个
builder.Services.AddScoped<DbRepo>();
有一个令人困惑的细节,那就是
UserRepository
实现了一个名为 IUser
的接口。类名描述了存储或检索用户的内容。它不会是“用户”。但我要回避这个问题,因为无论如何都有可能回答这个问题。
这会干扰控制反转:
public class UserService
{
public static Task<bool> CreateUser(UserDTO newUser)
{
User user = UserMapping(newUser);
return DataAccessFactory.UserData().Create(user);
}
}
UserService
取决于
UserRepository
,但它控制它的创建方式。它将调用 DataAccessFactory.UserData().Create(user);
,它又调用 new UserRepository()
。按照它的写法,没有办法改变这种依赖关系。您可以摆脱 DataAccessFactory
并直接调用
new UserRepository()
,结果将是相同的。对 UserRepository
有固定的依赖。您可以像这样更改它,而不是UserService
做出该决定:
public class UserService
{
private readonly UserRepository _userRepository;
public UserService(UserRepository userRepository)
{
_userRepository = userRepository;
}
// no longer static
public Task<bool> CreateUser(UserDTO newUser)
{
User user = UserMapping(newUser);
return _userRepository.CreateUser
}
}
现在
UserService
不控制
UserRepository
的创建。必须有其他东西创建该存储库并将其传递给 UserService
构造函数。因此,现在参数不一定必须是 UserRepository
。它也可以是继承自
UserRepository
的任何类型。这意味着该类不再与该确切类型耦合。这是一个改进,但这就是我们经常添加像IUserRepository
这样的界面的地方。这并不是绝对必要的,但有充分的理由。
public interface IUserRepository
{
Task<bool> Create(User user);
}
UserRepository
将实现该接口。
然后我们将更改UserService
以依赖于接口而不是具体类。
public class UserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
// no longer static
public Task<bool> CreateUser(UserDTO newUser)
{
User user = UserMapping(newUser);
return _userRepository.CreateUser
}
}
现在
UserService
只知道界面。我们可以将任何实现它的类传递给它。这对于测试很有用。我们可以传递
IUserRepository
的伪造或模拟实现,它总是返回一些预期值,这样我们就可以验证 UserService
是否按照我们期望的方式响应它收到的各种结果。在运行时(当应用程序实际运行时),您可能希望 IUserRepository
的实现成为像
UserRepository
这样的特定具体类。假设您使用 Microsoft 的依赖项注入容器,您将在 Startup
或 Program
中拥有代码,用于使用 IServiceCollection
注册依赖项。 (如果不知道您的应用程序是如何配置的,我无法更具体。)在该方法中,您将配置应用程序以创建各种依赖项。例如,如果您已修改 UserService
以依赖于
IUserRepository
,则该代码可能如下所示:services.AddScoped<IUserRepository, UserRepository>();
这意味着
当您必须向某个类的构造函数提供
这里IUserRepository
时,请创建
的实例。 我掩盖了一些依赖注入。您可以在UserRepository
阅读更多内容。 但由于它与您的问题直接相关,因此此更改实现了控制反转。而不是
UserService
说
我需要一个存储库,因此我将创建一个存储库(从而控制它的创建方式)它说
请在创建我时将
IUserRepository
注入到我的构造函数中。我无法控制它的创建方式。应用程序控制它。