xamarin - 替换 MvvmCross 中的默认 IoC 容器

标签 xamarin .net-core inversion-of-control mvvmcross

由于 MvvmCross v7 坚持使用自己的 IoC 容器,我想将其替换为 .NET Core 容器,以便在注册第三方库(例如 IHttpClientFactory)时更轻松。 , Polly , 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);
    }

.. 以及接口(interface)请求的所有必需方法。 然后在平台特定方面,我重写 IoC 创建,如下所示:

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

代码似乎可以工作,但是应用程序启动后,Mvx 就会注册自己的“额外”服务,例如 IMvxLoggerProvider , IMvxSettings等等。问题来了:

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

  2. 有大量 Mvx 服务未注册,因此应用程序无法启动。这些是IMvxLogProvider , IMvxAndroidLifetimeMonitor , IIMvxSettings , IMvxStart等等。我只是想知道,为什么?如何让 Mvx 处理容器中启动所需的所有内容的注册?我部分解决了其中一些问题,例如记录器将默认值替换为自定义值,但其他回调如 InitializeLifetimeMonitor被叫来得太晚,无法注册。

  3. 我需要更改我的 MvxApplication 中的任何内容吗?比最标准的实现?

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

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

最佳答案

刻意受到 Unity.Microsoft.DependencyInjection repository 的启发我已经用另一种方式解决了这个问题:我手动初始化一个 IServiceCollection 实例并将其添加到 Mvx 的 IoC 提供程序中,而不是替换默认的 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");
                }
            }
        }
    }

关于xamarin - 替换 MvvmCross 中的默认 IoC 容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64478974/

相关文章:

c# - 从设置为 ImageView 的相机捕获图像

c# - 如何在Xamarin Forms中查看 'customized'?

c# - 去除边框导航栏按钮 monotuch

.net - 如何在 VSTS 中构建 .net core 和完整的 .net 项目

c# - EF .NET Core2 第一次加载需要更多时间

.NET核心| MVC 将音频文件传递给 html5 播放器。启用搜索

dependency-injection - Ninject 3.0.1.10缺少IKernel.Get

visual-studio - 'XamarinShellPackage' 包没有正确加载

java - Guice:如何根据(动态网络属性)在运行时更改注入(inject)

c# - 使用 Unity 自动注册所有接口(interface)