web-dev-qa-db-fra.com

DbContext pour les tâches d'arrière-plan via l'injection de dépendances

Je ne pense probablement pas dans la bonne direction. Je suis assez nouveau pour Dependency Injection et ASP.Net Core.

J'ai un site Web principal ASP.Net, et l'une des tâches consiste à importer des données d'une feuille Excel vers une base de données qu'un utilisateur téléchargera. Les feuilles Excel peuvent être énormes et les tâches de transformation des données prennent du temps, donc je souhaite les effectuer en arrière-plan. c'est-à-dire que l'utilisateur téléchargera la feuille, la réponse sera envoyée immédiatement et le travail/thread d'arrière-plan importera les données.

J'essaie d'exécuter le travail d'arrière-plan en:

Task.Run(() => ProcessImport(model));

Le problème que je rencontre est que la méthode d'importation de processus appelle les services qui ont des classes de référentiel accédant à AppDbContext via le conteneur d'injection de dépendance ASP.Net qui est ajouté en tant que portée et une fois la réponse renvoyée, le contexte est supprimé. Je reçois une exception d'exécution que vous ne pouvez pas utiliser un contexte après sa suppression.

Ma question est, quelle est la meilleure façon de gérer cette situation? Dois-je faire le singleton AppDbContext? Dois-je créer une nouvelle instance d'AppDbContext dans la méthode ProcessImport et la transmettre? J'ai lu que DbContext n'est pas sûr pour les threads, est-ce donc une bonne approche?

21
Saad Farooq

Vous devez passer IServiceScopeFactory instance (c'est singleton) dans votre tâche.

Dans la tâche interne, lorsque les données arrivent, vous devez créer une nouvelle CreateScope() et demander des services à partir de cette étendue. Une fois le processus de données terminé - supprimez cette étendue (mais conservez la référence à IServiceScopeFactory pour la prochaine exécution).

Voir this par exemple. J'exécute des tâches petites et rapides avec cette bibliothèque.

Pour les tâches lourdes/longues, comme l'a écrit Gert, ne comptez pas sur le fait que votre tâche sera toujours exécutée. Soyez prêt pour le redémarrage, soyez prêt pour le retraitement des mêmes données.

25
Dmitry

Pour décomposer vos questions:

  1. quelle est la meilleure façon de gérer cette situation?

    Il n'est pas idéal pour l'API de gérer les tâches de longue durée. Vous pouvez déléguer le processus à une application en arrière-plan

  2. Dois-je faire le singleton AppDbContext?

    Le dbContext ne doit pas être singleton dans un scénario d'application Web car il peut poser des problèmes comme la gestion des transactions.

  3. quelle est la meilleure façon de gérer cette situation?

    décomposer les différents services/processus:

    • L'API qui prendra un fichier. Idéalement, l'API devrait simplement prendre le fichier en entrée et le conserver sur le disque ou dans la base de données.
    • Un service qui traitera le fichier. Créez ce composant/service en tant que bibliothèque distincte. Consommez ensuite cette bibliothèque à partir d'une application console. De cette façon, vous pouvez profiler les performances. Faites-la tirer et oubliez la méthode en la faisant async. De cette façon, vous avez la possibilité de réutiliser votre code.
    • Si vous ne vous attendez pas à beaucoup de téléchargements de fichiers, vous pouvez réutiliser la bibliothèque sur votre contrôleur API et exécuter la méthode à l'aide de QueueBackgroundWorkItem. Voir ici pour référence: http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
  4. Dois-je créer une nouvelle instance d'AppDbContext dans la méthode ProcessImport et la transmettre?

    Comme il n'est pas adapté aux threads, créez et utilisez une instance distincte de votre classe dbContext dans chaque thread.

  5. J'ai lu que DbContext n'est pas sûr pour les threads, est-ce donc une bonne approche?

    Pour un guide détaillé de l'utilisation d'EF dbContext, consultez ce blog: http://mehdi.me/ambient-dbcontext-in-ef6/

4
alltej