using System;
using System.Collections.Generic;
using System.Linq;
using Quadarax.Foundation.Core.Attributes;
using Quadarax.Foundation.Core.Value.Extensions;
namespace Quadarax.Foundation.Core.Exceptions
{
///
/// Provides a base class for exceptions that include a code.
///
[Serializable]
public class CodeException : Exception
{
public int Code => this.GetCode();
public CodeException(int code, string message, Exception innerException) : base(message, innerException)
{
this.SetCode(code);
}
public CodeException(int code, string message) : base(message)
{
this.SetCode(code);
}
public CodeException(int code, string message, params object[] messageArguments) : base(string.Format(message, messageArguments))
{
this.SetCode(code);
}
public CodeException(int code, string message, Exception innerException, params object[] messageArguments) : base(string.Format(message, messageArguments), innerException)
{
this.SetCode(code);
}
}
///
/// Provides a base class for exceptions that include a code in enumeration form.
/// Exception message is resolved from the of the enumeration.
///
/// Enumeration that defines error codes end its message defined by .
public class CodeException : CodeException where TCodeEnum : struct, Enum
{
public new TCodeEnum Code => (TCodeEnum)Enum.ToObject(typeof(TCodeEnum), this.GetCode());
///
/// Static cache for error messages.
///
private static readonly IDictionary _messageCache = new Dictionary();
public CodeException(TCodeEnum code, Exception innerException) : base(Convert.ToInt32(code),
ResolveMessage(code), innerException)
{
}
public CodeException(TCodeEnum code) : base(Convert.ToInt32(code), ResolveMessage(code))
{
}
public CodeException(TCodeEnum code, params object[] messageArguments) : base(
Convert.ToInt32(code), ResolveMessage(code, messageArguments))
{
}
public CodeException(TCodeEnum code, Exception innerException, params object[] messageArguments)
: base(Convert.ToInt32(code),ResolveMessage(code,messageArguments), innerException)
{
}
private static string ResolveMessage(TCodeEnum code, params object[] messageArguments)
{
var codeValue = Convert.ToInt32(code);
// check if cache is initialized
if (_messageCache.Count == 0)
{
// initialize cache
var fields = typeof(TCodeEnum).GetFields();
var names = Enum.GetNames(typeof(TCodeEnum)).ToArray();
var values = Enum.GetValues(typeof(TCodeEnum));
// iterate through all fields of the enumeration
foreach (var field in fields)
{
var attr = field.GetCustomAttributes(typeof(ErrorMessageAttribute), false);
var index = Array.IndexOf(names, field.Name);
if (index<0) continue;
var fieldVal = (int) (values.GetValue(index) ?? -1);
// if value has attribute ErrorMessageAttribute, add it to the cache
if (attr.Length == 1)
{
var message = ((ErrorMessageAttribute)attr[0]).ErrorMessage;
_messageCache.Add(fieldVal, message);
}
else
{
// message not found, log warning and add default message to the cache
System.Diagnostics.Debug.WriteLine($"Error message in enumeration '{typeof(TCodeEnum).Name}' not found for code '{codeValue}'", "WARN");
_messageCache.Add(fieldVal, $"Error message code: {code} [{fieldVal}]");
}
}
}
// return message from cache
return string.Format(_messageCache[codeValue], messageArguments);
}
}
}