Внедрение зависимостей DbContext с динамическим ConnString - PullRequest
0 голосов
/ 10 октября 2018

Ниже приведен простой, но функциональный пример того, как я бы делал Dependency Injection.Это прекрасно работает, когда моя строка подключения DbContext не является динамической.Даже если он передается на завод через конфигурационный файл или что-то еще, это не имеет значения, если он все время один и тот же.

Мне нужно только обернуть голову, как сделать ((в идеале незначительные) изменения в приведенном ниже коде, позволяющие динамически определять строку подключения во время выполнения.

Например, скажем, в представлении пользователь мог не только выбрать учителя, который будет передан вМетод пост контроллера, но и школа.Если для простоты, есть 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);
    }
}

UnityConfig

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

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

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

1 Ответ

0 голосов
/ 10 октября 2018

Во-первых, вы должны решить, как вы собираетесь использовать текущую строку подключения.Это через URL?или используя текущего пользователя или любым другим способом.

Затем создайте другую базу данных, в которой сопоставление между строками подключения и выбранным вами методом (user, 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);
    }
}
...