由于 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
等等。问题来了:
ServiceProvider = ServiceCollection.BuildServiceProvider();
在Host
期间被调用初始化但之后 Mvx 仍然继续注册服务。这意味着 IServiceProvider 与 IServiceCollection 和新的ServiceCollection.BuildServiceProvider();
不“同步”。需要打电话。我暂时解决了在每次集合注册时更新提供程序的问题(如上面的代码),但我知道这会影响性能。有人知道如何解决这个问题吗?有大量 Mvx 服务未注册,因此应用程序无法启动。这些是
IMvxLogProvider
,IMvxAndroidLifetimeMonitor
,IIMvxSettings
,IMvxStart
等等。我只是想知道,为什么?如何让 Mvx 处理容器中启动所需的所有内容的注册?我部分解决了其中一些问题,例如记录器将默认值替换为自定义值,但其他回调如InitializeLifetimeMonitor
被叫来得太晚,无法注册。我需要更改我的
MvxApplication
中的任何内容吗?比最标准的实现?我真的被迫更换标准 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/