C# 依赖注入有重复的单例

问题描述

我正在开发 Xamarin.Forms 应用程序,出于某种原因,有多次创建的单例。然而,这并非每次都发生,而且似乎是随机的。我的依赖注入设置发生在 App.xaml.cs

using System;
using Microsoft.AppCenter;
using Microsoft.AppCenter.Analytics;
using Microsoft.AppCenter.Crashes;
using Microsoft.Extensions.DependencyInjection;
using Peripass.Mobile.Framework;
using Peripass.Mobile.Framework.DependencyInterfaces;
using Peripass.YardAssetManagementApp.Data;
using Peripass.YardAssetManagementApp.Data.FileSystem;
using Peripass.YardAssetManagementApp.Data.LocalDataServices;
using Peripass.YardAssetManagementApp.Data.Queues;
using Peripass.YardAssetManagementApp.Data.RemoteDataServices;
using Peripass.YardAssetManagementApp.Data.Syncing;
using Peripass.YardAssetManagementApp.Data.Syncing.QueueItemSyncActions;
using Peripass.YardAssetManagementApp.Device;
using Peripass.YardAssetManagementApp.MVVM;
using Peripass.YardAssetManagementApp.MVVM.Pages;
using Peripass.YardAssetManagementApp.PushNotifications;
using Peripass.YardAssetManagementApp.Services;
using Peripass.YardAssetManagementApp.StepsWizard;
using Peripass.YardAssetManagementApp.UI.Views;
using Peripass.YardAssetManagementApp.UserAuthentication;
using Peripass.YardAssetManagementApp.viewmodels;
using Xamarin.Forms;
using Application = Xamarin.Forms.Application;

namespace Peripass.YardAssetManagementApp {
  public partial class App : Application,IApp {
    private string _startedByAndroidNotificationMessage;
    
    public App() {
      ConfigureServices();
      InitializeComponent();
      AppCenter.Start($"android={Configuration.Configuration.ApplicationInsightsKeyAndroid};",typeof(Analytics),typeof(Crashes));
      MainPage = ServiceProvider.GetrequiredService<MainPage>();
    }

    public static IServiceCollection Services { get; } = new ServiceCollection();
    public IServiceProvider ServiceProvider { get; set; }

    private void ConfigureServices() {
      Services.AddSingleton<ILifecycleHooksService,LifecycleHooksService>();
      Services.AddTransient<InetworkinformationProvider,networkinformationProvider>();

      RegisterLocalDataServices();
      RegisterRemoteDataServices();
      RegisterSyncLogic();
      RegisterServices();

      RegisterViews();
      Services.AddSingleton<IUserManager,UserManager>();
      Services.AddSingleton<HttpClientProvider>();
      Services.AddSingleton<ILogger,Logger>();
      Services.AddSingleton<INavigationService,NavigationService>();
      Services.AddSingleton<StepsWizardManager>();
      Services.AddSingleton<MainPage>();
      Services.AddSingleton(DependencyService.Get<ILocalFileSystem>());
      Services.AddSingleton<IRestServiceHelper,RestServiceHelper>();
      Services.AddSingleton<IPushNotificationsService,PushNotificationsService>();
      ServiceProvider = Services.BuildServiceProvider();
    }

    public void RegisterServices() {
      Services.AddTransient<ITaskService,TaskService>();
      Services.AddTransient<ILocationService,LocationService>();
      Services.AddTransient<ILocalizationService,LocalizationService>();
      Services.AddTransient<IDiagnosticsService,DiagnosticsService>();
    }

    public void RegisterLocalDataServices() {
      Services.AddSingleton<ILocalTaskDataService,LocalTaskDataService>();
      Services.AddSingleton<ILocalLocationDataService,LocalLocationDataService>();
      Services.AddSingleton<ILocalUserDataService,LocalUserDataService>();
      Services.AddSingleton<ILocalPushNotificationDataService,LocalPushNotificationDataService>();
      Services.AddSingleton<ILocalPictureDataService,LocalPictureDataService>();
      Services.AddSingleton<ISafeFileSystem,SafeFileSystem>();
      Services.AddSingleton<ILocalLocalizationDataService,LocalLocalizationDataService>();
    }

    public void RegisterRemoteDataServices() {
      Services.AddSingleton<IRemoteTaskDataService,RemoteTaskDataService>();
      Services.AddSingleton<IRemoteLocationDataService,RemoteLocationDataService>();
      Services.AddSingleton<IRemoteUserDataService,RemoteUserDataService>();
      Services.AddSingleton<IRemoteFileDataService,RemoteFileDataService>();
      Services.AddSingleton<IRemoteLocalizationDataService,RemoteLocalizationDataService>();
    }

