2017-03-11 9 views
1

Ich füge ein Singleton wie folgt hinzu.AddSingleton mit Async Invoke?

In Startup.cs füge ich folgendes:

services.AddSingleton<MySingleton>(); 

Ich möchte meine Singleton so bauen (was natürlich nicht möglich ist):

public class MySingleton 
{ 

    public MySingleton() 
    { 
     await InitAsync(); 
    } 

    private async Task InitAsync() 
    { 
     await Stuff(); 
    } 

} 

Wer weiß, wie kann ich lösen Dieses Problem ohne Deadlocks zu erstellen?

Antwort

1

Soweit ich sagen kann, ist die Konfiguration in ASP.NET Core nicht asynchron, also gibt es keine Möglichkeit, einen Dienst mit asynchronen Factory oder etwas ähnliches hinzuzufügen.

Aus diesem Grund und wenn man bedenkt, dass Blockierung kein großes Problem ist, wenn es nur einmal beim Start der Anwendung durchgeführt wird, sollten Sie beim Erstellen des Dienstes blockieren. Und da ASP.NET Core keinen Synchronisationskontext hat, führt dies auch nicht zu einem Deadlock.

0

Können Sie es normalerweise konstruieren, und verwenden Sie es async und erlauben Sie Ihre asynchrone Initialisierung, um bei Bedarf faul passieren?

public class MySingleton { 
    private bool initialized=false; 
    private SemaphoreSlim mutex = new SemaphoreSlim(1, 1); 
    public async Task DoStuff() { 
     if (!initialized) { 
      await mutex.WaitAsync(); 
      try { 
       if (!initialized) { 
        await InitAsync(); 
        initialized = true; 
       } 
      } finally { 
       mutex.Release(); 
      } 
     } 
     DoTheRealStuff(); 
    } 
    private async Task InitAsync() { 
     await Stuff(); 
    } 
} 
+0

Sie können nicht "erwarten" in einem 'Schloss'. – svick

+0

@svick, du hast völlig Recht, ich habe es vergessen. Ich habe mein Beispiel aktualisiert, um stattdessen einen SemaphoreSlim als Mutex zu verwenden. – Tim

0

Verwenden Sie das Microsoft.VisualStudio.Threading NuGet Paket und dann gestalten Sie Ihre Klasse wie folgt:

public class Singleton { 

    private static readonly AsyncLazy<Singleton> instance = 
     new AsyncLazy<Singleton>(CreateAndDoSomething); 

    private Singleton() { 
    } 

    // This method could also be an async lambda passed to the AsyncLazy constructor. 
    private static async Task<Singleton> CreateAndDoSomething() { 
    var ret = new Singleton(); 
    await ret.InitAsync(); 
    return ret; 
    } 

    private async Task InitAsync() { 
    await Stuff(); 
    } 

    public static AsyncLazy<Singleton> Instance 
    { 
    get { return instance; } 
    } 
} 

Verbrauch:

Singleton singleton = Singleton.Instance; 

Mehr zu Asynchronous Lazy Initialization.

+0

Funktioniert dies mit 'AddSingleton' aus ASP.NET Core Dependency Injection? Denn darum geht es in der Frage. – svick

+0

Außerdem gibt 'Instance'' AsyncLazy 'zurück, nicht' Singleton'. Hast du "erwarten" in deinem Gebrauch vergessen? – svick

0

Das Problem, dem Sie gegenüberstehen, besteht darin, dass Konstruktoren keine Async-Modifizierer haben können. Wenn dies der Fall ist, können Sie Folgendes tun. Wenn nicht, bitte erläutern. Die andere Sache, die Sie erforschen können, ist versuchen, das Double Check Lock Pattern (DCLP) zu verwenden.

public MySingleton() 
    { 
     InitAsync().Wait(); 
    } 

Wenn wie unten sein -

private volatile object _sync = new Object(); 

if (!_init) 
{ 
    lock (_sync) 
    { 
     if (!_init) 
     { 
     } 
    } 
} 

Diese in C# unterstützt wird/Net.. Sie sollten mehr Hinweise dazu auf den Interwebs finden.

+0

Wie hilft DCLP hier? – svick

+0

Honeslty, idk. Aber ich habe es aus folgenden Gründen einfach reingeschmissen. 1. DCLP ist ein übliches Muster zum Initialisieren von Singletons. 2. Es bietet eine größere Flexibilität für die Verwendung des asynchronen Musters. 3. Eine Menge Dinge im Konstruktor zu tun, ist verpönt. d. h. Aufruf von InitAsync(). – seattlesparty