First of all, if the login name is null probably is a bug because I don't think that an input from the UI could store a null value. Something could be wrong in some layer on top of your login code.
For above case, and only for that case, I would throw an ArgumentNullException. In my case, I would use code contracts.
Anyway, I'll give you a hint: I would turn login information into a class, and I would implement the specification pattern to validate it. Also, see how I implement parameter and return value validation using code contracts (design by contract):
public class UserLogin
{
public string Name { get; set; }
public string Password { get; set; }
}
public class UserLoginSpec
{
// This could be a simplified way of storing broken rules,
// where keys are the affected resource or property by the
// rule, and the value, a human-readable description of what
// happened with the broken rule...
public Dictionary<string, string> BrokenRules { get; } = new Dictionary<string, string>();
public bool IsSatisfiedBy(UserLogin login)
{
Contract.Requires(login != null);
if(string.IsNullOrEmpty(login.Name))
BrokenRules.Add("Name", "Name cannot be empty");
if(string.IsNullOrEmpty(login.Password))
BrokenRules.Add("Password", "Password cannot be empty");
// The spec is passed if no broken rule has been added
return BrokenRules.Count == 0;
}
}
public class UserLoginResult
{
public UserLoginResult(UserLoginSpec spec)
{
Contract.Requires(spec != null);
Successful = spec.BrokenRules.Count == 0;
Errors = spec.BrokenRules;
}
public bool Successful { get; private set; }
public Dictionary<string, string> Errors { get; private set; }
}
Now your authentication method would look as follows:
public UserLoginResult Authenticate(UserLogin login)
{
Contract.Requires(login != null);
Contract.Ensures(Contract.Result<UserLoginResult>() != null);
UserLoginSpec loginSpec = new UserLoginSpec();
if(loginSpec.IsSatisfiedBy(login))
{
// Actual code to validate user's credentials here
}
return new UserLoginResult(loginSpec);
}
Now you can go further and generalize this solution, or add more collected data in your result classes.