1
votes

I am working on my first Xamarin application. I am trying to display my first page but getting following error on base.ViewDidLoad(); line in ViewDidLoad()

MvvmCross.Platform.Exceptions.MvxException has been thrown

Failed to construct and initialize ViewModel for type iManage.ViewModels.LoginViewModel from locator MvxDefaultViewModelLocator - check InnerException for more information

LoginView.cs:

public partial class LoginView : MvxViewController<LoginViewModel>
{
    public LoginView() : base("LoginView", null)
    {
    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        txtUser.Layer.CornerRadius = 15;
        txtPassword.Layer.CornerRadius = 15;
        btnLogin.Layer.CornerRadius = 20;

        var set = this.CreateBindingSet<LoginView, LoginViewModel>();
        set.Bind(txtUser).To(vm => vm.Username);
        set.Bind(txtPassword).To(vm => vm.Password);
        set.Bind(btnLogin).To(vm => vm.LoginCommand);
        //set.Bind(btnLogin).To(vm => vm.AttemptLogin());
        set.Apply();
    }

    public override void DidReceiveMemoryWarning()
    {
        base.DidReceiveMemoryWarning();
        // Release any cached data, images, etc that aren't in use.
    }
}

LoginViewModel.cs:

public class LoginViewModel : BaseViewModel
{
    private readonly ILoginService _loginService;

    private readonly IDialogService _dialogService;

    public LoginViewModel(ILoginService loginService, IDialogService dialogService)
    {
        _loginService = loginService;
        _dialogService = dialogService;

        Username = "TestUser";
        Password = "YouCantSeeMe";
        IsLoading = false;
    }

    private string _username;
    public string Username
    {
        get
        {
            return _username;
        }

        set
        {
            SetProperty(ref _username, value);
            RaisePropertyChanged(() => Username);
        }
    }

    private string _password;
    public string Password
    {
        get
        {
            return _password;
        }

        set
        {
            SetProperty(ref _password, value);
            RaisePropertyChanged(() => Password);
        }
    }

    private bool _isLoading;

    public bool IsLoading
    {
        get
        {
            return _isLoading;
        }

        set
        {
            SetProperty(ref _isLoading, value);
        }
    }

    private IMvxCommand _loginCommand;
    public virtual IMvxCommand LoginCommand
    {
        get
        {
            _loginCommand = _loginCommand ?? new MvxCommand(AttemptLogin, CanExecuteLogin);
            return _loginCommand;
        }
    }

    private void AttemptLogin()
    {
        if (_loginService.Login(Username, Password))
        {
            ShowViewModel<DashboardEmpViewModel>();
        }
        else
        {
            _dialogService.Alert("We were unable to log you in!", "Login Failed", "OK");
        }
    }

    private bool CanExecuteLogin()
    {
        return (!string.IsNullOrEmpty(Username) || !string.IsNullOrWhiteSpace(Username))
               && (!string.IsNullOrEmpty(Password) || !string.IsNullOrWhiteSpace(Password));
    }
}

LoginService.cs:

public class LoginService : ILoginService
{
    /// <summary>Initializes a new instance of the <see cref="LoginService"/> class.</summary>
    public LoginService() // e.g. LoginService(IMyApiClient client)
    {
        // this constructor would most likely contain some form of API Client that performs
        // the message creation, sending and deals with the response from a remote API
    }

    /// <summary>
    /// Gets a value indicating whether the user is authenticated.
    /// </summary>
    public bool IsAuthenticated { get; private set; }

    /// <summary>Gets the error message.</summary>
    /// <value>The error message.</value>
    public string ErrorMessage { get; private set; }

    /// <summary>
    /// Attempts to log the user in using stored credentials if present
    /// </summary>
    /// <returns> <see langword="true"/> if the login is successful, false otherwise </returns>
    public bool Login()
    {
        // get the stored username from previous sessions
        // var username = Settings.UserName;
        // var username = _settingsService.GetValue<string>(Constants.UserNameKey);

        // force return of false just for demo purposes
        IsAuthenticated = false;
        return IsAuthenticated;
    }

    /// <summary>The login method to retrieve OAuth2 access tokens from an API. </summary>
    /// <param name="userName">The user Name (email address) </param>
    /// <param name="password">The users <paramref name="password"/>. </param>
    /// <param name="scope">The required scopes. </param>
    /// <returns>The <see cref="bool"/>. </returns>
    public bool Login(string userName, string password, string scope)
    {
        try
        {
            //IsAuthenticated = _apiClient.ExchangeUserCredentialsForTokens(userName, password, scope);
            return IsAuthenticated;
        }
        catch (ArgumentException argex)
        {
            ErrorMessage = argex.Message;
            IsAuthenticated = false;
            return IsAuthenticated;
        }
    }

    /// <summary>
    /// Logins the specified user name.
    /// </summary>
    /// <param name="userName">Name of the user.</param>
    /// <param name="password">The users password.</param>
    /// <returns></returns>
    public bool Login(string userName, string password)
    {
        // this simply returns true to mock a real login service call
        return true;
    }
}

Setup.cs:

public class Setup : MvxIosSetup
{
    public Setup(IMvxApplicationDelegate applicationDelegate, IMvxIosViewPresenter presenter) : base(applicationDelegate, presenter)
    {

    }

    protected override IMvxApplication CreateApp()
    {
        return new App();
    }
}

I have used this url to implement it.

Edit1: Exception Detail

Edit2: Inner Exception:

