myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Web-Technologien » [gelöst] ASP.NET Core Dependency Injection Singelton in Scoped verwenden?
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

[gelöst] ASP.NET Core Dependency Injection Singelton in Scoped verwenden?

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Olii
myCSharp.de-Mitglied

Dabei seit: 20.09.2017
Beiträge: 76


Olii ist offline

[gelöst] ASP.NET Core Dependency Injection Singelton in Scoped verwenden?

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo, ich probiere mich immer noch an ASP.NET Core mit GraphQL und Dapper.GraphQL aus.

Beim herumspielen ist mir aufgefallen das wenn man Dapper verwenden möchte, ein Nuget existiert, dass Dapper.GraphQL heißt. Soweit so gut. Ich bin dem Beispiel gefolgt und bin dann auf einen Punkt gestoßen der bei mir für Unsicherheit sorgt.

Beim Registrieren der Schema/Types etc. in der Middleware bzw. unter Startup.cs ConfigureServices, müssen für Dapper.GraphQL die entsprechenden Types etc. über services.AddDapperGraphQL registriert werden. Das ganze scheint als Singelton zu erfolgen. Das Schema allerdings habe ich nur über services.AddScoped registriert, da ich z.B. in dem Beispiel von Abt ebenfalls die Registrierung über Scoped gesehen habe.

Scoped wird bei jedem Request erstellt, werden ein Singelton erstellt wird sobald dieser zum ersten mal gebraucht wird, und dieser wird dann die ganze Zeit über erhalten.

Hier einmal ein paar Auszüge:

Startup.cs

