CodeException.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Quadarax.Foundation.Core.Attributes;
  5. using Quadarax.Foundation.Core.Value.Extensions;
  6. namespace Quadarax.Foundation.Core.Exceptions
  7. {
  8. /// <summary>
  9. /// Provides a base class for exceptions that include a code.
  10. /// </summary>
  11. [Serializable]
  12. public class CodeException : Exception
  13. {
  14. public int Code => this.GetCode();
  15. public CodeException(int code, string message, Exception innerException) : base(message, innerException)
  16. {
  17. this.SetCode(code);
  18. }
  19. public CodeException(int code, string message) : base(message)
  20. {
  21. this.SetCode(code);
  22. }
  23. public CodeException(int code, string message, params object[] messageArguments) : base(string.Format(message, messageArguments))
  24. {
  25. this.SetCode(code);
  26. }
  27. public CodeException(int code, string message, Exception innerException, params object[] messageArguments) : base(string.Format(message, messageArguments), innerException)
  28. {
  29. this.SetCode(code);
  30. }
  31. }
  32. /// <summary>
  33. /// Provides a base class for exceptions that include a code in enumeration form.
  34. /// Exception message is resolved from the <see cref="ErrorMessageAttribute"/> of the enumeration.
  35. /// </summary>
  36. /// <typeparam name="TCodeEnum">Enumeration that defines error codes end its message defined by <see cref="ErrorMessageAttribute"/>.</typeparam>
  37. public class CodeException<TCodeEnum> : CodeException where TCodeEnum : struct, Enum
  38. {
  39. public new TCodeEnum Code => (TCodeEnum)Enum.ToObject(typeof(TCodeEnum), this.GetCode());
  40. /// <summary>
  41. /// Static cache for error messages.
  42. /// </summary>
  43. private static readonly IDictionary<int, string> _messageCache = new Dictionary<int, string>();
  44. public CodeException(TCodeEnum code, Exception innerException) : base(Convert.ToInt32(code),
  45. ResolveMessage(code), innerException)
  46. {
  47. }
  48. public CodeException(TCodeEnum code) : base(Convert.ToInt32(code), ResolveMessage(code))
  49. {
  50. }
  51. public CodeException(TCodeEnum code, params object[] messageArguments) : base(
  52. Convert.ToInt32(code), ResolveMessage(code, messageArguments))
  53. {
  54. }
  55. public CodeException(TCodeEnum code, Exception innerException, params object[] messageArguments)
  56. : base(Convert.ToInt32(code),ResolveMessage(code,messageArguments), innerException)
  57. {
  58. }
  59. private static string ResolveMessage(TCodeEnum code, params object[] messageArguments)
  60. {
  61. var codeValue = Convert.ToInt32(code);
  62. // check if cache is initialized
  63. if (_messageCache.Count == 0)
  64. {
  65. // initialize cache
  66. var fields = typeof(TCodeEnum).GetFields();
  67. var names = Enum.GetNames(typeof(TCodeEnum)).ToArray();
  68. var values = Enum.GetValues(typeof(TCodeEnum));
  69. // iterate through all fields of the enumeration
  70. foreach (var field in fields)
  71. {
  72. var attr = field.GetCustomAttributes(typeof(ErrorMessageAttribute), false);
  73. var index = Array.IndexOf(names, field.Name);
  74. if (index<0) continue;
  75. var fieldVal = (int) (values.GetValue(index) ?? -1);
  76. // if value has attribute ErrorMessageAttribute, add it to the cache
  77. if (attr.Length == 1)
  78. {
  79. var message = ((ErrorMessageAttribute)attr[0]).ErrorMessage;
  80. _messageCache.Add(fieldVal, message);
  81. }
  82. else
  83. {
  84. // message not found, log warning and add default message to the cache
  85. System.Diagnostics.Debug.WriteLine($"Error message in enumeration '{typeof(TCodeEnum).Name}' not found for code '{codeValue}'", "WARN");
  86. _messageCache.Add(fieldVal, $"Error message code: {code} [{fieldVal}]");
  87. }
  88. }
  89. }
  90. // return message from cache
  91. return string.Format(_messageCache[codeValue], messageArguments);
  92. }
  93. }
  94. }