MvvmCross.Platform.Exceptions.MvxException: Failed to construct and initialize ViewModel for type iManage.ViewModels.LoginViewModel from locator MvxDefaultViewModelLocator - check InnerException for more information ---> MvvmCross.Platform.Exceptions.MvxException: Problem creating viewModel of type LoginViewModel ---> MvvmCross.Platform.Exceptions.MvxIoCResolveException: Failed to resolve parameter for parameter dialogService of type IDialogService when creating iManage.ViewModels.LoginViewModel at MvvmCross.Platform.IoC.MvxSimpleIoCContainer.GetIoCParameterValues (System.Type type, System.Reflection.ConstructorInfo firstConstructor) [0x00066] in <6adc0d5857264558a9d45778a78ae02a>:0 at MvvmCross.Platform.IoC.MvxSimpleIoCContainer.IoCConstruct (System.Type type) [0x0002c] in <6adc0d5857264558a9d45778a78ae02a>:0 at MvvmCross.Platform.Mvx.IocConstruct (System.Type t) [0x00006] in <6adc0d5857264558a9d45778a78ae02a>:0 at MvvmCross.Core.ViewModels.MvxDefaultViewModelLocator.Load (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterValues, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00000] in :0 --- End of inner exception stack trace --- at MvvmCross.Core.ViewModels.MvxDefaultViewModelLocator.Load (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterValues, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00029] in :0 at MvvmCross.Core.ViewModels.MvxViewModelLoader.LoadViewModel (MvvmCross.Core.ViewModels.MvxViewModelRequest request, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00035] in :0 --- End of inner exception stack trace --- at MvvmCross.Core.ViewModels.MvxViewModelLoader.LoadViewModel (MvvmCross.Core.ViewModels.MvxViewModelRequest request, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00068] in :0 at MvvmCross.iOS.Views.MvxViewControllerExtensionMethods.LoadViewModel (MvvmCross.iOS.Views.IMvxIosView iosView) [0x0005f] in <6f99728979034e579bc72f6d53e5bc35>:0 at MvvmCross.Core.Views.MvxViewExtensionMethods.OnViewCreate (MvvmCross.Core.Views.IMvxView view, System.Func`1[TResult] viewModelLoader) [0x00012] in :0 at MvvmCross.iOS.Views.MvxViewControllerExtensionMethods.OnViewCreate (MvvmCross.iOS.Views.IMvxIosView iosView) [0x00001] in <6f99728979034e579bc72f6d53e5bc35>:0 at MvvmCross.iOS.Views.MvxViewControllerAdapter.HandleViewDidLoadCalled (System.Object sender, System.EventArgs e) [0x00007] in <6f99728979034e579bc72f6d53e5bc35>:0 at at (wrapper delegate-invoke) :invoke_void_object_EventArgs (object,System.EventArgs) at MvvmCross.Platform.Core.MvxDelegateExtensionMethods.Raise (System.EventHandler eventHandler, System.Object sender) [0x00003] in <6adc0d5857264558a9d45778a78ae02a>:0 at MvvmCross.Platform.iOS.Views.MvxEventSourceViewController.ViewDidLoad () [0x00006] in <4467c42ffcc4478e847227b8e4af47fe>:0 at MvvmCross.iOS.Views.MvxViewController.ViewDidLoad () [0x00001] in <6f99728979034e579bc72f6d53e5bc35>:0 at iManage.iOS.Views.LoginView.ViewDidLoad () [0x00001] in /Users/pankajsachdeva/Projects/iManage/iOS/Views/LoginView.cs:18 at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr) at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Users/builder/data/lanes/5665/6857dfcc/source/xamarin-macios/src/UIKit/UIApplication.cs:79 at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/5665/6857dfcc/source/xamarin-macios/src/UIKit/UIApplication.cs:63 at iManage.iOS.Application.Main (System.String[] args) [0x00001] in /Users/pankajsachdeva/Projects/iManage/iOS/Main.cs:17

1
"check InnerException for more information", I don't see the InnerException in your question - Camilo Terevinto
Hi Camilo, how should I see the InnerException? I am sorry I am new to Xamarin. - pankaj
Debug up to the point where the exception is thrown, in the debugger you'll see the exception details and the InnerException property has the actual error - Camilo Terevinto
I have just added a screen shot of it, please check - pankaj
Given the error message, it seems that you did not register IDialogService in the container - Camilo Terevinto

1 Answers

1
votes

You must register the implementations of your services in the IoC container so that they can be resolved when needed. This can be done in two places in general:

For platform independent services in the App.cs in the Initialize method:

public class App : MvxApplication
{
   public override void Initialize()
   {
      ...
      Mvx.ConstructAndRegisterSingleton<IDialogService,DialogService>();
      ...
   }
}

(Note that this should be done by default, because the default App class already contains a block that automatically registers all types with the "Service" suffix)

For a platform specific service in the platform's Setup.cs in the InitializeFirstChance method, for example for Windows it would be:

public class Setup : MvxWindowsSetup
{
   protected override void InitializeFirstChance()
   {
       Mvx.ConstructAndRegisterSingleton<IDialogService,DialogService>();
       base.InitializeFirstChance();
   }
}

I'm guessing the DialogService will be platform dependent, so the second solution will be more suitable.

You can use LazyConstructAndRegisterSingleton to make sure the instance is created only when actually needed for the first time. You can also use RegisterType to just register the type and create a new instance each time it is needed.

More about MvvmCross IoC is available in the documentation.