在我的MVC 6项目中,我有ApplicationDBContext
类
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(ModelBuilder builder)
{
}
}
这已添加到Startup.cs
中的我的服务中public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
//Other configurations removed for brevity
}
现在,当我创建一个新的Controller时,它询问我是否要使用Entity Framework,我可以选择我的数据上下文。当创建该控制器时,使用我假设的依赖注入在构造函数中传递上下文。
public class CompanyController : Controller
{
private ApplicationDbContext _context;
public CompanyController(ApplicationDbContext context)
{
_context = context;
}
}
现在,我不想在控制器中进行所有数据库交互,而是在我的其他类中进行。我无法弄清楚的是,如何从我的其他类中获取ApplicationDbContext。从控制器传递它显然不会起作用,因为可以从控制器以外的其他地方调用类。
如果我只是尝试new ApplicationDbContext();
,我会收到以下错误:
No database providers are configured. Configure a database provider by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.
我觉得这应该是简单的事情,但我完全迷失在这里。
答案 0 :(得分:3)
ASP.NET Core基于依赖注入,因为您的上下文已添加到您的dependendy容器中,当您的控制器实例化时,它会由框架自动注入。
您可以设置课程以支持DI,假设您有两个课程。一个取决于你的背景,然后取决于你的背景和你的第一堂课:
public class MyClass
{
private ApplicationDbContext _context;
public MyClass(ApplicationDbContext context)
{
_context = context;
}
}
public class AnotherClass
{
private ApplicationDbContext _context;
private MyClass _myClass;
public AnotherClass(ApplicationDbContext context, MyClass myClass)
{
_context = context;
_myClass = myClass;
}
}
在启动时将您的类添加为服务集合中的瞬态依赖项,并让服务提供商为您解析它们的依赖项:
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddTransient<MyClass>();
services.AddTransient<AnotherClass>();
//Other configurations removed for brevity
}
将您的控制器更改为接受MyClass作为注入依赖项:
public class CompanyController : Controller
{
private ApplicationDbContext _context;
private MyClass _myClass;
public CompanyController(ApplicationDbContext context, MyClass myClass)
{
_context = context;
_myClass = myClass;
}
}
您还可以使用另一个将AnotherClass作为注入依赖项的控制器:
public class AnotherController : Controller
{
private AnotherClass _anotherClass;
public AnotherController(AnotherClass anotherClass)
{
_anotherClass = anotherClass;
// _anotherClass will have both ApplicationDbContext and MyClass injected by the service provider
}
}
您应该阅读ASP.NET核心依赖注入的docs,它可以帮助理解DI的基础知识。来自K. Scott Allen的另一个article解释了在处理DI时的一些不良做法。
答案 1 :(得分:2)
您可以创建一个以与控制器相同的方式接收DbContext的服务类。
public class SomeService
{
private ApplicationDbContext MyDbContext { get; set; }
public SomeService(ApplicationDbContext dbContext)
{
MyDbContext = dbContext;
}
public void MethodName()
{
// You can now do MyDbContext.SomeDomainModel
}
}
然后使用ConfigureServices
方法在Startup.cs中注册该服务。
public void ConfigureServices(IServiceCollection services) {
// <snipped>
services.AddTransient<SomeService>();
}
现在,在您的CompanyController
中,您可以在SomeService
的构造函数中添加另一个参数,就像您对ApplicationDbContext
一样。
public class CompanyController : Controller
{
private ApplicationDbContext _context;
private SomeService _someService;
public CompanyController(ApplicationDbContext context, SomeService someService)
{
_context = context;
_someService = someService;
}
}
所有这一切,我都不认为在控制器操作中使用逻辑来构建ViewModel,访问DbContext有什么问题。 DbContext是将业务逻辑(在控制器中)与DAL分开的原因。有些人可能不同意我的观点,但您不需要添加额外的服务来进一步分离它们。操作方法中的大多数代码对于该操作都是唯一的,不会被其他操作重用。 IMO,那些是放入服务的代码片段。比如发送电子邮件等等。