    public void RegisterSyncLogic() {
      Services.AddSingleton<IToMobileTasksSyncer,ToMobileTasksSyncer>();

      Services.AddSingleton<IQueue,IncomingHighPriorityQueue>();
      Services.AddSingleton<IQueue,IncomingLowPriorityQueue>();
      Services.AddSingleton<IQueue,OutgoingHighPriorityQueue>();
      Services.AddSingleton<IQueue,OutgoingLowPriorityQueue>();
      Services.AddSingleton<IQueue,PictureSyncLowPriorityQueue>();
      Services.AddSingleton<IQueue,PictureSyncHighPriorityQueue>();

      Services.AddSingleton<IQueueorchestrator,IncomingQueueorchestrator>();
      Services.AddSingleton<IQueueorchestrator,OutgoingQueueorchestrator>();
      Services.AddSingleton<IQueueorchestrator,PictureQueueorchestrator>();

      Services.AddSingleton<IQueueProcessor,IncomingQueueProcessor>();
      Services.AddSingleton<IQueueProcessor,OutgoingQueueProcessor>();
      Services.AddSingleton<IQueueProcessor,PictureQueueProcessor>();

      Services.AddSingleton<IQueueItemSyncAction,FetchTaskDetailSyncAction>();
      Services.AddSingleton<IQueueItemSyncAction,OutgoingStepValueUpdateSyncAction>();
      Services.AddSingleton<IQueueItemSyncAction,OutgoingTaskStatusChangedSyncAction>();
      Services.AddSingleton<IQueueItemSyncAction,SyncPictureAction>();

      Services.AddSingleton<IFileIntegrityHelper,FileIntegrityHelper>();
    }

    public void RegisterViews() {
      Services.AddTransient<LoginViewContent>();
      Services.AddSingleton<Loginviewmodel>();

      Services.AddTransient<UserInfoViewContent>();
      Services.AddSingleton<UserInfoviewmodel>();

      Services.AddTransient<MainTaskListViewContent>();
      Services.AddSingleton<MainTaskListviewmodel>();

      Services.AddTransient<TaskDetailViewContent>();
      Services.AddSingleton<TaskDetailviewmodel>();

      Services.AddTransient<IntegerFieldTaskStepViewContent>();
      Services.AddSingleton<IntegerFieldTaskStepviewmodel>();

      Services.AddTransient<TextAreaTaskStepViewContent>();
      Services.AddSingleton<TextAreaTaskStepviewmodel>();

      Services.AddTransient<DropDownTaskStepViewContent>();
      Services.AddSingleton<DropDownTaskStepviewmodel>();

      Services.AddTransient<MovetoLocationSummaryViewContent>();
      Services.AddSingleton<MovetoLocationSummaryviewmodel>();

      Services.AddTransient<TakePictureStepViewContent>();
      Services.AddSingleton<TakePictureStepviewmodel>();

      Services.AddTransient<MovetoLocationStepViewContent>();
      Services.AddSingleton<MovetoLocationStepviewmodel>();

      Services.AddTransient<TaskCompletedViewContent>();
      Services.AddSingleton<TaskCompletedviewmodel>();

      Services.AddTransient<LoggedOutViewContent>();
      Services.AddSingleton<LoggedOutviewmodel>();

      Services.AddTransient<TextFieldTaskStepViewContent>();
      Services.AddSingleton<TextFieldTaskStepviewmodel>();

      Services.AddTransient<DecimalFieldTaskStepViewContent>();
      Services.AddSingleton<DecimalFieldTaskStepviewmodel>();

      Services.AddTransient<GenericExceptionPageViewContent>();
      Services.AddSingleton<GenericExceptionPageviewmodel>();

      Services.AddTransient<CleanupBeforelogoutPageViewContent>();
      Services.AddSingleton<CleanupBeforelogoutPageviewmodel>();

      Services.AddTransient<SelectLanguageViewContent>();
      Services.AddSingleton<SelectLanguageviewmodel>();
    }

    protected override async void OnStart() {
      await ServiceProvider.GetrequiredService<ILifecycleHooksService>().OnStart();
    }

    protected override void OnSleep() { }

    protected override async void OnResume() {
      await ServiceProvider.GetrequiredService<ILifecycleHooksService>().OnResume();
    }

    public void StartedByTapOnAndroidNotification(string message) {
      _startedByAndroidNotificationMessage = message;
    }
  }
}

多次创建的单例就是这些。可能其他单身人士也被创建了多次,但我敢肯定。

      Services.AddSingleton<IQueueorchestrator,PictureQueueProcessor>();

