简体   繁体   English

动态ConnString对DbContext的依赖注入

[英]Dependency Injection of DbContext with Dynamic ConnString

Below is a simple but functional example of roughly how I would do Dependency Injection. 下面是一个简单但实​​用的示例,大致说明了我如何进行依赖注入。 This works great when my DbContext connection string is not dynamic. 当我的DbContext连接字符串不是动态的时,这非常有用。 Even if it's passed in to the factory through a config file or whatever, it doesn't matter so long as it's the same one all the time. 即使通过配置文件或其他方式传递到工厂,也没关系,只要一直保持相同即可。

What I need is to wrap my head around how to make (ideally minor) modifications to the below code to allow for the connection string to be determined dynamically at run time. 我需要围绕如何对以下代码进行修改(最好是较小的修改),以允许在运行时动态确定连接字符串。

For example, say on the View the user was able to not only select the teacher to be passed into the Post method of the controller, but also the school. 例如,在“视图”上说,用户不仅可以选择要传递到控制器的Post方法中的老师,还可以选择学校。 If, for simplicity sake, there are 2 schools that have the exact same database structure, but have different connection strings how do I get that down from the controller to the factory? 如果为了简单起见,有2个学校具有完全相同的数据库结构,但是具有不同的连接字符串,如何将其从控制器下放到工厂?

I've experimented with passing a value from method to method, but this isn't really sustainable for large projects, increases the likelihood of errors and overall is just messy (besides violations of SOLID) to be passing something from layer to layer like that. 我已经尝试过在方法之间传递值,但是对于大型项目而言,这实际上是不可持续的,增加了出错的可能性,并且总体上来说,像这样逐层传递某些东西是混乱的(除了违反SOLID) 。 (If desired I can add the not exactly ideal attempts I've made, I've omitted them for brevity sake since this is already a fairly long question what with the code examples and all). (如果需要,我可以添加我所做的不完全理想的尝试,为简洁起见,我将其省略了,因为这已经是一个相当长的问题,对代码示例和所有内容而言都是如此)。

Controller 调节器

public class HomeController : Controller
{
    private readonly IDataService _dataService;

    public HomeController(IDataService dataService)
    {
        _dataService = dataService;
    }

    public ActionResult Index()
    {

        var results = _dataService.GetTeachers();
        var model = new ViewModel
        {
            Teachers = results
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(ViewModel model)
    {
        var results = _dataService.GetCourses(model.Teacher);
        model.Courses = new List<string>(results);
        return View(model);
    }
}

Service 服务

public class DataService : IDataService
{
    private readonly IDataRepo _dataRepo;

    public DataService(IDataRepo dataRepo)
    {
        _dataRepo = dataRepo;
    }

    public List<string> GetCourses(string teacherName)
    {
        return _dataRepo.GetCourses()
            .Where(c => c.Teacher.FirstName == teacherName)
            .Select(c => c.Name)
            .ToList();
    }

    public List<string> GetTeachers()
    {
        return _dataRepo.GetCourses()
            .Select(c => c.Teacher.FirstName)
            .ToList();
    }
}

Repository 知识库

public class DataRepo : IDataRepo
{
    private readonly SchoolContext _context;

    public DataRepo()
    {
        _context = ContextFactory.MakeContext();
    }

    public IEnumerable<Course> GetCourses()
    {
        return _context.Courses;
    }
}

Context Factory 上下文工厂

public static class ContextFactory
{
    public static SchoolContext MakeContext()
    {
        var connString =
            "connStringA";
        return new SchoolContext(connString);
    }
}

UnityConfig UnityConfig

    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        container.RegisterType<IDataService, DataService>();
        container.RegisterType<IDataRepo, DataRepo>();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }

First, you have to decide how are you going to get the current connection string to use. 首先,您必须决定如何获取当前使用的连接字符串。 Is it through a URL? 通过URL吗? or using the current user or whatever other way. 或使用当前用户或其他任何方式。

Then, create another database that has a mapping between the connection strings and the method you chose (user, url ...) 然后,创建另一个数据库,该数据库在连接字符串和您选择的方法(用户,URL ...)之间具有映射

Lastly, implement a way to get the record from the database. 最后,实现一种从数据库获取记录的方法。

so, assuming that you will use the URL as an identifier for the current tenant, your entity class should be like this: 因此,假设您将URL用作当前租户的标识符,则您的实体类应如下所示:

public class Tenant
{
   public string Url {get;set;}
   public string ConnectionString {get;set;}
}

An interface that represents the logic to get the current tenant: 表示获取当前租户的逻辑的接口:

public interface ICurrentTenantService
{
  Tenant GetCurrentTenant();
}

And now you will put its implementation 现在您将执行它

public class CurrentTenantService : ICurrentTenantService
{
  public Tenant GetCurrentTenant()
   {
      string currentUrl = HttpContext.Current.Url; //make sure to get only the base URL here
      return TenantDbContext.Tenants.FirstOrDefault(t=>t.Url == url); //TenantDbContext should be a class that has the Tenant entity
   }
}

Now you have to wire up the context factory to the tenant service like this 现在,您必须像这样将上下文工厂连接到租户服务

public static class ContextFactory
{
    private readonly ICurrentTenantService currentTenantService;
   //Inject it in the constructor

    public static SchoolContext MakeContext()
    {
        var currentTenant= currentTenantService.GetCurrentTenant(); //Check for NULL

        return new SchoolContext(currentTenant.ConnectionString);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM