DbContext 的依赖关系注入与动态 ConnString



下面是一个简单但功能强大的示例,大致说明了我将如何进行依赖注入。当我的 DbContext 连接字符串不是动态的时,这非常有用。即使它通过配置文件或其他文件传递给工厂,只要它始终是相同的,也没关系。

我需要的是围绕如何对以下代码进行(理想情况下是次要的(修改,以允许在运行时动态确定连接字符串。

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

我已经尝试过将值从一个方法传递到另一个方法,但这对于大型项目来说并不可持续,增加了出错的可能性,而且总的来说,像这样在层之间传递一些东西是很混乱的(除了违反 SOLID 之外(。(如果需要,我可以添加我所做的不完全理想的尝试,为了简洁起见,我省略了它们,因为这已经是一个相当长的问题,代码示例和所有内容(。

控制器

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

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

然后,创建另一个数据库,该数据库在连接字符串和所选方法(用户、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);
}
}

最新更新