3

I'm running up against the age old return codes versus exceptions debate, and could do with some advice on a concrete example.

I have a simple method Authenticate, which takes your typical username, password and returns a session key on success, otherwise returns the failure reason. Something like:

Guid Authenticate(string username, string password)

Although the failure reason won't be displayed to the user I'd like to pass this up the layers so that they can take appropriate action.

I think there are three groups of possible responses:
1. Success
2. Expected/common failures e.g. invalid password/user, account locked
3. Unusual/unexpected failures/exceptions e.g. db connection failure etc

I'm happy with 1 being indicated by returning a valid guid, and 3 by an exception bubbling up, but what should I do for 2?

I'm edging towards exceptions, but I'm not sure something common like a incorrect password which could happen 50% of the time should do this? Alternatives are returning some sort of complex return status object (including the guid if successful) or an out parameter??

sll
  • 61,540
  • 22
  • 104
  • 156
Robert Roe
  • 122
  • 9
  • If the failures are expected then exceptions would seem, to me, to not be the way to go as they aren't exceptional and are something you can likely handle. – Firedragon Feb 24 '12 at 11:37

6 Answers6

4

Try out using pattern Do()/TryDo() for better flexibility of the API. So client (class, service, etc) which uses this API would have options:

API:

// Throw in case of error with AuthenticateExceptionEventArgs 
// contains information regarding error context
Guid Authenticate(string name, string password);

// Returns a status of operation, does not throw in case of error
AuthenticateStatus TryAuthenticate(string name, string password, out Guid guid);

Requires following infrastructure types:

enum AuthenticateStatus
{  
   Success,
   InvalidPassword
}

class AuthenticateExceptionEventArgs : EventArgs
{
    public AuthenticateStatus Status { get; private set; }
}
nhahtdh
  • 55,989
  • 15
  • 126
  • 162
sll
  • 61,540
  • 22
  • 104
  • 156
  • Is there a good reason to have both methods here as I would have thought both methods would need to do exception handling, just the one does it itself and the other you would need to do? – Firedragon Feb 24 '12 at 11:48
  • @Firedragon : Two methods are for better flexibility of the API, so if you would use more lightveigh/faster way - use method which does not generate exception, otherwise you obviously need to wrap `Authenticate()` by `try/catch` block, it's up to API client – sll Feb 24 '12 at 11:52
2

You could return an enum using out, if successfull, the Guid will be set, else you can check it for a status:

Guid Authenticate(string username, string password, out AuthResult authResult)

enum AuthResult {
    Success,
    BadPassword,
    BadUserName,
    .... 
}

Alternatively, turn the logic round slightly - return an Enum from the method, and set the GuiD via the out

AuthResult Authenticate(string username, string password, out Guid guid)
Morphed
  • 3,527
  • 2
  • 29
  • 55
1

You know you can use different types of exceptions depending on how you plan to handle them. I would suggest using ApplicationException for those exceptions that you want to be displayed to the user and generic Exception for other stuff that you don't want to be displayed.

I am strongly against special return values in languages like C# that do not support union types. Special return values work correctly in languages like Haskell, otherwise they are always a reason to resort to documentation and a source of bugs.

linepogl
  • 9,147
  • 4
  • 34
  • 45
  • `ApplicationException` shouldn't be used any more. Exceptions derived directly from `Exception` could be used. http://stackoverflow.com/questions/5685923/what-is-applicationexception-for-in-net – Firedragon Feb 24 '12 at 11:34
  • @Firedragon Yes, you are correct. It's been a while since I last used C#. In any case, a user defined special exception classes that work similarly to `ApplicationException` is the answer. – linepogl Feb 24 '12 at 11:38
1

The default action for an exception is for the program to die; the default action of a return code is for the program to continue. If, for example, the method has an invalid password, would it better if it died or continued? That would be your criteria for determining if it should use an exception or a return code.

shawnhcorey
  • 3,545
  • 1
  • 15
  • 17
0

Out variable, will do the trick, you can use Out vairable Out Parameters

Guid Authenticate(string username, string password, out bool Status)
{
   Status=false; //initially it will be false 
  if(LoginSuccess)
  {
    Status=True; // So that you can check whether the user is valid or not 
  }

}

to User this function call like this

bool LoginStatus; 
someGuidObj =  Authenticate(username, password, out LoginStatus)
Ravi Gadag
  • 15,735
  • 5
  • 57
  • 83
0

Return a custom type as the result & do not throw any exceptions:

public class AuthenticationResult
{
    // will be Guid.Empty if unable to authenticate.
    public Guid SessionKey
    {
        get;
        set;
    }

    public bool Authenticated
    {
        get
        {
            return this.SessionKey != Guid.Empty
        }
    }

    // This will contain the login failure reason.
    public string FailureMessage
    {
        get;
        set;
    }
}

The code which calls the Authenticate method can then throw an exception with the failure message if required.

Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60