Casablanca: IOC in MVC-Controller

Hallo allerseits,

macht es überhaupt sinn, Dependency Injection wie unten angezeigt in einem Controller einzusetzen? Es ist mir klar, dass man diese ja überall, wo eine lose Kopplung beabsichtigt ist, einsetzen kann. Folgendes Beispiel:

Ich habe in meinem Controller so etwas wie unten, das via using programmiert ist. Mit using wird das Object "myClient" bekanntlich nach dem verlassen des using{}-Block zerstört.

using (MyClient myClient = new MyClient())
{
   var items = myClient.GetAll();
   return items ;
}

Was passiert aber, wenn man das using durch folgendes ersetzt:

readonly IMyClient _myClient;

public MyController(IMyClient myClient)
{
    _myClient = myClient;
}

var items = _myClient.GetAll();
return items 

Ist das überhaupt OK so? Mach so etwas Sinn? Oder soll man bei using bleiben?

Gruß

  1. Tach!

    macht es überhaupt sinn, Dependency Injection wie unten angezeigt in einem Controller einzusetzen?

    Das hängt davon ab, was man erreichen möchte.

    Ich habe in meinem Controller so etwas wie unten, das via using programmiert ist. Mit using wird das Object "myClient" bekanntlich nach dem verlassen des using{}-Block zerstört.

    Dann hast du einen Fall, bei dem du die Verwendung auf diese eine Stelle begrenzen kannst, und weißt, dass danach aufzuräumen ist.

    using (MyClient myClient = new MyClient())
    {
       var items = myClient.GetAll();
       return items ;
    }
    

    Was passiert aber, wenn man das using durch folgendes ersetzt:

    readonly IMyClient _myClient;
    
    public MyController(IMyClient myClient)
    {
        _myClient = myClient;
    }
    
    var items = _myClient.GetAll();
    return items 
    

    Dann hast du ein Objekt übergeben bekommen, das du mehrfach innerhalb des Controllers verwenden kannst. Soll es am Ende aufgeräumt werden, gibts es Dispose-Mechanismen. Die ASP.NET-MVC-Controller haben einen solchen zum Überschreiben an Bord.

    Ist das überhaupt OK so? Mach so etwas Sinn? Oder soll man bei using bleiben?

    Kann man (ich) nicht pauschal für alle Fälle beantworten.

    dedlfix.

    1. Halo,

      vielen Dank. Ich wurde geradeklar, dass IOC bei WebAPI-Controllern nicht so einfach zu handeln ist, wie bei normalen Controllern. Gibt es da etwas zu beachten. Ich bekomme nämlich direkt beim Eintreten in den Controller Fehlermeldung.

      Gruß

      1. Tach!

        Ich wurde geradeklar, dass IOC bei WebAPI-Controllern nicht so einfach zu handeln ist, wie bei normalen Controllern. Gibt es da etwas zu beachten.

        Das hat nichts mit bestimmten Programmiermustern zu tun. Wenn du ein IOC-Framework hast, kannst du das im Prinzip mit jeder Klasse verwenden. Das Framework muss sich nur in den Initialisierungsmechanismus einklinken, der die Klasse erstellt. Das IOC-Framework wird dazu üblicherweise eine Erweiterung haben, die sich passend in andere Frameworks einklinkt. Das heißt, zu beachten gibts da die Dokumentation des IOC-Frameworks.

        Ich bekomme nämlich direkt beim Eintreten in den Controller Fehlermeldung.

        Auf magische Weise wird da jedenfalls kein Instanz als Constructor-Parameter übergeben.

        dedlfix.

        1. Hi,

          das Problem ist gelöst. Ich habe die falsche Unity-Version installiert. Die korrekte Version ist: Install-Package Unity.WebAPI

          Nun weiß ich nicht, ob die DependencyResolver-Klasse selber die Dispose-Methode implementiert oder muss ich selber darum kümmern. Anhand des Beispiels oben, weiß ich auch leider nicht wie und wo diese Methode hin muss, weil ich mit der Dispose-Methode nicht viel Erfahrung habe.

          Gruß

          1. Tach!

            Nun weiß ich nicht, ob die DependencyResolver-Klasse selber die Dispose-Methode implementiert oder muss ich selber darum kümmern. Anhand des Beispiels oben, weiß ich auch leider nicht wie und wo diese Methode hin muss, weil ich mit der Dispose-Methode nicht viel Erfahrung habe.

            Dispose ist Bestandteil der Controller-Klasse, die du beerbst. Hat nichts mit dem DI zu tun. Inhalt musst du selbst erstellen. Das Gerüst bekommst du mit "override" plus Leerzeichen tippen, da wo du eine neue Methode erstellen wollen würdest und Dispose aussuchen. Disposing ist eine grundlegende .NET-Funktionalität.

            dedlfix.

            1. Ja, OK. Ich deklariere oben ja das Object _myClient in dem Konstruktor und arbeite ich damit weiter unten und hole ich mir meine Informationen und gebe ich die dann weiter (return items):

              readonly IMyClient _myClient;
              
              public MyController(IMyClient myClient)
              {
                  _myClient = myClient;
              }
              
              var items = _myClient.GetAll();
              return items
              

              Wann und wo genau muss ich nun die Dispose-Methode aufrufen?

              Gruß

              1. Tach!

                Wann und wo genau muss ich nun die Dispose-Methode aufrufen?

                Gar nicht. Du musst nur das da reinschreiben, was beim Disposen ablaufen soll. Aufgerufen wird es vom ASP.NET MVC. Genauso wie es für dich den Controller instantiiert hat, kümmert es sich um das Disposen.

                dedlfix.

              2. Ich versteh grad deinen Code nicht. Das ist ein Konstruktor und drumherum stehen doch Dinge - die befinden sich also auf class-Ebene. Eine private Variable für IMyClient. Und dann zwei Zeilen, die eigentlich nur in einer Methode Sinn machen. Muss ich mir da eine Methode drumherum denken?

                Bei Konstrukten wie return dataProvider.GetAll() läuten übrigens sofort alle Alarmglocken. Was ist das, was GetAll() zurückliefert? Vermutlich ein IEnumerable<DataClass>, aber es kann verschiedene Implementierungen geben, die dahinter liegen. Ist es eine statische Collection (z.B. List oder Array), ist das Konstrukt unproblematisch. Ist es aber ein IQueryable (weil der dataProvider z.B. zum EntityFramework gehört), dann ist es gut möglich, dass das Queryable erst dann ausgewertet wird, nachdem der Controller und ggf. das IMyClient-Objekt bereits disposed wurde. Das geht dann schief. In solchen Fällen ist es am einfachsten, das Queryable innerhalb der Zugriffsmethode zu materialisieren, also ein .ToArray() oder .ToList() anzuhängen. Aber: Nicht blindlings anhängen. Nachdenken musst Du schon. Wenn Du das falsche anhängst, oder etwas unnötiges, erzeugst Du überflüssigerweise eine Kopie der items-Collection.

                Rolf