Реализация фабрики "Хранилище Ротатор" - PullRequest
0 голосов
/ 15 мая 2019

У меня есть приложение .Net Core Web API. Есть некоторый метод Get в контроллере и внедренный IRepositoryProviderFactory. Ничего особенного.

[ApiController]
public class DataController : ControllerBase
{
    private readonly ILogger<DataController> _logger;
    private readonly IRepositoryProviderFactory _repositoryProviderFactory;

    #region ctor

    /// <summary>
    /// ctor
    /// </summary>
    public DataController(ILogger<DataController> logger, IRepositoryProviderFactory repositoryProviderFactory)
    {
        _logger = logger;
        _repositoryProviderFactory = repositoryProviderFactory;
    }

    [HttpPost]
    public async Task<IActionResult> GetData([FromBody] SearchModel model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        try
        {
            var data = await _repositoryProviderFactory.GetDataAsync(model);

            return Ok(data);

        }
        catch (Exception ex)
        {
            return StatusCode((int)HttpStatusCode.InternalServerError);
        }
    }
}

Существуют репозитории, основанные на одном и том же интерфейсе для получения данных из разных источников данных.

public Repository1: IDataRepository {}
public Repository2: IDataRepository {}
public Repository3: IDataRepository {}

Я использую DI, поэтому все части зарегистрированы в службах как Scoped или Transient. Некоторые репозитории используют EntityFramework.

services.AddScoped<IDataRepository, Repository1>();
services.AddScoped<IDataRepository, Repository2>();
services.AddScoped<IDataRepository, Repository3>();

Хорошо, теперь мне нужно реализовать RepositoryProviderFactory для возврата репозитория. Но есть одна необходимая функциональность: она должна возвращать для каждого звонка разные репозитории .

Я ввел IEnumerable, и мне нужно вернуть Repository1, Repository2, Repository3 и снова Repository1, ... и т. Д. Таким образом, все репозитории используются одновременно.

/// <summary>
/// ctor
/// </summary>
public RepositoryProviderFactory(
    ILogger<RepositoryProviderFactory> logger,
    IEnumerable<IDataRepository> dataRepositories)
{
    _logger = logger;
    _dataRepositories = dataRepositories;
}

public IDataRepository GetRepository()
{
   // TODO: Logic to cycle repositories

    var instance = dataRepositories.Where();

    return instance;
}

Как это сделать?

Фабрика не может быть зарегистрирована как Singleton, потому что у репозиториев есть другие зависимости, у которых есть Scoped Lifetime (DbContext и т. Д.)

Как я могу создать какой-то потокобезопасный одноэлементный объект, чтобы иметь возможность сохранять последний использованный репозиторий и обслуживать другой для другого вызова?

1 Ответ

0 голосов
/ 16 мая 2019

Ну, я так и сделал.

Я создал класс GlobalAppData и зарегистрировался как Singleton.

services.AddSingleton<GlobalAppData>();

Затем я сделал простую реализацию (еще не законченную).

public class GlobalAppData
    {
        private IDataRepository[] _availableRepositories;
        private IDataRepository_lastUsedRepository;

        /// <summary>
        /// ctor
        /// </summary>
        public GlobalAppData()
        {
            _availableRepositories = new IDataRepository[0];
        }

        public void TryRegisterRepositories(IEnumerable<IDataRepository> repositories)
        {
            if (_availableRepositories.Length > 0)
            {
                return;
            }

            _availableRepositories = repositories.ToArray();

            _lastUsedRepository = null;
        }

        public IDataRepository GetNextRepository()
        {
            if (_lastUsedRepository == null)
            {
                _lastUsedRepository = _availableRepositories[0];
                return _lastUsedRepository;
            }

            var lastUsedIndex = _availableRepositories.IndexOf(_lastUsedRepository);
            if (lastUsedIndex < _availableRepositories.Length - 1)
            {
                lastUsedIndex++;
            }
            else
            {
                lastUsedIndex = 0;
            }

            _lastUsedRepository = _availableRepositories[lastUsedIndex];
            return _lastUsedRepository;
        }
    }

Тогда из-за DI будут храниться оригинальные экземпляры, а не внедренные, я сделал простое сравнение на фабрике.

        var instanceData = _globalAppData.GetNextRepository();
        var instance = _repositories.SingleOrDefault(r => r.GetType() == instanceData.GetType());

Не идеально, но работает как начало.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...