簡體   English   中英

如何實現一個通用的DI?

[英]How to realize a generic DI?

我有多個服務和多個存儲庫。 我所有的服務都包含一個存儲庫和一個映射器。 所以,我創建了一個這樣的 BaseService:

public abstract class BaseService<TEntity, TRepository> : BaseService
        where TEntity : class, IEntity
        where TRepository : IRepository<TEntity>
    {
        #region Fields

        /// <summary>
        /// Data manager
        /// </summary>
        protected TRepository Repository { get; } =
            ServiceCollectionHelper.GetElementFromDependencyInjection<TRepository>();

        /// <summary>
        /// Mapper
        /// </summary>
        protected IMapper Mapper { get; } = ServiceCollectionHelper.GetElementFromDependencyInjection<IMapper>();

        #endregion
    }

    public abstract class BaseService
    {
    }

ServiceCollectionHelper

 public static class ServiceCollectionHelper
    {
        #region Fields

        /// <summary>
        /// Service collection
        /// </summary>
        private static IServiceProvider _serviceProvider = null;

        /// <summary>
        /// Service provider getter
        /// </summary>
        private static IServiceProvider ServiceProvider
        {
            get
            {
                if (_serviceProvider != null) return _serviceProvider;

                //Get the service collection
                _serviceProvider = new ServiceCollection().BuildServiceProvider();

                return _serviceProvider;
            }
        }

        #endregion

        /// <summary>
        /// Get an element from the dependency injection
        /// </summary>
        /// <typeparam name="TElement">Element type</typeparam>
        /// <returns>Element</returns>
        public static TElement GetElementFromDependencyInjection<TElement>()
        {
            return ServiceProvider.GetService<TElement>();
        }
    }

繼承自BaseService的服務示例:

public class DepartmentService : BaseService<Department, IDepartmentRepository>
    {
        #region Fields

        #endregion

        #region Constructor

        #endregion

        #region Methods

        /// <summary>
        /// Get all departments
        /// </summary>
        /// <param name="withAdjacentDepartments">Include adjacent departments</param>
        /// <param name="withRegion">Include region</param>
        /// <returns>Departments</returns>
        public async Task<IEnumerable<DepartmentDTO>> GetAsync(bool withAdjacentDepartments = false,
            bool withRegion = false)
        {
            //Get departments
            var departments = await this.Repository.GetAsync(withAdjacentDepartments, withRegion);

            //Map to the DTO
            return departments.Select(department => this.Mapper.Map<DepartmentDTO>(department)).ToList();
        }

        #endregion
    }

問題是:找不到映射器和存儲庫,因此它們是 null。

我怎么能意識到這一點?

要重現,您可以在此處找到項目,並在此處找到相關工具

關於您在上面顯示的內容,我首先認識到的是您使用的是服務定位器模式而不是依賴注入,並且考慮到您使用的是 ASP NET Core DI 容器(或者在簡短的看看你的代碼庫),它使你的代碼比它需要的復雜得多。

在啟動期間,您正在注冊可能需要在整個代碼中調用的所有服務,但是當您實例化類並嘗試go 追捕它。

您遇到的具體問題是您正在嘗試設置 IServiceProvider 的一些全局 static 實例,但您從未將任何服務放入其中。 由於您沒有設置器,因此當您的定位器第一次嘗試使用 static 助手 class 獲取某些東西時,它會通知一個空集合並返回它,並且該實例與您在啟動期間注冊的實例完全分開。

也就是說,與“修復”全局 static 輔助實例相比,一些重組將是一條更好的前進道路。 考慮以下代碼:

    public class Foo
    {
        public int Bar;
        public int Qux;
    }

    public interface IRepository<T> where T : class, new()
    {
        T GetEntity();
    }

    public class FooRepository : IRepository<Foo>
    {
        public Foo GetEntity()
        {
            return new Foo();
        }
    }

    public abstract class BaseService<TEntity>
         where TEntity : class, new()
    {
         protected readonly IRepository<TEntity> _entityRepository;
         protected readonly IMapper _mapper;

         protected BaseService(IRepository<TEntity> entityRepository, IMapper mapper)
         {
             _entityRepository = entityRepository;
             _mapper = mapper;
         } 
    }

    public interface IFooService
    {
        Foo ServicyStuff();
    }

    public class FooService : BaseService<Foo>, IFooService
    {
        public FooService(IRepository<Foo> entityRepository, IMapper mapper) : base(entityRepository, mapper)
        {
        }

        public Foo ServicyStuff()
        {
            var foo = _entityRepository.GetEntity(); // Our abstract class handled this for us!
            return foo;
        }
    }

以及啟動時的以下服務注冊:

services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddTransient<IRepository<Foo>, FooRepository>();
services.AddTransient<IFooService, FooService>();

我們現在可以將一個 IFooService 實例傳遞給控制器或其他支持 DI 的服務,一切都已連接並准備好 go。 當 IFooService 解析 FooService 時,FooService 解析存儲庫並使用抽象基 class 來確保存儲庫在實例化期間被注入並可供繼承的類使用。 DI 容器負責您嘗試使用服務定位器抽象 class 和擴展解決的所有艱苦工作。

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IFooService _fooService;

    public HomeController(ILogger<HomeController> logger, IFooService fooService)
    {
        _logger = logger;
        _fooService = fooService;
    }

    public IActionResult Index()
    {
        var myFoo = _fooService.ServicyStuff();
        return View();
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM