下面是一个简单但实用的示例,大致说明了我如何进行依赖注入。当我的DbContext连接字符串不是动态的时,这非常有用。即使已通过配置文件或其他方式将其传递到工厂,也没关系,只要一直保持相同即可。
我需要围绕如何对以下代码进行(理想的)较小修改,以允许在运行时动态确定连接字符串。
例如,说在View上,用户不仅可以选择要传递到控制器的Post方法中的老师,还可以选择学校。为简单起见,如果有两所学校具有完全相同的数据库结构,但是具有不同的连接字符串,如何将其从控制器下放到工厂?
我已经尝试过在方法之间传递值,但是这对于大型项目而言实际上是不可持续的,增加了出错的可能性,并且总体上来说,将某些东西从层传递到其他地方只是一团糟(除了违反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);
}
}
UnityConfig
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IDataService, DataService>();
container.RegisterType<IDataRepo, DataRepo>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
答案 0 :(得分:1)
首先,您必须确定如何获取当前使用的连接字符串。通过URL吗?或使用当前用户或其他任何方式。
然后,创建另一个数据库,该数据库在连接字符串和您选择的方法(用户,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);
}
}