替换MvvmCross

问题描述

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

为此,我成功创建了一个实现为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等。问题来了:

    ServiceProvider = ServiceCollection.BuildServiceProvider();初始化期间调用
  1. Host,但是Mvx在此之后仍继续注册服务。这意味着IServiceProvider与IServiceCollection不“同步”,需要新的ServiceCollection.BuildServiceProvider();调用。我临时解决了在每次集合注册时更新提供程序的问题(例如上面的代码),但是我知道这会影响性能。有谁知道如何解决这个问题?

  2. 有许多Mvx服务尚未注册,因此应用程序无法启动。这些是IMvxLogProviderIMvxAndroidLifetimeMonitorIIMvxSettingsIMvxStart等。我只是想知道,为什么?如何让Mvx处理我的容器中所有需要启动的注册?我部分解决了其中的一些问题,例如用自定义记录器替换认记录器的记录器,但其他InitializeLifetimeMonitor之类的回调被称为注册太晚了。

  3. 除了最标准的实现之外,我还需要更改MvxApplication中的任何内容吗?

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

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

解决方法

我受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");
                }
            }
        }
    }