Unable to catch login exception P4API.net - .NET7.0/WinUI3

103 Views Asked by At

I am working on catching a simple login exception (in the event of an incorrect password entry) for an application I am building for internal use. All of my p4api code works fine for connection, login, client creation, syncing, etc but I cannot seem to catch exceptions and display them no matter what I try.

The exceptions are caught no problem by the debugger

Perforce.P4.P4Exception: 'Authentication failed.'

Exception caught by debugger

Catch doesn't seem to work whether I use catch (P4Exception ex), catch (Exception ex), or catch with no types.

Current code block:

public void PerforceLogin(){
    var P4USER = CurrentUserName; //established as current logged in user globally
    P4PORT = locationSelectText.Split('(')[1].TrimEnd(')');
    var P4PASSWD = p4PasswordBox.Password;
    var srv = new Perforce.P4.Server(new ServerAddress(P4PORT));
    var p4 = new Perforce.P4.Repository(srv);

    var p4Options = new Perforce.P4.Options();
    p4Options["-a"] = null;
    try
    {
        p4.Connection.Login(P4PASSWD, p4Options);
    }
    catch (P4Exception ex)
    {
        Debug.WriteLine("Exception caught: " + ex.Message);
        //DisplayDialogBox(ex.Message, "Login Failed");
        return;
    }
}
private void p4LoginButton_Click(object sender, RoutedEventArgs e)
{
    PerforceLogin();
}

Currently have my DisplayDialogBox method noted out to rule out any issues stemming from that but still nothing in my Debug output either unfortunately.

I've also messed with setting P4Exception.MinThrowLevel = ErrorSeverity.LEVEL to various levels with no real success.

I don't have a ton of experience with catching exceptions, especially from non-.Net sources but it seems like it should be pretty straight forward?

EDIT to add Call Stack:

p4api.net.dll!Perforce.P4.P4Exception.Throw(string cmd, string[] args, Perforce.P4.P4ClientErrorList errors, Perforce.P4.P4ClientInfoMessageList details)
p4api.net.dll!Perforce.P4.P4Server.RunCommand(string cmd, uint cmdId, bool tagged, string[] args, int argc)
p4api.net.dll!Perforce.P4.P4Command.RunInt(Perforce.P4.StringList flags)
p4api.net.dll!Perforce.P4.P4CommandResult.P4CommandResult(Perforce.P4.P4Command cmd, Perforce.P4.StringList flags)
p4api.net.dll!Perforce.P4.P4Command.Run(Perforce.P4.StringList flags)
p4api.net.dll!Perforce.P4.Connection.Login(string password, Perforce.P4.Options options, string user)
p4api.net.dll!Perforce.P4.Connection.Login(string password, Perforce.P4.Options options)
OMIT.dll!OMIT.Views.MainPage.PerforceLogin() Line 419
    at OMIT\Views\MainPage.xaml.cs(419)
OMIT.dll!OMIT.Views.MainPage.p4LoginButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) Line 971
    at OMIT\Views\MainPage.xaml.cs(971)
Microsoft.WinUI.dll!WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.GetEventInvoke.AnonymousMethod__1_0(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) Line 8184
    at C:\__w\1\s\BuildOutput\obj\x86fre\src\projection\generated\WinRTEventHelpers.cs(8184)
Microsoft.WinUI.dll!ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(nint thisPtr, nint sender, nint e) Line 26137
    at C:\__w\1\s\BuildOutput\obj\x86fre\src\projection\generated\Microsoft.UI.Xaml.cs(26137)
[Native to Managed Transition]
[Managed to Native Transition]
Microsoft.WinUI.dll!ABI.Microsoft.UI.Xaml.IApplicationStaticsMethods.Start(WinRT.IObjectReference _obj, Microsoft.UI.Xaml.ApplicationInitializationCallback callback) Line 13655
    at C:\__w\1\s\BuildOutput\obj\x86fre\src\projection\generated\Microsoft.UI.Xaml.cs(13655)
Microsoft.WinUI.dll!Microsoft.UI.Xaml.Application.Start(Microsoft.UI.Xaml.ApplicationInitializationCallback callback) Line 312
    at C:\__w\1\s\BuildOutput\obj\x86fre\src\projection\generated\Microsoft.UI.Xaml.cs(312)
OMIT.dll!OMIT.Program.Main(string[] args) Line 31
    OMIT\obj\x64\Release\net7.0-windows10.0.19041.0\win10-x64\App.g.i.cs(31)

Edit to add: Username is auto-pulled from Windows login as our Perforce instance is LDAP authenticated and password is pulled from a password box on the mainform. There are no issues running this with the right password but I'd love to be able to detect bad passwords!

Edit to add Usings:

