Sto cercando di aggiornare alcune delle mie società con codice esistente per consentire l'implementazione dei test unitari. Per essere in grado di farlo, tutti i repository sono interfacciati per consentire DI. Tuttavia, il codice esistente ha l'abitudine di creare 1 classe repository per tabella nel database, il che significa che una sezione della logica aziendale potrebbe dover interrogare 5 diverse classi di repository.
Passare in 5+ interfacce usando DI sembra complicato e sto cercando aiuto su come ridisegnarlo.
Questo è tutto per un sito MVC 5 C #, e un esempio è riportato di seguito (ho ridotto le dimensioni del codice in modo che sia più facile da leggere).
Abbiamo il nostro controller per Account, che in questo scenario gestisce le sessioni utente:
public class AccountController : Controller
{
private AccountLogic _accountLogic { get; set; }
public AccountController(
ISessionRepository sessionRepository,
ILoginRepository loginRepository)
{
_accountLogic = new AccountLogic(sessionRepository, loginRepository);
}
public IActionResult Index()
{
return View();
}
public IActionResult Login()
{
return View();
}
public IActionResult Login(LoginModel loginModel)
{
if (ModelState.IsValid)
{
if (_accountLogic.DoesUserExist(loginModel.Username))
{
var existingHash= _accountLogic.GetPassword(loginModel.Username);
if (Hash.VerifyPassword(loginModel.Password, existingHash))
{
// Set Auth Cookies
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError(
"Username",
"Sorry, we did not recognize " +
"either your username or password");
}
}
}
return View(loginModel);
}
}
Il team cerca di ridurre le dimensioni del controller facendo in modo che una classe business esegua la maggior parte delle azioni. Ciò che questo significa in realtà è che la business class è molto grande e ha molte responsabilità in quanto deve essere passata un'interfaccia per tutti i repository che deve interrogare. Nell'esempio mostrato, passiamo sia nei repository Session che Login, ognuno dei quali è l'unico responsabile delle rispettive tabelle nel database.
public class AccountLogic
{
private ISessionRepository _sessionRepository { get; set; }
private ILoginRepository _loginRepository { get; set; }
public AccountLogic(
ISessionRepository sessionRepository,
ILoginRepository loginRepository)
{
_sessionRepository = sessionRepository;
_loginRepository = loginRepository;
}
public Guid CreateSession(int loginID, string userAgent, string locale)
{
return _sessionRepository.CreateSession(loginID, userAgent, locale);
}
public Session GetSession(Guid sessionKey)
{
return _sessionRepository.GetSession(sessionKey);
}
public void EndSession(Guid sessionKey)
{
_sessionRepository.EndSession(sessionKey);
}
public bool DoesUserExist(string username)
{
return _loginRepository.DoesUserExist(username);
}
public string GetPassword(string username)
{
return _loginRepository.GetPassword(username);
}
}
Abbiamo quindi la classe AccountLogic, che gestisce tutte le logiche di business. Nell'esempio fornito, non vi è alcuna logica complicata da eseguire, quindi diventa puramente una chiamata a catena ai metodi di interfaccia.
La mia domanda è: come possiamo renderlo più facile da maneggiare, ma anche testabile su una scala più ampia? Se avessi un controller che ha bisogno di interrogare 10 diversi repository, sicuramente non è gestibile passare 15 interfacce al controller e quindi a una business class rilevante? Abbiamo bisogno di cambiare il modo in cui i repository sono gestiti in modo che non ci sia una classe per tabella?