I am writing web api in C#, trying to follow REST concepts, i.e. success response will be HttpStatus: 200, validation errors will be 433 and so on.
I have ExceptionFilter registered for entire application in global.asax.
My question here is, for validation errors such as during authentication, if authentication failed, then how should the message be communicated back to client (it has to be a different status code such as 433 or 401).
As of now I am throwing custom exceptions from business layer. Is it recommended to throw exceptions in case of errors?
Following is the code sample:
Logger
public class ExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
HttpResponseMessage response;
if (context.Exception is ExceptionBase)
{
response = context.Request.CreateResponse(HttpStatusCode.InternalServerError,
new ErrorDTO() { ErrorCode = (int)((ExceptionBase)context.Exception).ExceptionCode, Messages = ((ExceptionBase)context.Exception).Message });
}
else {
response = context.Request.CreateResponse(HttpStatusCode.InternalServerError,
new ErrorDTO() { ErrorCode = (int)HttpStatusCode.InternalServerError, Messages = "Error occured at server." });
}
context.Response = response;
base.OnException(context);
LogException(context);
}
private static void LogException(HttpActionExecutedContext context)
{
if (context.Exception != null)
{
Logger.Instance.LogError(context.ActionContext.ActionDescriptor.ActionName, context.Exception);
}
}
public override Task OnExceptionAsync(HttpActionExecutedContext context, CancellationToken cancellationToken)
{
return base.OnExceptionAsync(context, cancellationToken);
}
}
Business layer
public AuthorizationTokenDTO AuthenticateUser(UserDTO userDTO)
{
User userEntity = _userRepository.GetUserWithAssociatedRole(userDTO.UserName);
if (userEntity == null)
throw new BLException("User does not exists.", ExceptionCode.RestApiValidation);
ActiveDirectory activeDirectory = _activeDirectoryRepository.GetEntityById(ConfigurationSettings.GetConfigSetting<int>(ApplicationConstants.ActiveDirectoryId));
if (activeDirectory == null)
throw new BLException("UserName or password is incorrect.", ExceptionCode.RestApiValidation);
using (var context = new PrincipalContext(ContextType.Domain))
{
string password = EncryptionUtility.Decrypt(userDTO.Password, ConfigurationSettings.GetConfigSetting<string>(ApplicationConstants.PrivateKeyForRSAEncryption));
if (!context.ValidateCredentials(userDTO.UserName, password))
throw new BLException("UserName or password is incorrect.", ExceptionCode.RestApiValidation);
UserAccessTokenDTO accessToken = GenrateNewUserAccessToken(userEntity);
if (accessToken == null)
throw new BLException("Error occured while generating access token.", ExceptionCode.RestApiValidation);
return GetAuthorizationTokenDTO(userEntity, accessToken);
}
}
Is it recommended to throw exceptions for such cases? or is there a better way to write Web APIs?