5

Ich habe ein generisches Repository, das ich für DI registrieren möchte, es implementiert ein Interface IRepository..net-core Dependency Injection

Normalerweise würde ich eine Instanz davon wie folgt erstellen:

IRepository repo = new Repository<Order>(); 

aber ich Geschwindigkeit aufstehen versuchen in .net 5 vor Release und will diesen mit DI arbeiten zu bekommen, habe ich Zuflucht auf die folgenden:

services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>(); 

Aber das fühlt sich falsch, ich will nicht über 50 Linien in es eine für jede der Klassen in meinem Modell ...

ich nicht alles online über t finden Ich weiß, dass es mit anderen IOC-Containern möglich ist. Aber da es sich um ein Lernprojekt handelt, möchte ich keinen anderen Container verwenden, sondern alles mit .net5s nativen Containern.

Antwort

4

Nach einigem Hin und her die Kommentare zu anderen Antworten Ich habe eine funktionierende Lösung, es ist vielleicht nicht der beste Weg, aber es funktioniert. Ich werde das Update erneut durchführen, wenn ich eine bessere Möglichkeit finde, dies zu implementieren.

Die beiden Fragen, die ich hatte waren: Wir brauchten eine generische Schnittstelle zu registrieren, das Problem hier war eine Unaufmerksamkeit von mir .. ich falsch die Syntax hatte eine generische Art für die Registrierung, die natürlich ist:

services.AddTransient(typeof(IRepository<>), typeof(Repository<>)); 

Das zweite Problem war, dass ich eine Assembly habe, die 50+ verschiedene Modelle enthält, die ich registriert haben wollte. Die Art, wie ich dies ansprach, war eine Methode zu schreiben, die ich zusammen mit dem Namespace eine Liste von Assemblies übergeben kann zu registrieren und es iteriert über alle Typen, die den Kriterien entsprechen, und registriert sie im DI-Container.

public void RegisterModels(IServiceCollection services, string[] Assemblies, string @NameSpace) 
    { 
     foreach (var a in Assemblies) 
     { 
      Assembly loadedAss = Assembly.Load(a); 

      var q = from t in loadedAss.GetTypes() 
        where t.IsClass && !t.Name.Contains("<") && t.Namespace.EndsWith(@NameSpace) 
        select t; 

      foreach (var t in q.ToList()) 
      { 
       Type.GetType(t.Name); 
       services.AddTransient(Type.GetType(t.FullName), Type.GetType(t.FullName)); 
      } 
     } 
    } 

Dies ist dann von der startup.cs Methode ConfigureServices aufgerufen:

public void ConfigureServices(IServiceCollection services) 
    { 
     // Add framework services. 
     services.AddEntityFramework() 
      .AddSqlServer() 
      .AddDbContext<TestContext>(options => 
       options.UseSqlServer(@"Server=LOCALHOST\SQLEXPRESS;Database=Test;Trusted_Connection=True;")); 

     services.AddMvc(); 

     RegisterModels(services, new string[] { "UI" }, "UI.Models"); 

     services.AddTransient(typeof(IRepository<>), typeof(Repository<>)); 
    } 

Es gibt einen besseren Weg, dies zu tun sein mag, es ist auf jeden Fall anders DI-Container verwenden, wenn jemand Verbesserungen zu bieten hat lass es mich wissen, bitte.

+0

Es sei denn, ich vermisse etwas. Warum müssen Sie Ihre Viewmodels mit DI registrieren? – testydonkey

+0

Sie haben recht, das ursprüngliche Problem war, dass ich das generische Repository nicht registrieren konnte, ohne einen Typ anzugeben, der mich zu einem Pfad führte, wo es vorgeschlagen wurde, dass dies in der .net 5 DI nicht möglich ist Container - also habe ich angefangen, Wege zu finden, um die Arbeit zu minimieren, um alle verschiedenen Arten von generischen Repo zu registrieren, die ich benötigen würde ... Wie auch immer Sie sind, die RegisterModels Methode wird nicht benötigt - Ive es gelassen, wie es nützlich sein kann für andere, die eine Anzahl von Klassen innerhalb eines Namensraums registrieren wollen, wird Ill bearbeitet, um das klarer zu machen. – D3vy

+0

plus 1 für 'loadedAss' –

0

Sie können eine Erweiterungsmethode erstellen, um alle einzelnen Elemente einzukapseln, die registriert werden müssen.

, dass die gleiche Technik Microsoft ist, unter Verwendung, zum Beispiel Sie dies nur in Start setzen:

services.AddMvc(); 

aber das ist eine Erweiterung Methode und hinter den Kulissen können Sie darauf wetten, es wird ein paar Sachen Registrierung es braucht.

so können Sie Ihre eigene Erweiterungsmethode wie folgt erstellen:

using Microsoft.Extensions.DependencyInjection; 
public static IServiceCollection AddMyFoo(this IServiceCollection services) 
{ 
    services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>(); 
    //.... 

    return services; 
} 

