Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Dans .NET 11, le conteneur d'injection de dépendances intégré tente de supprimer tous les services supprimables capturés, même si un service lève une exception. Ce comportement s'applique à la suppression synchrone et asynchrone des portées et des fournisseurs de services racine. Plusieurs échecs de suppression produisent une AggregateException.
Version introduite
.NET 11 Preview 2
Comportement antérieur
Auparavant, la suppression des portées et des fournisseurs racine traitait les services supprimables capturés dans l'ordre inverse de leur capture, mais s'arrêtait à la première exception. Cette exception s’est propagée inchangée et les services restants n’ont pas été libérés.
Par exemple, supposons que vous avez résolu FirstDisposable, puis SecondDisposable, et que les deux services ont levé une exception pendant la libération. Le conteneur supprimait d'abord SecondDisposable. Son exception empêchait la suppression de FirstDisposable.
Nouveau comportement
À partir de .NET 11, la suppression synchrone et asynchrone des portées intégrées et des fournisseurs de services racine tente de supprimer tous les services supprimables capturés dans l'ordre inverse de leur capture, même après un échec.
Une fois toutes les tentatives de suppression terminées, une exception unique est relancée sans modification. Si plusieurs opérations de suppression échouent, la suppression lève une AggregateException qui contient toutes les exceptions.
Dans l'exemple précédent, le conteneur tente de supprimer SecondDisposable, puis FirstDisposable. Étant donné que les deux lèvent une exception, la libération lève une exception AggregateException qui contient les deux exceptions.
Type de changement avec rupture de compatibilité
Ce changement est un changement de comportement.
Raison du changement
Pour donner à chaque service capturé la possibilité de libérer des ressources telles que des minuteurs, des gestionnaires d'événements et des handles non managés, le conteneur poursuit la suppression après les exceptions. Auparavant, l’échec d’un service empêchait d’autres services de libérer leurs ressources.
Pour plus d’informations, consultez dotnet/runtime PR #123342.
Action recommandée
Aucune action n’est requise si vos implémentations de libération ne lèvent pas d’exception et que votre code ne s’appuie pas sur la libération pour s’arrêter après le premier échec.
Pour éviter les échecs de nettoyage, préférez les implémentations Dispose() et DisposeAsync() qui ne lèvent pas d’exception. Si votre code gère les échecs de suppression, prenez en charge à la fois l'exception d'origine en cas d'échec unique et AggregateException en cas d'échecs multiples. Interceptez AggregateException avant un gestionnaire d’exceptions général et inspectez InnerExceptions pour gérer chaque défaillance.
Ne comptez pas sur une exception de suppression pour empêcher la suppression des autres services. Aucun commutateur de compatibilité ne restaure le comportement précédent.
API affectées
- Microsoft.Extensions.DependencyInjection.ServiceProvider.Dispose()
- Microsoft.Extensions.DependencyInjection.ServiceProvider.DisposeAsync()
- Microsoft.Extensions.DependencyInjection.AsyncServiceScope.Dispose()
- Microsoft.Extensions.DependencyInjection.AsyncServiceScope.DisposeAsync()
- System.IDisposable.Dispose() sur Microsoft.Extensions.DependencyInjection.IServiceScope instances créées par le conteneur intégré.