Короче говоря, это тип контроллеров, которые я вижу в каждой кодовой базе профессионально:
//All in One Service interfaces
public class DiController : ControllerBase
{
private readonly IDiService _diService;
public DiController(IDiService diService)
{
_diService = diService;
}
[HttpGet]
public IActionResult GetA()
{
return Ok(_diService.GetA());
}
[HttpGet]
public IActionResult GetB()
{
return Ok(_diService.GetB());
}
}
//Task-based interfaces
public class DiController : ControllerBase
{
private readonly IAService _aService;
private readonly IBService _bService;
public DiController(IAService aService, IBService bService)
{
_aService = aService;
_bService = bService;
}
[HttpGet]
public IActionResult GetA()
{
return Ok(_aService.Handle());
}
[HttpGet]
public IActionResult GetB()
{
return Ok(_bService.Handle());
}
}
Теперь, чтобы сохранить небольшой размер поста, представьте, что у вас есть один репозиторий для A и другой для B, который будет использоваться сервисами. Каждый компонент здесь Scoped (один и тот же объект для каждого запроса). Неважно, что вы выбираете, вы в конечном итоге в такой ситуации:
Это относится к интерфейсу на основе задач, и, как вы можете видеть, вы не используете службу B, но получаете один экземпляр независимо. В другом случае вам будут созданы два репозитория.
Чтобы решить эту проблему, я использовал следующие фабрики:
1 - Абстрактный класс, который содержит контейнер и свойство, которое предоставляет экземпляр типа.
public interface IGenericFactory<out T>
{
T Service { get; }
}
public abstract class GenericFactory<T> : IGenericFactory<T> where T : class
{
private readonly Container _container;
public T Service => _container.GetInstance<T>();
protected GenericFactory(Container container)
{
_container = container;
}
}
2 - интерфейс для регистрации в контейнере
public interface IAServiceFactory : IGenericFactory<IAService>
{
}
3- Класс для регистрации в контейнере
public class AServiceFactory : GenericFactory<IAService>, IAServiceFactory
{
public AServiceFactory(Container container) : base(container)
{
}
}
4- Зарегистрируйте фабрики как Singletons, а сервисы как Scoped / Transient (в зависимости от варианта использования). Вот пример (в Simple Injector) того, как выполняется регистрация для контроллера интерфейса на основе задач:
_container.Register<IAService, AService>(Lifestyle.Scoped);
_container.Register<IBService, BService>(Lifestyle.Scoped);
_container.Register<IAServiceFactory, AServiceFactory>(Lifestyle.Singleton);
_container.Register<IBServiceFactory, BServiceFactory>(Lifestyle.Singleton);
Конечный продукт будет таким:
Экземпляр A, а не B.
Это правильно? Я участвовал в проектах, в которых у вас было бы дюжина Сервисов или Репозитариев, и только один из них использовался бы в каждом вызове.
Спасибо.