Problem mit DI in Blazor Service Side + EF Core

  • C# (ASP)
  • (Core) Blazor Server

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von KingLM97.

    Problem mit DI in Blazor Service Side + EF Core

    Hallo zusammen,

    ich bastel mir gerade eine Anwendung mit Blazor Server Side + EF Core zusammen.
    Für den Datenzugriff habe ich mir eine Art RepositoryWrapper geschrieben, welcher per DI (Transient) in meine ViewModels injected wird.
    Das Problem ist nun, dass ich Seiten, wo der RepositoryWrapper verwendet wird, nur einmal aufrufen kann, beim zweiten aufrufen stürzt es mit der Meldung "A second operation started on this context before a previous operation completed." ab.
    In der Funktion AddDbContext habe ich bereits ServiceLifetime.Scoped angegeben, wie es auch in der Dokumentation von Microsoft beschrieben steht. Mein RepositoryWrapper selbst ist ebenfalls als Transient deklariert.

    Ich bin auf dem Gebiet auch noch relativ neu.

    Es gibt wohl noch die Möglichkeit OwningComponentBase zu verwenden, aber das entfällt vermutlich bei mir, da meine ViewModels eben keine Components sind, sondern das ViewModel in die Components injected wird.

    So sieht mein RepositoryWrapper aus:
    Spoiler anzeigen

    C#-Quellcode

    1. public class RepositoryWrapper
    2. {
    3. public IMitarbeiterRepository Mitarbeiter { get; private set; }
    4. public IGruppeRepository Gruppe { get; private set; }
    5. public IStempelstatusRepository Stempelstatus { get; private set; }
    6. public IZeitprofilRepository Zeitprofil { get; private set; }
    7. public IRolleRepository Rolle { get; private set; }
    8. public IRechteRepository Recht { get; private set; }
    9. public IStempelRepository Stempel { get; private set; }
    10. readonly ApplicationDbContext context;
    11. public RepositoryWrapper(ApplicationDbContext context)
    12. {
    13. this.context = context;
    14. Mitarbeiter = new MitarbeiterRepository(context);
    15. Gruppe = new GruppeRepository(context);
    16. Stempelstatus = new StempelstatusRepository(context);
    17. Zeitprofil = new ZeitprofilRepository(context);
    18. Rolle = new RolleRepository(context);
    19. Recht = new RechtRepository(context);
    20. Stempel = new StempelRepository(context);
    21. }
    22. public async Task SaveAsync()
    23. {
    24. await context.SaveChangesAsync();
    25. }
    26. }


    Und so mein AddDbContext sowie die DI für den RepositoryWrapper:
    Spoiler anzeigen

    C#-Quellcode

    1. services.AddDbContext<ApplicationDbContext>(options =>
    2. {
    3. bool lokal = false;
    4. var connectionString = lokal
    5. ? Configuration.GetConnectionString("lokaleDb")
    6. : Configuration.GetConnectionString("remoteDb");
    7. options.UseSqlServer(connectionString);
    8. ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
    9. {
    10. builder
    11. .AddFilter((cat, level) => cat == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information)
    12. .AddConsole();
    13. });
    14. options.UseLoggerFactory(loggerFactory);
    15. }, ServiceLifetime.Transient);
    16. services.AddTransient<RepositoryWrapper>();


    Ich bin über jeden Rat dankbar :)
    Ich verwende überall await, sonst würde VS ja entsprechend meckern.
    Ich habe das Problem aber ein wenig eindämmen können:
    Es hängt wohl an einer etwas größeren Abfrage, mit where und OrderBy. Bei allen anderen Abfragen ohne where etc. funktioniert alles einwandfrei.
    Aber selbst wenn ich Durchdebugge, die größere Abfrage binnen kürzester Zeit durchgelaufen. Komisch...
    Naja deine SubRepositories verwenden alle dieselbe Instanz vom Context. Wenn diese im ViewModel gebunden werden könnte es ggf. zu Problemen kommen.
    Es wäre besser wenn diese alle einfach einen Context injected bekommen statt so das transient aufzuheben.
    Das ist meine Signatur und sie wird wunderbar sein!
    Und wenn ich mir ein internes Feld anlege, welches mir sagt ob gerade eine Abfrage läuft und ich solange in einer Schleife darauf warte bis es fertig ist?
    Sollte doch funktionieren, das probiere ich mal aus ^^
    Das würde ich dir nicht empfehlen. Registriere doch einfach die Repositories. Und dann injecte sie von mir aus in den Wrapper wenn du sie alle zusammen haben willst
    Das ist meine Signatur und sie wird wunderbar sein!

    KingLM97 schrieb:

    Es hängt wohl an einer etwas größeren Abfrage, mit where und OrderBy. Bei allen anderen Abfragen ohne where etc. funktioniert alles einwandfrei

    Kannst du die Abfrage mal zeigen?

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Nofear23m schrieb:

    Kannst du die Abfrage mal zeigen?

    Tatsächlich hängt es bei dieser Zeile, den vermutlichen Fehler habe ich aber bereits gefunden! :)

    C#-Quellcode

    1. await repository.Rolle.GetAllAsync(filter: r => r.Aktiv)


    Das Problem/der Fehler:
    Ich benutze zur Anzeige der Daten von DevExpress das DataGrid und dort habe ich zwei Comboboxen, mit denen ich meine Daten filtern kann. Jede Combobox hat eine eigene Funktion zum laden der Daten. Normalerweise werden die Daten erst geladen, wenn ich die Combobox öffne. Jedenfalls beim ersten Seitenaufruf. Beim zweiten, warum auch immer, werden beide Methoden gleichzeitig aufgerufen und dann stürzt es ab. ?(

    Meine Lösung:
    Beim Initialisieren meines Viewmodels lade ich die Daten für die Comboboxen und speichere sie mir in zwei Feldern ab und beim öffnen der Combobox gebe ich einfach die entsprechenden Daten zurück. Funktioniert bisher ^^

    KingLM97 schrieb:

    Beim Initialisieren meines Viewmodels lade ich die Daten für die Comboboxen und speichere sie mir in zwei Feldern ab

    Sollte übrigens stets so gemacht werden. Dafür hat man ja ein ViewModel. ;)

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##