#xamarin #.net-core #inversion-of-control #mvvmcross
#xamarin #.net-ядро #инверсия управления #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);
}
.. и все необходимые методы, запрошенные интерфейсом.
Затем на стороне, зависящей от платформы, я переопределяю создание 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();
?
Если это необходимо, я использую Xamarin classic, используя платформу Droid. Спасибо
Комментарии:
1. Вопрос в его текущем состоянии является неполным и, следовательно, неясным. Откуда взялся
Host
пример?2. Я думаю, для этого потребуется переписать MvxSetup, чтобы не вызывать
BuildServiceProvider()
для каждого вызова. Добавление поддержки или замена IoC в MvvmCross на Microsoft DI — это то, о чем я думал, просто у меня еще не было времени поиграть.3. @Nkosi
Host
— это статический класс .NET Core. Почему неясно? Вы можете понять почти все из названия, остальное — это то, как я подошел к проблеме. @Cheesebaron Это то, что я могу сделать на стороне клиента, или мне дождаться поддержки Mvx? Кстати, я хотел бы открыть PR в официальном репозитории Mvx, но, к сожалению, я не могу :/
Ответ №1:
Намеренно вдохновленный Unity.Майкрософт.Репозиторий DependencyInjection Я обошел эту проблему, подойдя к проблеме наоборот: вместо замены контейнера IoC по умолчанию я вручную инициализирую IServiceCollection
экземпляр и добавляю его к поставщику IoC Mvx.
Для достижения этой цели я использовал следующий код:
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");
}
}
}
}
Комментарии:
1. Возможно, вы захотите изменить
var instance = serviceDescriptor.ImplementationFactory(serviceProvider); Mvx.IoCProvider.RegisterSingleton(serviceDescriptor.ServiceType, instance);
этоMvvmCross.Mvx.IoCProvider.RegisterSingleton(serviceDescriptor.ServiceType,()=> serviceDescriptor.ImplementationFactory(serviceProvider));
, чтобы избежать быстрой загрузки. Также перед регистрацией в IocProvider вам необходимо проверитьLifeTime
и зарегистрировать соответствующим образом