替换 MvvmCross 中的默认 IoC 容器

Replace default IoC container in MvvmCross

由于 MvvmCross v7 坚持自己的 IoC 容器,我想用 .NET Core 替换它,以便在注册第三方库时更轻松,例如 IHttpClientFactoryPollyAutomapper 等,通过已经内置的扩展方法。

为了实现这一点,我已经成功创建了一个 class 实现 MvxSingleton<IMvxIoCProvider> 如下所述:

public class HostingAdapter : MvxSingleton<IMvxIoCProvider>, IMvxIoCProvider
{
    private IServiceProvider ServiceProvider;
    private IServiceCollection ServiceCollection;

    public HostingAdapter()
    {
        var host = Host               
            .ConfigureServices((context, serviceCollection) =>
            {
                // Configure local services
                ConfigureServices(context, serviceCollection);

                ServiceCollection = serviceCollection;
                ServiceProvider = ServiceCollection.BuildServiceProvider();
            })
            .Build();
    }

    public void RegisterType<TFrom, TTo>() where TFrom : class where TTo : class, TFrom
    {
         ServiceCollection.AddTransient<TFrom, TTo>();
         ServiceProvider = ServiceCollection.BuildServiceProvider();
    }

    public T GetSingleton<T>() where T : class
    {
        return ServiceProvider.GetRequiredService<T>();
    }

    public object GetSingleton(Type type)
    {
        return ServiceProvider.GetRequiredService(type);
    }

..以及接口请求的所有必需方法。 然后在平台特定方面,我按如下方式覆盖 IoC 创建:

protected override IMvxIoCProvider CreateIocProvider()
{
    var hostingAdapter = new HostingAdapter();
    return hostingAdapter;
}

该代码似乎有效,但一旦应用程序启动,Mvx 就会注册其自己的“额外”服务,例如 IMvxLoggerProviderIMvxSettings 等。问题来了:

  1. ServiceProvider = ServiceCollection.BuildServiceProvider();Host 初始化期间被调用,但 Mvx 仍然在之后继续注册服务。这意味着 IServiceProvider 不是 'in sync' with IServiceCollection 并且需要一个新的 ServiceCollection.BuildServiceProvider(); 调用。我暂时解决了在每次集合注册时更新提供者的问题(如上面的代码),但我知道这会影响性能。有人知道如何解决这个问题吗?

  2. 有很多Mvx服务没有注册导致应用启动失败。这些是 IMvxLogProviderIMvxAndroidLifetimeMonitorIIMvxSettingsIMvxStart 等。我只是想知道,为什么?如何让 Mvx 处理在我的容器中注册它需要启动的所有内容?我部分解决了其中的一些问题,例如记录器将默认值替换为自定义的问题,但其他回调如 InitializeLifetimeMonitor 被调用为时已晚,无法注册。

  3. 我的 MvxApplication 中是否需要更改任何与最标准实施不同的内容?

  4. 我真的被迫更换标准 IoC 容器吗?我如何处理第 3 方库公开的 IServiceCollection 的扩展方法,如 services.AddHttpClient();

如果需要,我在 Xamarin classic 上使用 Droid 平台。谢谢

故意受到 Unity.Microsoft.DependencyInjection repository 的启发,我已经解决了这个问题:我没有替换默认的 IoC 容器,而是手动初始化一个 IServiceCollection 实例并将其添加到Mvx 的 IoC 提供者。

为此,我使用了以下代码:

public class App : MvxApplication
    {
        public override void Initialize()
        {
            base.Initialize();

            InitializeServiceCollection();

            CreatableTypes()
                .EndingWith("Service")
                .AsInterfaces()
                .RegisterAsLazySingleton();

            RegisterAppStart<HomeViewModel>();
        }

        private static void InitializeServiceCollection()
        {
            IServiceCollection serviceCollection = new ServiceCollection();
            ConfigureServices(serviceCollection);

            IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();

            MapServiceCollectionToMvx(serviceProvider, serviceCollection);
        }

        private static void ConfigureServices(IServiceCollection serviceCollection)
        {
            serviceCollection.AddHttpClient();
        }

        private static void MapServiceCollectionToMvx(IServiceProvider serviceProvider,
            IServiceCollection serviceCollection)
        {
            foreach (var serviceDescriptor in serviceCollection)
            {
                if (serviceDescriptor.ImplementationType != null)
                {
                    Mvx.IoCProvider.RegisterType(serviceDescriptor.ServiceType, serviceDescriptor.ImplementationType);
                }
                else if (serviceDescriptor.ImplementationFactory != null)
                {
                    var instance = serviceDescriptor.ImplementationFactory(serviceProvider);
                    Mvx.IoCProvider.RegisterSingleton(serviceDescriptor.ServiceType, instance);
                }
                else if (serviceDescriptor.ImplementationInstance != null)
                {
                    Mvx.IoCProvider.RegisterSingleton(serviceDescriptor.ServiceType, serviceDescriptor.ImplementationInstance);
                }
                else
                {
                    throw new InvalidOperationException("Unsupported registration type");
                }
            }
        }
    }