当前位置: 欣欣网 > 码农

如何在 ASP.NET Core 的单一实例服务中使用作用域服务

2024-06-28码农


在 ASP.NET Core 中,有三种类型的依赖注入服务。您可以在此处详细阅读它们。在这篇文章中,我们将重点介绍如何在单例服务中使用作用域内服务。

在单例服务中使用作用域服务的主要目标是访问单例服务中不可用的特定于请求的数据或资源。例如,您可能希望从单一实例服务(如后台服务、缓存服务或通知服务)访问数据库上下文、配置服务或用户服务。

在单例服务中使用作用域服务的主要挑战是手动管理作用域的生存期和处置。由于单一实例服务没有请求作用域,因此需要使用 创建作用域,并在完成作用域服务后释放它。您还需要使用 或 等方法从作用域的服务提供程序解析作用域服务。IServiceScopeFactoryGetRequiredServiceGetService

如果未正确创建和释放作用域,则可能会遇到错误或内存泄漏等错误。您还需要处理在作用域内使用作用域服务时可能发生的任何异常。InvalidOperationException: Cannot resolve scoped service from root provider

可能需要在单一实例服务中使用作用域内服务的一些方案示例包括:

  • 定期运行的 后台服务 ,需要访问数据库上下文才能执行某些操作。数据库上下文是依赖于当前请求的作用域服务,因此需要手动创建作用域并解析作用域内的数据库上下文。

  • public classMyBackgroundService : BackgroundService
    {
    privatereadonlyIServiceScopeFactory _scopeFactory;
    publicMyBackgroundService(IServiceScopeFactory scopeFactory)
    {
    _scopeFactory = scopeFactory;
    }
    protectedoverrideasyncTaskExecuteAsync(CancellationToken stoppingToken)
    {
    // Create a scope using the CreateScope method
    using (var scope = _scopeFactory.CreateScope())
    {
    // Resolve the database context using the GetRequiredService method
    var dbContext = scope.ServiceProvider.GetRequiredService\<MyDbContext>();
    // Do something with the database context
    var users = await dbContext.Users.ToListAsync();
    // ...
    }
    }
    }

  • 一种 缓存服务 ,用于存储分布式缓存中的数据并从中检索数据。缓存服务是由整个应用程序共享的单一实例服务,但它需要访问配置服务才能获取缓存设置。配置服务是依赖于当前请求的作用域服务,因此需要手动创建作用域,并在作用域内解析配置服务。

  • public classMyCacheService
    {
    privatereadonlyIServiceScopeFactory _scopeFactory;
    publicMyCacheService(IServiceScopeFactory scopeFactory)
    {
    _scopeFactory = scopeFactory;
    }
    // Define a method to get data from the cache
    publicasyncTask<T>GetDataAsync<T>(string key)
    {
    // Create a scope using the CreateScope method
    using (var scope = _scopeFactory.CreateScope())
    {
    // Resolve the configuration service using the GetService method
    var configuration = scope.ServiceProvider.GetService<IConfiguration>();
    // Get the cache settings from the configuration
    var cacheSettings = configuration.Getp("CacheSettings").Get<CacheSettings>();
    // Do something with the cache settings
    var cache = newDistributedCache(cacheSettings);
    // Get data from the cache
    var data = await cache.GetAsync<T>(key);
    return data;
    }
    }
    }

  • 通过电子邮件或短信向用户发送通知的 通知服务 。通知服务是由整个应用程序共享的单一实例服务,但它需要访问用户服务才能获取用户的联系信息。用户服务是依赖于当前请求的作用域服务,因此需要手动创建作用域,并在作用域内解析用户服务。

  • public classMyNotificationService
    {
    privatereadonlyIServiceScopeFactory _scopeFactory;
    publicMyNotificationService(IServiceScopeFactory scopeFactory)
    {
    _scopeFactory = scopeFactory;
    }
    // Define a method to send notifications to users
    publicasyncTaskSendNotificationAsync(string message, int userId)
    {
    // Create a scope using the CreateScope method
    using (var scope = _scopeFactory.CreateScope())
    {
    // Resolve the user service using the GetRequiredService method
    var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
    // Get the user's contact information from the user service
    var user = await userService.GetUserByIdAsync(userId);
    var email = user.Email;
    var phone = user.Phone;
    // Do something with the contact information
    var emailService = newEmailService();
    var smsService = newSmsService();
    // Send notifications to the user via email and SMS
    await emailService.SendEmailAsync(email, message);
    await smsService.SendSmsAsync(phone, message);
    }
    }
    }

    在单一实例服务中使用作用域服务的优点和缺点包括:

    优势

  • 您可以避免使用单一实例服务访问特定于请求的数据或资源时可能出现 的并发问题 。例如,如果使用单一实例服务访问数据库上下文,则可能会遇到 或 等错误。通过在单一实例服务中使用作用域内服务,可以确保每个请求都有自己的数据库上下文实例,并避免这些错误。

  • 您可以 确保正确处置 作用域内的服务及其依赖项。例如,如果使用单一实例服务访问数据库上下文,则可能会忘记释放它或过早释放它,这可能会导致内存泄漏或数据损坏。通过在单一实例服务中使用作用域服务,可以确保在请求结束时释放作用域,并随请求释放数据库上下文。

  • 缺点

  • 您可以为代码和性能 增加一些复杂性和开销 。例如,如果在单一实例服务中使用作用域服务,则需要将作用域注入到单一实例服务中,手动创建和释放作用域,然后从作用域的服务提供程序解析作用域服务。这会为单例服务添加一些额外的代码和逻辑,这可能会使其更难读取和维护。它还会增加一些额外的内存和 CPU 使用率,以创建和释放作用域并解析服务,这可能会影响您的性能。

  • 如果你喜欢我的文章,请给我一个赞!谢谢