简体   繁体   English

实施“Repository Rotator”工厂

[英]Implementing “Repository Rotator” factory

I have .Net Core Web API application. 我有.Net Core Web API应用程序。 There is some Get method in controller and injected IRepositoryProviderFactory. 控制器中有一些Get方法,并注入了IRepositoryProviderFactory。 Nothing special. 没什么特别的。

[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);
        }
    }
}

There are repositories based on the same Interface to get data from different data sources. 存在基于相同接口的存储库以从不同数据源获取数据。

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

I'm using DI so all parts are registered in services as Scoped or Transients. 我正在使用DI,因此所有部件都在服务中注册为Scoped或Transients。 Some repositories are using EntityFramework. 一些存储库正在使用EntityFramework。

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

Ok, now I need to implement RepositoryProviderFactory to return repository. 好的,现在我需要实现RepositoryProviderFactory来返回存储库。 But there is one required functionality: it must return for every call different repository . 但是有一个必需的功能: 它必须为每个调用不同的存储库返回

I have injected IEnumerable and I need to return Repository1, Repository2, Repository3 and again Repository1, … etc. So all repositores are used the same time. 我注入了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;
}

How to do this? 这个怎么做?

Factory can't be registered as Singleton, because repositories have another dependencies that have Scoped Lifetime (DbContext etc.) Factory无法注册为Singleton,因为存储库具有另一个具有Scoped Lifetime的依赖项(DbContext等)

How can I create some thread safe singleton object to be able persists last used repository and serve another one, for another call? 如何创建一些线程安全的单例对象,以便能够持久保存最后使用的存储库并为另一个存储库提供服务,以进行另一个调用?

Well, I did it this way. 嗯,我是这样做的。

I made class GlobalAppData and registered is as Singleton. 我创建了类GlobalAppData并注册为Singleton。

services.AddSingleton<GlobalAppData>();

Then I made simple implementation (not finished yet). 然后我做了简单的实现(还没有完成)。

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;
        }
    }

Then because of DI there will be stored original instances, not injected ones, I made just simple compare in factory. 然后因为DI会存储原始实例,而不是注入的实例,我在工厂里做了简单的比较。

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

Not perfect, but it works as a start. 不完美,但它起初作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM