将DbContext注入服务层

时间:2016-12-09 10:21:44

标签: 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();
}

MyDbContext.cs

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

    public MyDbContext(DbContextOptions<MyDbContext> options)
    :base(options)
    {
    }
}

appsettings.json

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=MyServer;Database=MyDatabase;user id=MyUser;password=MyPassword;"
  }
}

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;
        }
    }
}

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

1 个答案:

答案 0 :(得分:21)

您不必自己包含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>();
}

您的服务类:

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);
}

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

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
      }
}

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

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

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

  

<强>瞬态

     

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

     

<强>作用域

     

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

     

<强>的Singleton

     

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();