C#-Code:
public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<ISchema, MyQuerySchema>();

            services.AddSingleton<IDependencyResolver>(s => new FuncDependencyResolver(s.GetRequiredService));

            services.AddDapperGraphQL(options =>
            {
                // Add GraphQL types
                options.AddType<UserAccountType>();
                options.AddType<MyGraphQuerySchema>();

                // Add query builders for dapper
                options.AddQueryBuilder<UserAccount, UserAccountQueryBuilder>();
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

Controller

C#-Code:
private readonly ISchema _schema;

        public GraphQLController(ISchema schema)
        {
            _schema = schema;
        }

        public async Task<IActionResult> Post([FromBody] GraphQLQuery query)
        {
            var inputs = query.Variables.ToInputs();

            ExecutionResult result = await new DocumentExecuter().ExecuteAsync(_ =>
            {
                _.Schema = _schema;
                _.Query = query.Query;
                _.OperationName = query.OperationName;
                _.Inputs = inputs;
            }).ConfigureAwait(false);

            if(result.Errors?.Count > 0)
            {
                return BadRequest();
            }

            return Ok(result);
        }

MyQuerySchema

C#-Code:
public class MyQuerySchema : Schema
    {
        public MyQuerySchema(IDependencyResolver resolver):base(resolver)
        {
            Query = resolver.Resolve<MyGraphQuerySchema>();
        }
    }

Den Resolver verwende ich hier damit ich später auch mit Mutations arbeiten kann. Das habe ich so in mehreren Beispielen gesehen.

Meine Frage ist nun um es noch einmal zusammen zu fassen: Macht es Sinn in einem Scoped, Singelton zu verwenden? Denn MyQuerySchema ist ja mit einer der wichtigsten Teile über den dann mehr oder weniger die anderen Dinge laufen wie MyGraphQLQuerySchema also wo das Mapping etc. stattfindet. Von Dapper.GraphQL bin ich nägmlich gezwungen einige Teile als Singelton zu registrieren. Oder ergibt es mehr Sinn einfach alles als Singelton fest zu legen?

Beide Fälle funktionieren, dass habe ich getestet, aber es könnte ja später doch vielleicht zu Problemen führen? Ich würde gerne möglichst sauber lernen und nicht so viel fuschen.

Wenn ich etwas unklar definiert habe, bitte bescheid geben damit ich es ändern kann.

Note: Wenn jemand entsprechendes Lesematerial hat, freue ich mich natürlich ebenfalls. Die offizielle MS Doc habe ich natürlich auch schon dazu gelesen. Mich würde nur mal das zusammenspiel in so einem Fall interessieren.

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Olii am 20.06.2019 22:44.

Neuer Beitrag 13.06.2019 13:35 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 13.260
Herkunft: Stuttgart/Stockholm


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von Olii:
Beim herumspielen ist mir aufgefallen das wenn man Dapper verwenden möchte, ein Nuget existiert, dass Dapper.GraphQL heißt. Soweit so gut. Ich bin dem Beispiel gefolgt und bin dann auf einen Punkt gestoßen der bei mir für Unsicherheit sorgt.

Hört sich nach ner ganz schlechten Idee an.
Dapper ist Datenbankschicht - GraphQL ist die Anssichtsschickt.
Allein das Konzept ist eine Verletzung der  [Artikel] Drei-Schichten-Architektur

Auch die Grundidee, dass GraphQL aus mehreren Quellen Daten konsolidiert, um die Anfragemenge zu minimieren, würde DapperGraphQL völlig unterlaufen.

Zitat von Olii:
Macht es Sinn in einem Scoped, Singelton zu verwenden?

Aus einem Scoped darf man einen Singleton verwenden, aber nicht umgekehrt.
Ansonsten wird der Scoped automatisch zu einer Singleton-Referenz (im Singleton selbst).
Das kann zu Race Conditions führen.

Zitat von Olii:
Oder ergibt es mehr Sinn einfach alles als Singelton fest zu legen?

Datenbank(verbindungen) niemals* als Singleton definieren.
Gibt Ausnahmen, die man an einer Hand abzählen kann. Hier sehe ich keine.

Zitat von Olii:
Beide Fälle funktionieren, dass habe ich getestet, aber es könnte ja später doch vielleicht zu Problemen führen?

Das Konzept Datenbank Entitäten in den API Return zu pressen ist ein Fehler, korrekt :)
Neuer Beitrag 13.06.2019 14:05 Beiträge des Benutzers | zu Buddylist hinzufügen
Olii
myCSharp.de-Mitglied

Dabei seit: 20.09.2017
Beiträge: 76

Themenstarter Thema begonnen von Olii

Olii ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von Abt:
Hört sich nach ner ganz schlechten Idee an.
Dapper ist Datenbankschicht - GraphQL ist die Anssichtsschickt.
Allein das Konzept ist eine Verletzung der  [Artikel] Drei-Schichten-Architektur

Aber mit EntityFramework würde es doch auf das selbe hinauslaufen oder? Dapper.GraphQL bringt nur einen SQL Builder und einen Mapper mit, mit dem dann aus der GraphQL Query ein SQL erstellt wird.

Vielleicht verstehe ich dich auch falsch, aber an der Stelle wo Daten nun abgefragt werden, also wie in deinem Beispiel bei MyGraphQLQuerySchema, sah ich Beispiele mit EF bei denen an dieser Stelle nun Daten abgefragt werden, oder man verwendet Repositorys oder wie du ein Mediater. In dem Fall wollte ich einfach anstatt EF, Dapper verwenden. Dazu gibt es dann das Nuget Dapper.GraphQL womit aus der GraphQL Query ein SQL erstellt wird. Und damit kann ich halt meine Daten holen.

Weil man muss ja irgendwie aus der Query ein gültiges SQL erstellen.

Oder meinst du das, dass Abfragen der Daten in dieser Konstellation nicht schön ist? Sonder das man z.B. ein Mediater etc. an dieser Stelle verwenden sollte der einem bei der Datenbeschaffung hilft?

Ich wollte das mit dem Mediater noch ausprobieren aber das ganze erst so simple wie möglich halten damit ich nicht so durcheinander komme :D

Quasi wie in disem "Ofiziellen" Beispiel:

C#-Code:
Field<ListGraphType<PersonType>>(
    "people",
    description: "A list of people.",
    resolve: context =>
    {
        // Create an alias for the 'Person' table.
        var alias = "person";
        // Add the 'Person' table to the FROM clause in SQL
        var query = SqlBuilder.From($"Person {alias}");
        // Build the query, using the GraphQL query and SQL table alias.
        query = personQueryBuilder.Build(query, context.FieldAst, alias);

        // Create a mapper that understands how to map the 'Person' class.
        var personMapper = new PersonEntityMapper();

        // Open a connection to the database
        using (var connection = serviceProvider.GetRequiredService<IDbConnection>())
        {
            // Execute the query with the person mapper
            var results = query.Execute(connection, personMapper, context.FieldAst);

            // `results` contains a list of people.
            return results;
        }
    }
);

Source:  https://github.com/landmarkhw/Dapper.Gra...aster/README.md

Zitat:
Das Konzept Datenbank Entitäten in den API Return zu pressen ist ein Fehler, korrekt :)

