Laden...

Open Generic in .NET Core DI Container registrieren und auflösen

Erstellt von Davaaron vor 4 Jahren Letzter Beitrag vor 4 Jahren 2.018 Views
D
Davaaron Themenstarter:in
106 Beiträge seit 2016
vor 4 Jahren
Open Generic in .NET Core DI Container registrieren und auflösen

Hi,

ich habe einige Klassen und Interfaces (siehe unten), die ich gerne dem DI Container von .NET Core (IServiceCollection) hinzufügen will. Als Erweiterung habe ich Scrutor installiert, damit ich einfacher die benötigten Typen registrieren kann.
Ziel ist es, neben einigen Services auch generische Presenter zur Collection hinzuzufügen, auch welche, die außerhalb der ausführenden Assembly liegen.
Soweit funktioniert auch alles, aber bei einem Konstrukt habe ich das Problem, dass sie anscheinend nicht der Collection hinzugefügt werden. Beim Auflösen bekomme ich eine Fehlermeldung:

"System.ArgumentException: Open generic service type 'Winforms.MVP.UI.IPresenter`2[TView,TModel]' requires registering an open generic implementation type. (Parameter 'descriptors')"

Die Interfaces und Klassen sehen folgendermaßen aus:


public interface IPresenter<TView, TModel> where TView : IView
        where TModel : BaseViewModel
    {
        TView View { get; set; }

        TModel Model { get; set; }

        IDialogService DialogService { get; }

        INavigationService NavigationService { get; }
        IWizardService WizardService { get; }

        IMediator Mediator { get; }


    }



 public abstract class BasePresenter<V, M> : BasePresenter where V : IView
                                    where M : BaseViewModel
    {


        public new V View { get => (V)_view; set => _view = value; }

        public new M Model { get => (M)_model; set => _model = value; }


        public BasePresenter(V view, M model, INavigationService navigationService,
            IDialogService dialogService, IWizardService wizardService, IMediator mediator, IServiceCollection serviceCollection)
            : base(view, model, navigationService, dialogService, wizardService, mediator, serviceCollection)
        {


        }
    }

    public abstract class BasePresenter : IPresenter<IView, BaseViewModel>
    {
        protected IView _view;
        protected BaseViewModel _model;

        public INavigationService NavigationService { get; }
        public IDialogService DialogService { get; }
        public IWizardService WizardService { get; }
        public IMediator Mediator { get; }
        public IServiceCollection ServiceCollection { get; }

        public BasePresenter(IView view, BaseViewModel model, INavigationService navigationService, IDialogService dialogService, 
            IWizardService wizardService, IMediator mediator, IServiceCollection serviceCollection)
        {
            View = view;
            Model = model;
            NavigationService = navigationService;
            DialogService = dialogService;
            WizardService = wizardService;
            Mediator = mediator;
            ServiceCollection = serviceCollection;
        }
}


So registriere ich alle Presenter:


Container.Scan(scan =>
              scan.FromApplicationDependencies()
               .AddClasses(@class => @class.AssignableToAny(Config.PresenterTypes))
               .AsImplementedInterfaces()
               .WithSingletonLifetime());

            //Oder
            Container.AddTransient(typeof(IPresenter<,>), typeof(BasePresenter<,>));


Config.PresenterTypes:


        public List<Type> PresenterTypes { get; } = new List<Type>() { typeof(BasePresenter<IView,BaseViewModel>) };


So versuche ich sie aufzulösen:


  var presenter = container.Get<IPresenter<TestView, TestModel>>();
            var presente2r = container.Get<BasePresenter<TestView, TestModel>>();
            var presente2r3 = container.Get<BasePresenter<IView, BaseViewModel>>();
            var testPresenter = container.Get<TestPresenter>();
            var presenters = container.Get(typeof(IPresenter<,>));
            Assert.IsTrue(presenter != null || testPresenter != null || presenters != null || presente2r != null || presente2r3 != null);



Keine der Auflösungen funktioniert, da, wie ich vermute, kein Presenter gefunden und hinzugefügt wird. Hat jemand einen Typ, wie ich alle Klassen dem Container hinzufügen kann, die entweder von IPresenter oder BasePresenter implementiert bzw. erbt?
Auflösen würde ich dann einen bestimmten Presenter, indem ich den konkreten Implementierungstyp angebe, bspw.

DIContainer.Get<BillpaymentPresenter>();

2.078 Beiträge seit 2012
vor 4 Jahren

Wenn ich dich richtig verstehe, versuchst Du die fertigen nicht generischen Implementierungen mit einem offenen generischen Interface zu registrieren?

Ohne es getestet zu haben fürchte ich, dass das nicht geht.
Wenn Du einen offenen generischen Typ registrierst und eine geschlossene generische Variante davon abfragst, sucht der Contrainer nach einer passenden Klasse, bei der er die generischen Typen setzen kann.
Eine solche Klasse gibt es aber nicht, davon ist ja nichts generisch.

Versuch Mal per Reflection nach allen Implementierungen zu suchen und hole dir dann das konkrete geschlossene Interface (müsste über die InterfaceMap gehen).
Nun hast Du das geschlossen generische Interface und die nicht generische Implementierung und kannst beides simpel registrieren.