Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
214 views
in Technique[技术] by (71.8m points)

c# - Injecting DbContext into service layer

How am I supposed to inject my MyDbContext into my database service layer 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;
        }
    }
}

In my GetUser method, I know I am supposed to be using my injected MyDbContext here but I am not quite sure how to fetch it. Which piece of the puzzle am I missing?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You don't have to include the dbcontext yourself, ASP.NET core dependency injection service will do this for you.

You have just to declare your services and your database context in your startup class, and put the dbcontext you need in your service's constructor :

Startup.cs (your have to choose the service lifetime you want, here it's a scoped service, once per request):

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

Your service class:

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

In your controller, you have to declare the services (or the database context) you need to use in the same way :

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

Note about the controller : you don't have to add them in your startup class like you do with your database context or your services. Just implement their constructor.

If you need more information about the .NET Core depencency injection, the official documentation is clear and very complete : https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection


NB: In the startup.cs, the AddScoped line is an option. Your can choose the lifetime you want for your service. There is the different lifetimes you can choose :

Transient

Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless services.

Scoped

Scoped lifetime services are created once per request.

Singleton

Singleton lifetime services are created the first time they are requested (or when ConfigureServices is run if you specify an instance there) and then every subsequent request will use the same instance.

Above taken from: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection


Note: It's not the question here but your GetUser data query looks like a little strange to me. If your count()==1 goal is to check the unicity of the user, the good way is to add a unicity constraint in your database. If count()==1 goal is to check you have data to avoid a object null reference exception, you can use .FirstOrDefault(), it will manage this for you. You can simplify this method :

public User GetUser(string username) => (from u in _context.User where u.WindowsLogin == username select u).FirstOrDefault();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...