Dependency injection between two ASP.NET Core projects

痴心易碎 提交于 2021-02-09 12:46:16

问题


I'm currently developing a web application with ASP.NET Core and handling the database with Entity Framework Core. I have two projects in my VS Solution; WebApp (the main application) and DatabaseHandler (the EF Core handler). I have installed Entity Framework Core with the Pomelo package, since I'm using a MySQL database.

I've been following the Microsoft documentation to setup EF Core, connection strings and all that, and it works fine. I'm able to make migrations, make updates and do stuff with the database. I'm however not sure if I'm doing it correctly, since the latest EF Core tutorials use dependency injection and I'm not familiar with it.

Right now I'm passing the DbContext object as an argument from WebApp to DatabaseHandler, since I want all database-related stuff to only exist in DatabaseHandler. This works, but is it possible to call functions from another project and also share the DbContext object without passing it as an argument? I'm probably not explaining it well, I hope my code explains it better.

WebApp/Startup.cs:
This is where I load the connection string from appsettings.json.

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContextPool<DataContext>(
        options => options.UseMySql(Configuration.GetConnectionString("DefaultConnection")
    ));

    services.AddRouting(options => options.LowercaseUrls = true);
    services.AddControllersWithViews();
}

WebApp/HomeController.cs:
This is where I call the GetAllChallenges() function from the DatabaseHandler project, and I also pass the DataContext object as an argument. This is what I'm trying to avoid!

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly DataContext db;

    public HomeController(ILogger<HomeController> logger, DataContext _db)
    {
        _logger = logger;
        db = _db;
    }

    public IActionResult Challenges()
    {
        List<Challenge> ChallengesList = DatabaseHandler.HandleChallenges.GetAllChallenges(db);
        return View(ChallengesList);
    }
}

DatabaseHandler/DataContext.cs:
This is where I initialize the entity classes and so on.

public class DataContext : DbContext
{
    public DataContext(DbContextOptions<DataContext> options) : base(options) { }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { }

    // Tables
    public DbSet<User> Users { get; set; }
    public DbSet<Challenge> Challenges { get; set; }

    // Data seeding
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Seed();
    }
}

DatabaseHandler/HandleChallenges.cs:
This is where I have all my database functions. The results are returned back to the controller within the WebApp project.

public class HandleChallenges
{
    public static List<Challenge> GetAllChallenges(DataContext db)
    {
        var Data = db.Challenges;
        List<Challenge> ChallengesList = Data.ToList();
        return ChallengesList;
    }
}

I have looked into dependency injection, but I'm not sure how I can use this between two projects. Is there a less complicated way of achieving this, perhaps without using DI at all? I'm satisfied as long as I don't need to pass the DataContext object as an argument every time I need to call a function from DatabaseHandler.

Can someone help me understand? Thanks a lot in advance!


回答1:


You could use Options pattern, which I have already used many times. Its working very well despite of database you use. Thanks to dependency injection you are able to access if from multiple projects. Reading documentation about Option pattern (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1) is useful but I will also provide you with my own example :

  1. First you create model to store you connection string, dbName etc. Remember to add it in a library outside your main project(eg. Web Api) :

     public class NameOfYourProject_ApiDbSettings : IIMTTApiDbSettings
     {
         public NameOfYourProject_ApiDbSettings()
         {
         }
         public string CollectionName { get; set; }
         public string ConnectionString { get; set; }
         public string DatabaseName { get; set; }
     }
    
    
    public interface I_NameOfYourProject_ApiDbSettings
    {
     string CollectionName { get; set; }
     string ConnectionString { get; set; }
     string DatabaseName { get; set; }
    }
    
  2. Secondly you make it available for all you projects :

        services.Configure<NameOfYourProjectApiDbSettings>(options =>
         {
             options.ConnectionString
                 = Configuration.GetSection("NameOfYourProjectDbSettings:ConnectionString").Value;
             options.DatabaseName
                 = Configuration.GetSection("NameOfYourProjectDbSettings:DatabaseName").Value;
         });
    
  3. Then you can use it in multiple projects. (Rememebr to add referance to you model -> point 1. I keep the model always with repository) I will give you my example where I use MongoDb :

     private readonly IMongoDatabase _database = null;
    
     public SomeObjectContext(IOptions<IMyProjectDbSettings> settings)
     {
         var client = new MongoClient(settings.Value.ConnectionString);
         if (client != null)
             _database = client.GetDatabase(settings.Value.DatabaseName);
     }
    
     public IMongoCollection<MyModel> MyModels
     {
         get
         {
             return _database.GetCollection<MyModel>("MyModels");
         }
     }
    



回答2:


You need to extract an interface from the class (note the method is no longer static) and add a constructor for the context:

public interface IHandleChallenges
{
    List<Challenge> GetAllChallenges();
}

public class HandleChallenges : IHandleChallenges
{
    public HandleChallenges(DataContext context)
    {
        db = context;
    }
    
    private DataContext db;
    
    public List<Challenge> GetAllChallenges()
    {
        var Data = db.Challenges;
        List<Challenge> ChallengesList = Data.ToList();
        return ChallengesList;
    }
}

Then register it as a service:

 services.AddScoped<IHandleChallenges, HandleChallenges>();
 

Your controller now receives this class in it's constructor instead of the context:

private IHandleChallenges _challengeHandler;
public HomeController(ILogger<HomeController> logger, IHandleChallenges challengeHandler)
{
    _logger = logger;
    _challengeHandler = challengeHandler;
}

And calls it from the action:

public IActionResult Challenges()
{
    List<Challenge> ChallengesList = _challengeHandler.GetAllChallenges();
    return View(ChallengesList);
}


来源:https://stackoverflow.com/questions/62994950/dependency-injection-between-two-asp-net-core-projects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!