我发现在解析 ILifecycleHooksService 的依赖项时,有时会多次调用 OnStart 方法,创建这些单例的多个实例。这是 LifeCycleHooksService 中的代码

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Peripass.YardAssetManagementApp.Data;
using Peripass.YardAssetManagementApp.Data.LocalDataServices;
using Peripass.YardAssetManagementApp.Data.Syncing;
using Peripass.YardAssetManagementApp.MVVM;
using Peripass.YardAssetManagementApp.PushNotifications;
using Peripass.YardAssetManagementApp.viewmodels;

namespace Peripass.YardAssetManagementApp {
  public interface ILifecycleHooksService {
    Task OnStart();
    Task OnResume();
  }
  public class LifecycleHooksService : ILifecycleHooksService {
    private readonly INavigationService _navigationService;
    private readonly ILocalUserDataService _localUserDataService;
    private readonly ILocalTaskDataService _localTaskDataService;
    private readonly ILocalLocationDataService _localLocationDataService;
    private readonly ILocalPushNotificationDataService _localPushNotificationDataService;
    private readonly ILocalPictureDataService _localPictureDataService;
    private readonly IToMobileTasksSyncer _toMobileTasksSyncer;
    private readonly IEnumerable<IQueueProcessor> _queueProcessors;
    private readonly IPushNotificationsService _pushNotificationsService;
    private readonly ILocalLocalizationDataService _localLocalizationDataService;

    public LifecycleHooksService(INavigationService navigationService,ILocalUserDataService localUserDataService,IToMobileTasksSyncer toMobileTasksSyncer,IEnumerable<IQueueProcessor> queueProcessors,ILocalTaskDataService localTaskDataService,ILocalLocationDataService localLocationDataService,ILocalPushNotificationDataService localPushNotificationDataService,IPushNotificationsService pushNotificationsService,ILocalPictureDataService localPictureDataService,ILocalLocalizationDataService localLocalizationDataService) {

      _navigationService = navigationService;
      _localUserDataService = localUserDataService;
      _toMobileTasksSyncer = toMobileTasksSyncer;
      _queueProcessors = queueProcessors;
      _localTaskDataService = localTaskDataService;
      _localLocationDataService = localLocationDataService;
      _localPushNotificationDataService = localPushNotificationDataService;
      _pushNotificationsService = pushNotificationsService;
      _localPictureDataService = localPictureDataService;
      _localLocalizationDataService = localLocalizationDataService;
    }
    public async Task OnStart() {
      await ReloadData();
      await CreatedeviceidOnFirstStartAsync();
      var currentUser = _localUserDataService.GetCurrentUser();
      if (currentUser.IsLoggedIn) {
        Configuration.Configuration.SetEnvironment(currentUser.Environment);
        await _navigationService.NavigatetoviewmodelAsync<MainTaskListviewmodel>(true);
        try {
          await _toMobileTasksSyncer.SyncAllMetaData();
        }
        catch {
          // ignored
        }
      }
      else {
        await _navigationService.NavigatetoviewmodelAsync<Loginviewmodel>();
      }
      foreach (var queueProcessor in _queueProcessors) {
        _ = Task.Run(async () => await queueProcessor.StartPeriodicProcessing());
      }
    }

    public async Task OnResume() {
      try {
        await _toMobileTasksSyncer.SyncAllTasks(true);
      }
      catch {
        // ignored
      }
    }

    public async Task CreatedeviceidOnFirstStartAsync() {
      var currentPushNotificationInfo = await _localPushNotificationDataService.GetCurrentPushNotificationInfo();
      if (string.IsNullOrEmpty(currentPushNotificationInfo.deviceidTag)) {
        await _localPushNotificationDataService.Setdeviceid(Guid.NewGuid().ToString());
      }
    }

    private async Task ReloadData() {
      await _localLocalizationDataService.ReloadData();
      await _localUserDataService.ReloadData();
      await _localTaskDataService.ReloadData();
      await _localLocationDataService.ReloadData();
      await _localPictureDataService.ReloadData();
      await _pushNotificationsService.ProcessReceivedMessages();
    }
  }
}

在这个类中,我注入了 IQueueProcessors 的 I Enumerable。这些 queueProcessor 为自己注入了 IQueueorchestrators。如果您需要更多信息,请随时问我。

解决方法

我找到了导致它的原因。原因与 android 相关,并在此堆栈溢出帖子中进行了描述:description of what causes this

对我有用的解决方案来自这篇关于同一主题的帖子:solution for me

基本上对我有用的解决方案是将它添加到 OnCreate 中:

// Possible work around for market launches. See https://issuetracker.google.com/issues/36907463
// for more details. Essentially,the market launches the main activity on top of other activities.
// we never want this to happen. Instead,we check if we are the root and if not,we finish.

if (!isTaskRoot()) {
    final Intent intent = getIntent();
    if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(intent.getAction())) {
        Log.w(LOG_TAG,"Main Activity is not the root.  Finishing Main Activity instead of launching.");
        finish();
        return;       
    }
}