using COD_Workspace_Setup.ViewModels;
using Monitor.Core.Utilities;
using Microsoft.UI.Xaml.Controls;
using Perforce.P4;
using System;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Diagnostics.Eventing.Reader;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Management;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Xml.Linq;
using Microsoft.UI.Xaml;
using Windows.UI.Popups;

Edit to add new snippet. I went ahead and built a standalone project in an attempt to get this working. It's only a PasswordBox and a Button for login. All of the p4 info is hard coded.

using Microsoft.UI.Xaml.Controls;
using Perforce.P4;
using System;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Diagnostics.Eventing.Reader;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Xml.Linq;
using Microsoft.UI.Xaml;
using Windows.UI.Popups;
using P4LoginTest.ViewModels;
using Microsoft.UI.Xaml.Media;

namespace P4LoginTest.Views;

public sealed partial class MainPage : Page
{
    public MainViewModel ViewModel
    {
        get;
    }

    public MainPage()
    {
        ViewModel = App.GetService<MainViewModel>();
        InitializeComponent();
    }
    private async void DisplayDialogBox(string message, string title)
    {
        if (!string.IsNullOrWhiteSpace(message))
        {
            ContentDialog dialog = new ContentDialog();

            dialog.XamlRoot = this.XamlRoot;
            dialog.Style = Application.Current.Resources["DefaultContentDialogStyle"] as Style;
            dialog.Title = title;
            dialog.PrimaryButtonText = "Ok";
            dialog.DefaultButton = ContentDialogButton.Primary;
            dialog.Content = message;

            var result = await dialog.ShowAsync();
        }
    }
    public void PerforceLogin()
    {
        if (p4PasswordBox.Password.Length > 0)
        {
            Debug.WriteLine("Starting Login");
            p4PasswordBox.IsEnabled = false;
            var P4USER = "HARDCODEDUSERNAME";
            var P4PORT = "HARDCODEDSERVERFQDN";
            var P4PASSWD = p4PasswordBox.Password;
            Debug.WriteLine("P4PORT = " + P4PORT);

            var srv = new Perforce.P4.Server(new ServerAddress(P4PORT));
            var p4 = new Perforce.P4.Repository(srv);
            p4.Connection.UserName = P4USER;

            Debug.WriteLine("Starting connection...");
            p4.Connection.Connect(new Perforce.P4.Options());
            Debug.WriteLine("Connection passed");

            var p4Options = new Perforce.P4.Options();
            p4Options["-a"] = null;

            Debug.WriteLine("Starting Login try block");
            try
            {
                p4.Connection.Login(P4PASSWD, p4Options);
            }
            catch (Perforce.P4.P4Exception)
            {
                Debug.WriteLine("Exception CAUGHT, P4Exception");
                DisplayDialogBox("Incorrect password entered, please try again.", "Login Failed");
                System.Diagnostics.Debugger.Break();
                return;
            }
            catch
            {
                Debug.WriteLine("Exception CAUGHT, ALL");
                System.Diagnostics.Debugger.Break();
                return;
            }
            Debug.WriteLine("Try block passed");
        }
    }
    void p4LoginButton_Click(object sender, RoutedEventArgs e)
    {
        PerforceLogin();
    }
}

And the Output from the above:

Starting Login
P4PORT = HARDCODEDSERVERFQDN
Starting connection...
Connection passed
Starting Login try block
Exception thrown: 'Perforce.P4.P4Exception' in p4api.net.dll
Exception thrown: 'Perforce.P4.P4Exception' in p4api.net.dll
Exception thrown: 'Perforce.P4.P4Exception' in p4api.net.dll
Try block passed

EDIT: I spun up a WinForms project and copy pasted my login method and the catch still doesn't work.

I did, however, seem to resolve it in a roundabout way. I wrapped the p4 command I run immediately after login in a try/catch statement:

            // Get list of top level folders in Depot to build branch select menu
            var opts = new GetDepotDirsCmdOptions(GetDepotDirsCmdFlags.None, null);
            var dirs = new List<String>();
            dirs.Add("//" + projectID + "/*");
            IList<String> target = new List<String>();
            try
            {
                target = p4.GetDepotDirs(dirs, opts);
            }
            catch (P4Exception e)
            {
                DisplayDialogBox(e.Message + "\nPlease retry password entry.", "Login Error.");
                return;
            }

The command fails if the password is bad and it returns a P4Exception referencing an error in P4PSSWD which I can use to toss up a dialog window asking to reenter the password. So while I can't catch it at login time I can still catch it in follow up commands that fall back on P4PSSWD for their operation. I plan to read the e.Message string to look for a P4PSSWD error to differentiate the error messages but as I've never seen any other error with this command it's a low priority. Hope this helps others!

0

There are 0 best solutions below