The big picture, I am trying to inject a SQL Lite repository into my viewmodels thats why I installed the Dependecy Injection packages and tried to set it up, but I get the following error when trying to load the Login page:
System.InvalidOperationException: 'Unable to resolve service for type
'Xamarin.Forms.Page' while attempting to activate
'MyXamarinProject.ViewModels.LoginViewModel'.'
I am using the NuGet Packages:
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.DependencyInjection.Abstractions
In Locator.cs:
public static class Locator { private static IServiceProvider _serviceProvider; public static void Initialize() { var services = new ServiceCollection(); services.AddSingleton<IMobileUserRepository, MobileUserRepository>(); services.AddTransient<LoginViewModel>(); services.AddTransient<MainPageViewModel>(); services.AddTransient<SignUpPageViewModel>(); services.AddTransient<LoginView>(); services.AddTransient<MainPage>(); services.AddTransient<SignUpPage>(); _serviceProvider = services.BuildServiceProvider(); } public static T Resolve<T>() => _serviceProvider.GetService<T>(); }
in App.xaml.cs:
public partial class App : Application { public App() { InitializeComponent(); Locator.Initialize(); InitializeRepositories(); if (!IsUserLoggedIn) { MainPage = new NavigationPage(Locator.Resolve<LoginView>()); // ERROR happens after this step, after calling the Locator static method: public static T Resolve<T>() => _serviceProvider.GetService<T>(); } else { MainPage = new NavigationPage(Locator.Resolve<MainPage>()); } } private static void InitializeRepositories() { IMobileUserRepository _mobileUserRepository = Locator.Resolve<IMobileUserRepository>(); _mobileUserRepository.Initialize(); } protected override void OnStart() { } protected override void OnSleep() { } protected override void OnResume() { } }
In BaseWithHttp.cs:
public class BaseWithHttp : BindableBase { public INavigation Navigation { get; set; } protected async Task<bool> SendToClientApi(Func<ClientApiClient, Task> clientAction) { try { var client = new ClientApiClient(Constants.ClientApiUrl, App.UserToken); await clientAction(client); return true; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); return false; } } }
in LoginViewModel.cs:
public class LoginViewModel : BaseWithHttp { private Page _loginPage; private readonly IMobileUserRepository _mobileUserRepository; public LoginViewModel(Page loginPage, IMobileUserRepository mobileUserRepository) { _loginPage = loginPage; _signupCommand = new DelegateCommand(ExecuteSignupCommand); _loginCommand = new DelegateCommand(ExecuteLoginCommand); _mobileUserRepository = mobileUserRepository; } private string _userName; public string UserName { get { return _userName; } set { _userName = value; RaisePropertyChanged(); } } private string _password; public string Password { get { return _password; } set { _password = value; RaisePropertyChanged(); } } private string _loginMessage; public string LoginMessage { get { return _loginMessage; } set { _loginMessage = value; RaisePropertyChanged(); } } private DelegateCommand _signupCommand; public ICommand SignupCommand => _signupCommand; private async void ExecuteSignupCommand() { await _loginPage.Navigation.PushAsync(new SignUpPage()); } private DelegateCommand _loginCommand; public ICommand LoginCommand => _loginCommand; private async void ExecuteLoginCommand() { var user = new User { Username = this.UserName, Password = this.Password }; DependencyService.Get<ICustomActivityIndicatorPage>().InitActivityPage(new LoggingInActivityIndicatorPage()); DependencyService.Get<ICustomActivityIndicatorPage>().ShowActivityPage(); var isValid = await TryLogin(user); if (isValid) { MobileUser mobileUser = new MobileUser // this is just for test { UserID = 1, SiteID = 1, LoggerID = 1 }; await _mobileUserRepository.AddORUpdateMobileUser(mobileUser); var mobileUsers = _mobileUserRepository.GetMobileUsers(); _loginPage.Navigation.InsertPageBefore(new MainPage(), _loginPage); DependencyService.Get<ICustomActivityIndicatorPage>().HideActivityPage(); await _loginPage.Navigation.PopAsync(); } else { App.IsUserLoggedIn = false; this.LoginMessage = "Login failed"; this.Password = string.Empty; DependencyService.Get<ICustomActivityIndicatorPage>().HideActivityPage(); } } private async Task<bool> TryLogin(User user) { var result = await SendToClientApi(async (clientClient) => { var clientResponse = await clientClient.Auth_SignInAsync(new ProjectServer.Api.Library.Client.SignInDtoOfUserAndGuid() { User = user.Username, Password = user.Password }); if (clientResponse != null) { App.IsUserLoggedIn = true; App.UserToken = clientResponse?.Token; App.RefreshToken = clientResponse?.RefreshToken; } }); return result; } }
in LoginView.xaml.cs:
[XamlCompilation(XamlCompilationOptions.Compile)] public partial class LoginView : ContentPage { public LoginView(LoginViewModel loginPageViewModel) { InitializeComponent(); loginPageViewModel.Navigation = Navigation; BindingContext = loginPageViewModel; } }
Any help is appreciated.
Answers
I tried to reproduce this issue by creating a new app according to the code you posted, but failed.
What's the
IMobileUserRepository
,MobileUserRepository
and theClientApiClient
?Could you please post more details about this issue?
@jezh Thank you so much for your help. The api client is just a swagger api, calls some endpoints to log in the user witht the db, can reproduce with some fake data, the log in in part shouldnt make a difference. Here are the missing classes:
Thank you so much for sharing your code snippets,but what's the
ClientApiClient
andICustomActivityIndicatorPage
?If it is convenient for you, could you please share the basic code snippets which could help us to reproduce this issue?