替换 MvvmCross 中的默认 IoC 容器
Replace default IoC container in MvvmCross
由于 MvvmCross v7 坚持自己的 IoC 容器,我想用 .NET Core 替换它,以便在注册第三方库时更轻松,例如 IHttpClientFactory
、Polly
、Automapper
等,通过已经内置的扩展方法。
为了实现这一点,我已经成功创建了一个 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 就会注册其自己的“额外”服务,例如 IMvxLoggerProvider
、IMvxSettings
等。问题来了:
ServiceProvider = ServiceCollection.BuildServiceProvider();
在 Host
初始化期间被调用,但 Mvx 仍然在之后继续注册服务。这意味着 IServiceProvider 不是 'in sync' with IServiceCollection 并且需要一个新的 ServiceCollection.BuildServiceProvider();
调用。我暂时解决了在每次集合注册时更新提供者的问题(如上面的代码),但我知道这会影响性能。有人知道如何解决这个问题吗?
有很多Mvx服务没有注册导致应用启动失败。这些是 IMvxLogProvider
、IMvxAndroidLifetimeMonitor
、IIMvxSettings
、IMvxStart
等。我只是想知道,为什么?如何让 Mvx 处理在我的容器中注册它需要启动的所有内容?我部分解决了其中的一些问题,例如记录器将默认值替换为自定义的问题,但其他回调如 InitializeLifetimeMonitor
被调用为时已晚,无法注册。
我的 MvxApplication
中是否需要更改任何与最标准实施不同的内容?
我真的被迫更换标准 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");
}
}
}
}
由于 MvvmCross v7 坚持自己的 IoC 容器,我想用 .NET Core 替换它,以便在注册第三方库时更轻松,例如 IHttpClientFactory
、Polly
、Automapper
等,通过已经内置的扩展方法。
为了实现这一点,我已经成功创建了一个 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 就会注册其自己的“额外”服务,例如 IMvxLoggerProvider
、IMvxSettings
等。问题来了:
ServiceProvider = ServiceCollection.BuildServiceProvider();
在Host
初始化期间被调用,但 Mvx 仍然在之后继续注册服务。这意味着 IServiceProvider 不是 'in sync' with IServiceCollection 并且需要一个新的ServiceCollection.BuildServiceProvider();
调用。我暂时解决了在每次集合注册时更新提供者的问题(如上面的代码),但我知道这会影响性能。有人知道如何解决这个问题吗?有很多Mvx服务没有注册导致应用启动失败。这些是
IMvxLogProvider
、IMvxAndroidLifetimeMonitor
、IIMvxSettings
、IMvxStart
等。我只是想知道,为什么?如何让 Mvx 处理在我的容器中注册它需要启动的所有内容?我部分解决了其中的一些问题,例如记录器将默认值替换为自定义的问题,但其他回调如InitializeLifetimeMonitor
被调用为时已晚,无法注册。我的
MvxApplication
中是否需要更改任何与最标准实施不同的内容?我真的被迫更换标准 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");
}
}
}
}