实施 "Repository Rotator" 工厂

Implementing "Repository Rotator" factory

我有 .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 或 Transients。一些存储库正在使用 EntityFramework.

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

好的,现在我需要将 RepositoryProviderFactory 实施到 return 存储库。但是有一个必需的功能:它必须 return 每次调用不同的存储库

我已经注入了 IEnumerable,我需要 return 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;
}

如何做到这一点?

工厂无法注册为单例,因为存储库有另一个具有作用域生命周期的依赖项(DbContext 等)

我如何创建一些线程安全的单例对象以能够保留上次使用的存储库并为另一个存储库提供服务,以供另一个调用?

好吧,我就是这样做的。

我创建了 class 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());

不完美,但可以作为一个开始。