und indem die Methode die IServiceCollection zurückkehren Sie machen es fließend, so dass Sie Kommentar Aktualisiert tun können

services.AddMyFoo().AddSomeOtherFoo(); 

basierend auf

Die andere Technik zur Reduzierung von Registrierungen ist, wenn Ihre Abhängigkeit selbst keine Abhängigkeiten hat, können Sie den Konstruktor dazu bringen, einen Standardwert von null zu haben Sie haben immer noch eine Entkopplung und könnten später eine andere übergeben, aber die DI wird keinen Fehler auslösen und Sie können nur instanziieren, was Sie brauchen, wenn sie nicht übergeben wird.

public class MyFoo(IFooItemDependency myItem = null) 
{ 
    private IFooItemDependency internalItem; 

    public MyFoo(IFooItemDependency myItem = null) 
    { 
     internalItem = myItem ?? new FooItemItem(); 
    } 
} 
+0

Das hat mich noch 50+ Repositories registrieren erfordert, es ist einfach, den Code zu bewegen, so woanders zu tun ... Wenn ich das mache, dann könnte ich auch das generische Repository loswerden. Zur Klärung möchte ich (wenn möglich) eine Zeile haben, um den Repo zu registrieren, egal welcher Art seine konkrete Implementierung sein wird. – D3vy

+0

nur meine Antwort mit etwas aktualisiert, das helfen kann, aber letztlich kann nichts weitergegeben werden, es sei denn, es ist irgendwo registriert, gibt es keine automatische Erkennung durch Reflexion. Beachten Sie, dass Sie nicht die eingebaute DI verwenden müssen, wenn ein anderes kompatibles DI die automatische Registrierung unterstützt, könnten Sie es verwenden, aber das ist keine Funktion des integrierten DI –

+0

Das habe ich mir gedacht. Danke für die Bestätigung. So sehr ich auch nichts anderes verwenden wollte, werde ich einen anderen IOC-Container verwenden. – D3vy

0

Ich bin nicht 100% sicher, was Ihre Frage ist, ich nehme an, Sie nicht

services.AddTransient<DAL.IRepository<Models.Order>, DAL.Repository<Models.Order>>(); 
services.AddTransient<DAL.IRepository<Models.Person>, DAL.Repository<Models.Person>>(); 
services.AddTransient<DAL.IRepository<Models.Invoice>, DAL.Repository<Models.Invoice>>(); 

etc

Ich habe dies getan, vor (mit ninject) haben wollen

Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope(); 

ich für die Einheit vorstellen, dass Sie etwas ähnliches wie

tun können
services.AddTransient<DAL.IRepository<>, typeof(Repository<>)(); 

und dann in einem

Service zu nutzen
public OrderService(IRepository<Models.Order> orderRepository) 
{ 
    this.orderRepository = orderRepository; 
} 

EDIT

Wie OP ist die korrekte Syntax darauf hingewiesen:

services.AddTransient(typeof(IRepository<>), typeof(Repository<>)); 
+0

leider 'services.AddTransient , typeof (Repository <>)();' ist kein gültiger Code und die Frage bezieht sich nicht auf Unity. – qujck

+0

Meine schlechte Meinung über Unity, aber es ist sowieso kein Einheitscode. Gibt es irgendwelche Fehler? Laufzeit? Bauzeit? – testydonkey

+0

Ich habe es nicht in VS eingegeben, aber kann 3 Probleme von hier sehen, die alle nicht kompilieren werden: 1. Es gibt mehr '<''s than '>' s. 2. Sie können 'typeof (Repository <>)' nicht zwischen '<' and '>' und 3. Sie können keinen offenen generischen Typ wie 'DAL.IRepository <>' zwischen '<' and '>' setzen (Sie benötigen etwas wie ' AddTransient (typeof (DAL.IRepository <>), typeof (Repository <>) ') – qujck

10

sollten Sie in der Lage sein, die offen generic registrieren

services.AddTransient(typeof(IRepository<>), typeof(Repository<>)); 
1

Sie eine Konvention basierte Registrierung Bibliothek wie Scrutor nutzen könnten.

Scrutor ist eine kleine Open-Source-Bibliothek, die eine fließende API zur Registrierung von Diensten in Ihrem Microsoft.Extensions.DependencyInjection-Container basierend auf Konventionen bietet (ähnlich der AutoFac-Methode RegisterAssemblyTypes, StructureMaps Scan-Methode und Ninjects Conventions).

Dies ermöglicht es Ihnen, so etwas zu tun:

services.Scan(scan => scan 
      .FromAssemblies(<<TYPE>>.GetTypeInfo().Assembly) 
       .AddClasses(classes => classes.Where(x => { 
        var allInterfaces = x.GetInterfaces(); 
        return 
         allInterfaces.Any(y => y.GetTypeInfo().IsGenericType && y.GetTypeInfo().GetGenericTypeDefinition() == typeof(IRepository<>))); 
       })) 
       .AsSelf() 
       .WithTransientLifetime() 
     );