将DbContext注入服务层

Dan*_*len 16 c# entity-framework asp.net-core-mvc

我该如何将我的MyDbContext注入我的数据库服务层MyService

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<MyDbContext>(options =>
    options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
    services.AddMvc();
}
Run Code Online (Sandbox Code Playgroud)

MyDbContext.cs

public partial class MyDbContext : DbContext
{
    public virtual DbSet<User> User { get; set; }

    public MyDbContext(DbContextOptions<MyDbContext> options)
    :base(options)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

appsettings.json

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=MyServer;Database=MyDatabase;user id=MyUser;password=MyPassword;"
  }
}
Run Code Online (Sandbox Code Playgroud)

MyService.cs

public class MyService
{
    public User GetUser(string username)
    {
        // Should i remove this call and get the reference from the injection somehow?
        MyDbContext db_context = new MyDbContext(optionsBuilder.Options);
        using (db_context)
        {
            var users = from u in db_context.User where u.WindowsLogin == username select u;
            if (users.Count() == 1)
            {
                return users.First();
            }
            return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的GetUser方法中,我知道我应该使用我MyDbContext在这里注入,但我不太确定如何获取它.我错过了哪一块拼图?

Adr*_*ris 31

您不必自己包含dbcontext,ASP.NET核心依赖注入服务将为您执行此操作.

您只需在启动类中声明服务和数据库上下文,并将所需的dbcontext放在服务的构造函数中:

Startup.cs(你必须选择你想要的服务生命周期,这里它是一个范围的服务,每个请求一次):

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<MyDbContext>(options =>
    options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
    services.AddMvc();
    services.AddScoped<IMyService, MyService>();
}
Run Code Online (Sandbox Code Playgroud)

您的服务类:

public class MyService : IMyService
{
    private readonly MyDbContext _context;

    public MyService(MyDbContext ctx){
         _context = ctx;
    }

    public User GetUser(string username)
    {
        var users = from u in _context.User where u.WindowsLogin == username select u;
        if (users.Count() == 1)
        {
            return users.First();
        }
        return null;
    }
}

public interface IMyService
{
    User GetUser(string username);
}
Run Code Online (Sandbox Code Playgroud)

在您的控制器中,您必须以相同的方式声明您需要使用的服务(或数据库上下文):

public class TestController : Controller
{
     private readonly IMyService _myService;

      public TestController(IMyService serv)
      {
           _myService = serv;
      }

      public IActionResult Test()
      {
          return _myService.MyMethod(); // No need to instanciate your service here
      }
}
Run Code Online (Sandbox Code Playgroud)

关于控制器的注意事项:您不必像在数据库环境或服务中那样在启动类中添加它们.只需实现他们的构造函数.

如果您需要有关.NET Core依赖注入的更多信息,官方文档清晰且非常完整:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection


注意: 在startup.cs中,AddScoped行是一个选项.您可以选择所需的服务期限.您可以选择不同的生命周期:

短暂的

每次请求时都会创建瞬态生命周期服务.这种生命周期最适合轻量级无状态服务.

作用域

每个请求创建一次范围生命周期服务.

独生子

Singleton生命周期服务是在第一次请求时创建的(或者当您在那里指定实例时运行ConfigureServices时),然后每个后续请求将使用相同的实例.

以上摘自:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection


注意:这不是问题,但您的GetUser数据查询对我来说有点奇怪.如果你的count()== 1目标是检查用户的唯一性,那么好的方法是在数据库中添加unicity约束.如果count()== 1目标是检查你有数据以避免对象空引用异常,你可以使用.FirstOrDefault(),它会为你管理这个.您可以简化此方法:

public User GetUser(string username) => (from u in _context.User where u.WindowsLogin == username select u).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)