2017-05-04 2 views
1

In einem meiner Controller, ich habe ein Asynchron-Methode, die ein paar db Anrufe gleichzeitig zu machen hat, so dass ich es wie folgt auf:EF Core DBContext im Controller für Multithreading erstellen?

public xxxController(IConfiguration configuration, xxxContext xxxContext, xxx2Context xxx2Context) 
    : base(xxxContext) 

Ich speichere die Kontexte, die injiziert werden. In dem besonderen Verfahren:

var v = await Task.WhenAll(...) 

Innerhalb des WhenAll, muß ich die xxxContext für jedes Element verwenden, so dass ich das nicht-Thread-sicher Ausnahme.

Was ist der richtige Weg, um einen neuen DbContext zu erstellen? Im Moment ist ich tun:

var v = new DbContextOptionsBuilder<xxxContext>(); 
v.UseSqlServer(_xxxContext.Database.GetDbConnection().ConnectionString);  
xxContext e = new xxContext(v.Options); 

So bin ich die Verbindungszeichenfolge aus dem bestehenden Kontext erhalten, die injiziert wurde, und verwendet, um einen neuen zu erstellen.

Die Verbindungszeichenfolgen werden in appSettings.json gespeichert. Im Abschnitt "ConnectionStrings".

Gibt es eine sauberere Möglichkeit, die Kontexte für Multithreading zu erstellen?

Antwort

0

Für diesen Zweck habe ich etwas wie Fabrikklasse erstellt, die Kontext pro Aufruf bieten kann. Für Ihren Fall kann es

public class AppDependencyResolver 
{ 
    private static AppDependencyResolver _resolver; 

    public static AppDependencyResolver Current 
    { 
     get 
     { 
      if (_resolver == null) 
       throw new Exception("AppDependencyResolver not initialized. You should initialize it in Startup class"); 
      return _resolver; 
     } 
    } 

    public static void Init(IServiceProvider services) 
    { 
     _resolver = new AppDependencyResolver(services); 
    } 

    private readonly IServiceProvider _serviceProvider; 

    private AppDependencyResolver(IServiceProvider serviceProvider) 
    { 
     _serviceProvider = serviceProvider; 
    } 

    public xxxContext CreatexxxContextinCurrentThread() 
    { 
     var scopeResolver = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope(); 
     return scopeResolver.ServiceProvider.GetRequiredService<xxxContext>(); 
    } 
} 

als Sie Init Methode in Startup

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
{ 
    AppDependencyResolver.Init(app.ApplicationServices); 
    //other configure code 
} 

Sie können für dieses mein Ansatz aussehen auf github

0

nennen sollte ich Angst, dass Sie Ihre asynchronen Methoden in dieser Ausführung Weg

var task = Task.Run(() => MyAsynchronosMethod()); 

DbContext Operationen sind Eingabe-Ausgabe-Operationen, die Sie nicht auf verschiedenen Threads ausführen müssen, um "gleichzeitig" zu arbeiten. Sie können es ohne neue Threads arbeiten.

public MyController(IConfiguration configuration, AContext aContext, BContext bContext) 
    : base(aContext) 
{ 
    _aContext = aContext; 
    _bContext = bContext; 
} 

public Task<IActionResult> GetSomething(int id) 
{ 
    var customerTask = aContext.Customers 
            .FirstOrDefaultAsync(customer => customer.Id == id); 
    var sellerTask = aContext.Sellers 
            .FirstOrDefaultAsync(seller => seller.CustomerId == id); 
    var ordersTask = bContext.Orders 
            .Where(order => order.CustomerId == id) 
            .ToListAsync(); 
    var invoicesTask = bContext.Invoices 
            .Where(invoice => invoice.CustomerId == id) 
            .ToListAsync(); 
    var allTasks = new[] { customerTask, sellerTask, ordersTask, invoicesTask}; 
    await Task.WhenAll(allTasks); 

    // Do stuff with result of completed tasks 

    Return OK(calculatedResult); 
} 

In Methode oben werden Sie alle Abfragen fast gleichzeitig senden, ohne auf eine Antwort zu warten. Sie beginnen erst nach dem Senden aller Abfragen auf Antworten zu warten.
Nachdem alle Abfrageergebnisse angekommen sind, können Sie Daten verarbeiten - alle Operationen werden auf einem Thread ausgeführt.

Verwandte Themen