Wie meinst du das, ich kann dir da gerade nicht ganz folgen.
Neuer Beitrag 13.06.2019 14:35 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 13.260
Herkunft: Stuttgart/Stockholm


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von Olii:
Aber mit EntityFramework würde es doch auf das selbe hinauslaufen oder?
Dapper.GraphQL bringt nur einen SQL Builder und einen Mapper mit, mit dem dann aus der GraphQL Query ein SQL erstellt wird.

Richtig. Genauso kacke.

Man bindet keine Datenbankschicht - egal über welchen Provider - direkt an die API.
Damit untergräbst Du - egal mit welchem Provider - völlig das Konzept der Schichtentrennung.

Zitat von Olii:
Oder meinst du das, dass Abfragen der Daten in dieser Konstellation nicht schön ist? Sonder das man z.B. ein Mediater etc. an dieser Stelle verwenden sollte der einem bei der Datenbeschaffung hilft?

Der Mediator ist die Schnittstelle der Logik.
Der Handler eines Mediators beinhaltet vollständig die Logik der Anwendung (bzw. die Menge an Handlern).

Zitat:
Quasi wie in disem "Ofiziellen" Beispiel:

C#-Code:
Field<ListGraphType<PersonType>>(
    "people",
    description: "A list of people.",
    resolve: context =>
    {
        // Create an alias for the 'Person' table.
        var alias = "person";
        // Add the 'Person' table to the FROM clause in SQL
        var query = SqlBuilder.From($"Person {alias}");
        // Build the query, using the GraphQL query and SQL table alias.
        query = personQueryBuilder.Build(query, context.FieldAst, alias);

        // Create a mapper that understands how to map the 'Person' class.
        var personMapper = new PersonEntityMapper();

        // Open a connection to the database
        using (var connection = serviceProvider.GetRequiredService<IDbConnection>())
        {
            // Execute the query with the person mapper
            var results = query.Execute(connection, personMapper, context.FieldAst);

            // `results` contains a list of people.
            return results;
        }
    }
);

Source:  https://github.com/landmarkhw/Dapper.Gra...aster/README.md

Und das ist halt genau das was ich meine: Zum Teufel gehört kein SQL Code in das Schema.
Auch sieht man hier Service Locator Anti-Pattern.
Ganz klassischer Fail der  [Artikel] Drei-Schichten-Architektur

Das Schema ist nur der Relay zur Logik.
Neuer Beitrag 13.06.2019 14:50 Beiträge des Benutzers | zu Buddylist hinzufügen
Olii
myCSharp.de-Mitglied

Dabei seit: 20.09.2017
Beiträge: 76

Themenstarter Thema begonnen von Olii

Olii ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Achso okey. wir sind zwar ein wenig vom Thema abgekommen aber ich fasse noch einmal zusammen:

Die Beispiele die unter anderem dargestellt wurde auf Github etc. sind nicht sauber, da in der Präsentationsschicht sofort Logik und Datenbankzugriff mit drin ist.

Besser wäre es mit z.B. einem Mediater zu arbeiten in Verbindung mit vielleicht dem Repository Pattern und mit diesen dann die Logik und den Datenbankzugriff zu steuern.
Somit müsste der SQLBuilder etc. der von Dapper.GraphQL mitgebracht wird, mit in den Mediator rutschen, bzw. halt aus dem Schema fliegen.

Ein Singelten kann in ruhe in einem Scoped verwendet werden.

Setze ich diese Punkte so um, habe ich eine (hoffentlich) präsentable Lösung für mein Problem.
Neuer Beitrag 13.06.2019 15:18 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 13.260
Herkunft: Stuttgart/Stockholm


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Jo, Schema ruft Logik (zB. Mediator) auf und der Handler spricht mit der Datenbank.
Neuer Beitrag 13.06.2019 15:33 Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 6 Monate.
Der letzte Beitrag ist älter als 6 Monate.
Antwort erstellen


© Copyright 2003-2019 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 13.12.2019 22:43