代码之家  ›  专栏  ›  技术社区  ›  gilliduck

动态连接字符串的dbcontext依赖注入

  •  0
  • gilliduck  · 技术社区  · 6 年前

    下面是一个简单但实用的示例,大致说明了如何进行依赖项注入。当我的dbcontext连接字符串不是动态的时,这非常有用。即使它是通过配置文件或其他方式传递到工厂的,只要它一直是同一个就没关系。

    我需要了解的是如何对下面的代码进行(最好是小的)修改,以便在运行时动态地确定连接字符串。

    例如,假设在视图上,用户不仅可以选择要传递到控制器的post方法的教师,而且还可以选择学校。如果为了简单起见,有两个学校有完全相同的数据库结构,但有不同的连接字符串,我如何从控制器到工厂?

    我曾尝试过将一个值从一个方法传递到另一个方法,但这对于大型项目来说并不是真正可持续的,它增加了出错的可能性,而且总的来说,像这样从一个层传递到另一个层只是一团乱(除了违反实体)。 (如果需要的话,我可以添加我所做的不太理想的尝试,为了简洁起见,我省略了它们,因为这已经是一个相当长的问题,代码示例和所有这些都是什么)。

    控制器

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

    服务

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

    存储库

    public class DataRepo : IDataRepo
    {
        private readonly SchoolContext _context;
    
        public DataRepo()
        {
            _context = ContextFactory.MakeContext();
        }
    
        public IEnumerable<Course> GetCourses()
        {
            return _context.Courses;
        }
    }
    

    上下文工厂

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

    单位配置

        public static void RegisterComponents()
        {
            var container = new UnityContainer();
    
            container.RegisterType<IDataService, DataService>();
            container.RegisterType<IDataRepo, DataRepo>();
    
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Haitham Shaddad    6 年前

    首先,您必须决定如何使用当前连接字符串。是通过一个网址吗?或者使用当前用户或其他方式。

    然后,创建另一个数据库,该数据库在连接字符串和所选方法(用户、url…)之间具有映射。

    最后,实现一种从数据库中获取记录的方法。

    因此,假设您将使用url作为当前租户的标识符,那么您的实体类应该如下所示:

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

    表示获取当前租户的逻辑的接口:

    public interface ICurrentTenantService
    {
      Tenant GetCurrentTenant();
    }
    

    现在你要把它的实现

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

    现在您必须像这样将上下文工厂连接到租户服务

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