diff --git a/GlobalAssemblyInfos.cs b/GlobalAssemblyInfos.cs index 9c43aa9..b311193 100644 --- a/GlobalAssemblyInfos.cs +++ b/GlobalAssemblyInfos.cs @@ -11,6 +11,6 @@ [assembly: AssemblyConfiguration("Release")] #endif -[assembly: AssemblyVersion("1.3.0.0")] -[assembly: AssemblyFileVersion("1.3.0.0")] -[assembly: AssemblyInformationalVersion("1.3.0")] \ No newline at end of file +[assembly: AssemblyVersion("1.4.2.0")] +[assembly: AssemblyFileVersion("1.4.2.0")] +[assembly: AssemblyInformationalVersion("1.4.2")] \ No newline at end of file diff --git a/Nuget-Pub/pack.bat b/Nuget-Pub/pack.bat index e59c642..48bd8aa 100644 --- a/Nuget-Pub/pack.bat +++ b/Nuget-Pub/pack.bat @@ -3,4 +3,8 @@ ECHO Delete Existing Packages for /r %%f in (*.nupkg) do del %%f ECHO Packing Projects NuGet Pack ..\Source\SuperMassive\SuperMassive.csproj -OutputDirectory ".\SuperMassive" -Build -IncludeReferencedProjects -Prop Configuration=Release -Symbols +NuGet Pack ..\Source\SuperMassive.ExceptionHandling\SuperMassive.ExceptionHandling.csproj -OutputDirectory ".\SuperMassive.ExceptionHandling" -Build -IncludeReferencedProjects -Prop Configuration=Release -Symbols +NuGet Pack ..\Source\SuperMassive.ExceptionHandling.Logging\SuperMassive.ExceptionHandling.Logging.csproj -OutputDirectory ".\SuperMassive.ExceptionHandling.Logging" -Build -IncludeReferencedProjects -Prop Configuration=Release -Symbols NuGet Pack ..\Source\SuperMassive.Fakers\SuperMassive.Fakers.csproj -OutputDirectory ".\SuperMassive.Fakers" -Build -IncludeReferencedProjects -Prop Configuration=Release -Symbols +NuGet Pack ..\Source\SuperMassive.Logging\SuperMassive.Logging.csproj -OutputDirectory ".\SuperMassive.Logging" -Build -IncludeReferencedProjects -Prop Configuration=Release -Symbols +NuGet Pack ..\Source\SuperMassive.Logging.AzureTable\SuperMassive.Logging.AzureTable.csproj -OutputDirectory ".\SuperMassive.Logging.AzureTable" -Build -IncludeReferencedProjects -Prop Configuration=Release -Symbols diff --git a/README.md b/README.md index 994f0bb..eaea978 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,19 @@ # SuperMassive +![SuperMassive Logo](https://github.com/PulsarBlow/SuperMassive/blob/master/supermassive.png) + SuperMassive is a small condensed framework of reusable .NET components and utility classes. ### Version -Current : 1.3.0 +Current : 1.4.2 ### Projects descriptions * **SuperMassive** : Core features - SuperMassive swiss army knife! +* **SuperMassive.ExceptionHandling** : Exception handling as it should be. +* **SuperMassive.ExceptionHandling.Logging** : Exception handling with logging features. * **SuperMassive.Fakers** : A suit of data fakers to feed your hungry unit tests with "almost" real data. * **SuperMassive.Logging** : A set of abstract and base logging components * **SuperMassive.Logging.AzureTable** : A concrete implementation of the logging facade for Azure Table @@ -22,6 +26,8 @@ Pick the features you want by installing the corresponding NuGet package : ```Ìnstall-Package SuperMassive``` +```Ìnstall-Package SuperMassive.ExceptionHandling``` +```Ìnstall-Package SuperMassive.ExceptionHandling.Logging``` ```Ìnstall-Package SuperMassive.Fakers``` ```Ìnstall-Package SuperMassive.Logging``` ```Ìnstall-Package SuperMassive.Logging.AzureTable``` diff --git a/Source/SuperMassive.ExceptionHandling.Logging/LoggingExceptionHandler.cs b/Source/SuperMassive.ExceptionHandling.Logging/LoggingExceptionHandler.cs new file mode 100644 index 0000000..11a440e --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling.Logging/LoggingExceptionHandler.cs @@ -0,0 +1,169 @@ +using SuperMassive.ExceptionHandling.Logging.Properties; +using SuperMassive.Logging; +using System; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Text; + +namespace SuperMassive.ExceptionHandling.Logging +{ + /// + /// Represents an that formats the exception into a log message + /// + public class LoggingExceptionHandler : IExceptionHandler + { + #region Members + private readonly string applicationName; + private readonly string logCategory; + private readonly int eventId; + private readonly TraceEventType severity; + private readonly string defaultTitle; + private readonly Type formatterType; + private readonly int minimumPriority; + private readonly ILogWriter logWriter; + #endregion + + /// + /// Handler name + /// + public string Name + { + get { return this.GetType().Name; } + } + + + /// + /// Initializes a new instance of the class with the log category, the event ID, the , + /// the title, minimum priority, the formatter type, and the . + /// + /// + /// The default category + /// An event id. + /// The severity. + /// The log title. + /// The minimum priority. + /// The type type. + /// The to use. + /// + /// The type specified for the attribute must have a public constructor with + /// parameters of type , and . + /// + public LoggingExceptionHandler( + string applicationName, + string logCategory, + int eventId, + TraceEventType severity, + string title, + int priority, + Type formatterType, + ILogWriter writer) + { + this.applicationName = applicationName; + this.logCategory = logCategory; + this.eventId = eventId; + this.severity = severity; + this.defaultTitle = title; + this.minimumPriority = priority; + this.formatterType = formatterType; + this.logWriter = writer; + } + + /// + /// Handles the specified object by formatting it and writing to the configured log. + /// + /// The exception to handle. + /// Modified exception to pass to the next handler in the chain. + public Exception HandleException(Exception exception) + { + WriteToLog(CreateMessage(exception), exception.Data); + return exception; + } + + /// + /// Writes the specified log message using the Logging Application Block's + /// method. + /// + /// The message to write to the log. + /// The exception's data. + protected virtual void WriteToLog(string logMessage, IDictionary exceptionData) + { + LogEntry entry = new LogEntry(this.applicationName, logMessage, logCategory, minimumPriority, eventId, severity, defaultTitle, null); + + foreach (DictionaryEntry dataEntry in exceptionData) + { + if (dataEntry.Key is string) + { + entry.ExtendedProperties.Add(dataEntry.Key as string, dataEntry.Value); + } + } + + this.logWriter.Write(entry); + } + + /// + /// Creates an instance of the + /// class using its default constructor. + /// + /// A newly created + protected virtual StringWriter CreateStringWriter() + { + return new StringWriter(CultureInfo.InvariantCulture); + } + + /// + /// Creates an + /// object based on the configured ExceptionFormatter + /// type name. + /// + /// The stream to write to. + /// The to pass into the formatter. + /// A newly created + protected virtual ExceptionFormatter CreateFormatter( + StringWriter writer, + Exception exception) + { + ConstructorInfo constructor = GetFormatterConstructor(); + return (ExceptionFormatter)constructor.Invoke( + new object[] { writer, exception } + ); + } + + private ConstructorInfo GetFormatterConstructor() + { + Type[] types = new Type[] { typeof(TextWriter), typeof(Exception) }; + ConstructorInfo constructor = formatterType.GetConstructor(types); + if (constructor == null) + { + throw new ExceptionHandlingException( + string.Format(CultureInfo.CurrentCulture, Resources.MissingConstructor, formatterType.AssemblyQualifiedName)); + } + return constructor; + } + + private string CreateMessage(Exception exception) + { + StringWriter writer = null; + StringBuilder stringBuilder = null; + try + { + writer = CreateStringWriter(); + ExceptionFormatter formatter = CreateFormatter(writer, exception); + formatter.Format(); + stringBuilder = writer.GetStringBuilder(); + + } + finally + { + if (writer != null) + { + writer.Close(); + } + } + + return stringBuilder.ToString(); + } + } +} diff --git a/Source/SuperMassive.ExceptionHandling.Logging/Properties/AssemblyInfo.cs b/Source/SuperMassive.ExceptionHandling.Logging/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8698d30 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling.Logging/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("SuperMassive.ExceptionHandling.Logging")] +[assembly: AssemblyDescription("Exception Handling with logging")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: Guid("f65e6698-393e-45e3-82bf-95950ae55ae8")] diff --git a/Source/SuperMassive.ExceptionHandling.Logging/Properties/Resources.Designer.cs b/Source/SuperMassive.ExceptionHandling.Logging/Properties/Resources.Designer.cs new file mode 100644 index 0000000..9ecf08b --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling.Logging/Properties/Resources.Designer.cs @@ -0,0 +1,135 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SuperMassive.ExceptionHandling.Logging.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SuperMassive.ExceptionHandling.Logging.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Handler: '{0}'. + /// + internal static string HandlerPartNameTemplate { + get { + return ResourceManager.GetString("HandlerPartNameTemplate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Category. + /// + internal static string LoggingHandlerCategoryPartName { + get { + return ResourceManager.GetString("LoggingHandlerCategoryPartName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Event ID. + /// + internal static string LoggingHandlerEventIdPartName { + get { + return ResourceManager.GetString("LoggingHandlerEventIdPartName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Formatter. + /// + internal static string LoggingHandlerFormatterPartName { + get { + return ResourceManager.GetString("LoggingHandlerFormatterPartName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Priority. + /// + internal static string LoggingHandlerPriorityPartName { + get { + return ResourceManager.GetString("LoggingHandlerPriorityPartName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Severity. + /// + internal static string LoggingHandlerSeverityPartName { + get { + return ResourceManager.GetString("LoggingHandlerSeverityPartName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Title. + /// + internal static string LoggingHandlerTitlePartName { + get { + return ResourceManager.GetString("LoggingHandlerTitlePartName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The configured exception formatter '{0}' must expose a public constructor that takes a TextWriter object, an Exception object and a GUID instance as parameters.. + /// + internal static string MissingConstructor { + get { + return ResourceManager.GetString("MissingConstructor", resourceCulture); + } + } + } +} diff --git a/Source/SuperMassive.ExceptionHandling.Logging/Properties/Resources.resx b/Source/SuperMassive.ExceptionHandling.Logging/Properties/Resources.resx new file mode 100644 index 0000000..1600142 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling.Logging/Properties/Resources.resx @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Handler: '{0}' + + + Category + + + Event ID + + + Formatter + + + Priority + + + Severity + + + Title + + + The configured exception formatter '{0}' must expose a public constructor that takes a TextWriter object, an Exception object and a GUID instance as parameters. + . + Parameters: 0 - formatterName (string) + + \ No newline at end of file diff --git a/Source/SuperMassive.ExceptionHandling.Logging/SuperMassive.ExceptionHandling.Logging.csproj b/Source/SuperMassive.ExceptionHandling.Logging/SuperMassive.ExceptionHandling.Logging.csproj new file mode 100644 index 0000000..3440792 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling.Logging/SuperMassive.ExceptionHandling.Logging.csproj @@ -0,0 +1,82 @@ + + + + + Debug + AnyCPU + {0F55959E-D2EA-4A2B-89A8-2E62FDF78A05} + Library + Properties + SuperMassive.ExceptionHandling.Logging + SuperMassive.ExceptionHandling.Logging + v4.5.1 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + GlobalAssemblyInfos.cs + + + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {320c2290-3b8b-4c76-a2da-b73a890a95ac} + SuperMassive.ExceptionHandling + + + {f4e601d8-6a83-4ae9-8d2b-220059a5ca46} + SuperMassive.Logging + + + {0671eeaf-72c5-4164-b728-5c6c516c8fc9} + SuperMassive + + + + + \ No newline at end of file diff --git a/Source/SuperMassive.ExceptionHandling/ConstantStringResolver.cs b/Source/SuperMassive.ExceptionHandling/ConstantStringResolver.cs new file mode 100644 index 0000000..dcc102f --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/ConstantStringResolver.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// Resolves strings by returning a constant value. + /// + public sealed class ConstantStringResolver : IStringResolver + { + /// + /// Initializes a new instance of with a constant value. + /// + public ConstantStringResolver(string value) + { + this.value = value; + } + + private readonly string value; + + string IStringResolver.GetString() + { + return this.value; + } + } +} diff --git a/Source/SuperMassive.ExceptionHandling/ExceptionFormatter.cs b/Source/SuperMassive.ExceptionHandling/ExceptionFormatter.cs new file mode 100644 index 0000000..913f2c3 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/ExceptionFormatter.cs @@ -0,0 +1,293 @@ +using SuperMassive.ExceptionHandling.Properties; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Security; +using System.Security.Principal; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// Represents the base class from which all implementations of exception formatters must derive. The formatter provides functionality for formatting objects. + /// + public abstract class ExceptionFormatter + { + private static readonly List IgnoredProperties = new List{ "Source", "Message", "HelpLink", "InnerException", "StackTrace" }; + + private readonly Exception exception; + private NameValueCollection additionalInfo; + + /// + /// Initializes a new instance of the class with an to format. + /// + /// The object to format. + protected ExceptionFormatter(Exception exception) + { + if (exception == null) throw new ArgumentNullException("exception"); + + this.exception = exception; + } + + /// + /// Gets the to format. + /// + /// + /// The to format. + /// + public Exception Exception + { + get { return this.exception; } + } + /// + /// Gets additional information related to the but not + /// stored in the exception (eg: the time in which the was + /// thrown). + /// + /// + /// Additional information related to the but not + /// stored in the exception (for example, the time when the was + /// thrown). + /// + public NameValueCollection AdditionalInfo + { + get + { + if (this.additionalInfo == null) + { + this.additionalInfo = new NameValueCollection(); + this.additionalInfo.Add("MachineName", GetMachineName()); + this.additionalInfo.Add("TimeStamp", DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)); + this.additionalInfo.Add("FullName", Assembly.GetExecutingAssembly().FullName); + this.additionalInfo.Add("AppDomainName", AppDomain.CurrentDomain.FriendlyName); + this.additionalInfo.Add("ThreadIdentity", Thread.CurrentPrincipal.Identity.Name); + this.additionalInfo.Add("WindowsIdentity", GetWindowsIdentity()); + } + + return this.additionalInfo; + } + } + + /// + /// Formats the into the underlying stream. + /// + public virtual void Format() + { + WriteDescription(); + WriteDateTime(DateTime.UtcNow); + WriteException(this.exception, null); + } + + /// + /// Formats the exception and all nested inner exceptions. + /// + /// The exception to format. + /// The outer exception. This + /// value will be null when writing the outer-most exception. + /// + /// This method calls itself recursively until it reaches + /// an exception that does not have an inner exception. + /// + /// This is a template method which calls the following + /// methods in order + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// If the specified exception has an inner exception + /// then it makes a recursive call. + /// + /// + /// + /// + protected virtual void WriteException(Exception exceptionToFormat, Exception outerException) + { + if (exceptionToFormat == null) throw new ArgumentNullException("exceptionToFormat"); + + this.WriteExceptionType(exceptionToFormat.GetType()); + this.WriteMessage(exceptionToFormat.Message); + this.WriteSource(exceptionToFormat.Source); + this.WriteHelpLink(exceptionToFormat.HelpLink); + this.WriteReflectionInfo(exceptionToFormat); + this.WriteStackTrace(exceptionToFormat.StackTrace); + + // We only want additional information on the top most exception + if (outerException == null) + { + this.WriteAdditionalInfo(this.AdditionalInfo); + } + + Exception inner = exceptionToFormat.InnerException; + + if (inner != null) + { + // recursive call + this.WriteException(inner, exceptionToFormat); + } + } + + /// + /// Formats an using reflection to get the information. + /// + /// + /// The to be formatted. + /// + /// + /// This method reflects over the public, instance properties + /// and public, instance fields + /// of the specified exception and prints them to the formatter. + /// Certain property names are ignored + /// because they are handled explicitly in other places. + /// + protected void WriteReflectionInfo(Exception exceptionToFormat) + { + if (exceptionToFormat == null) throw new ArgumentNullException("exceptionToFormat"); + + Type type = exceptionToFormat.GetType(); + PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); + FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public); + object value; + + foreach (PropertyInfo property in properties) + { + if (property.CanRead && IgnoredProperties.IndexOf(property.Name) == -1 && property.GetIndexParameters().Length == 0) + { + try + { + value = property.GetValue(exceptionToFormat, null); + } + catch (TargetInvocationException) + { + value = Resources.PropertyAccessFailed; + } + WritePropertyInfo(property, value); + } + } + + foreach (FieldInfo field in fields) + { + try + { + value = field.GetValue(exceptionToFormat); + } + catch (TargetInvocationException) + { + value = Resources.FieldAccessFailed; + } + WriteFieldInfo(field, value); + } + } + + /// + /// When overridden by a class, writes a description of the caught exception. + /// + protected abstract void WriteDescription(); + + /// + /// When overridden by a class, writes the current time. + /// + /// The current time. + protected abstract void WriteDateTime(DateTime utcNow); + + /// + /// When overridden by a class, writes the of the current exception. + /// + /// The of the exception. + protected abstract void WriteExceptionType(Type exceptionType); + + /// + /// When overridden by a class, writes the . + /// + /// The message to write. + protected abstract void WriteMessage(string message); + + /// + /// When overridden by a class, writes the value of the property. + /// + /// The source of the exception. + protected abstract void WriteSource(string source); + + /// + /// When overridden by a class, writes the value of the property. + /// + /// The help link for the exception. + protected abstract void WriteHelpLink(string helpLink); + + /// + /// When overridden by a class, writes the value of the property. + /// + /// The stack trace of the exception. + protected abstract void WriteStackTrace(string stackTrace); + + /// + /// When overridden by a class, writes the value of a object. + /// + /// The reflected object. + /// The value of the object. + protected abstract void WritePropertyInfo(PropertyInfo propertyInfo, object value); + + /// + /// When overridden by a class, writes the value of a object. + /// + /// The reflected object. + /// The value of the object. + protected abstract void WriteFieldInfo(FieldInfo fieldInfo, object value); + + /// + /// When overridden by a class, writes additional properties if available. + /// + /// Additional information to be included with the exception report + protected abstract void WriteAdditionalInfo(NameValueCollection additionalInformation); + + private static string GetMachineName() + { + string machineName = String.Empty; + try + { + machineName = Environment.MachineName; + } + catch (SecurityException) + { + machineName = Resources.PermissionDenied; + } + + return machineName; + } + + private static string GetWindowsIdentity() + { + string windowsIdentity = String.Empty; + try + { + windowsIdentity = WindowsIdentity.GetCurrent().Name; + } + catch (SecurityException) + { + windowsIdentity = Resources.PermissionDenied; + } + + return windowsIdentity; + } + } +} diff --git a/Source/SuperMassive.ExceptionHandling/ExceptionHandler.cs b/Source/SuperMassive.ExceptionHandling/ExceptionHandler.cs new file mode 100644 index 0000000..21806fb --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/ExceptionHandler.cs @@ -0,0 +1,40 @@ +using System; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// Base class for Exception Handler implementations + /// + public abstract class ExceptionHandler : IExceptionHandler + { + private readonly string name; + /// + /// Handler name + /// + public string Name + { + get + { + if (String.IsNullOrWhiteSpace(this.name)) + return this.GetType().Name; + return this.name; + } + } + /// + /// Initializes a new instance of the class with the name is the handler. + /// + /// + public ExceptionHandler(string name) + { + if (String.IsNullOrWhiteSpace(name)) + throw new ArgumentNullException("name"); + this.name = name; + } + /// + /// When implemented by a class, handles an . + /// + /// The exception to handle. + /// Modified exception to pass to the next exceptionHandlerData in the chain. + public abstract Exception HandleException(Exception exception); + } +} diff --git a/Source/SuperMassive.ExceptionHandling/ExceptionHandlingException.cs b/Source/SuperMassive.ExceptionHandling/ExceptionHandlingException.cs new file mode 100644 index 0000000..d16933f --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/ExceptionHandlingException.cs @@ -0,0 +1,45 @@ +using System; +using System.Runtime.Serialization; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// An error occured during exception handling + /// + [Serializable] + public class ExceptionHandlingException : Exception + { + /// + /// Instantiates a new + /// + public ExceptionHandlingException() + { + } + /// + /// Instantiates a new + /// + /// + public ExceptionHandlingException(string message) + : base(message) + { + } + /// + /// Instantiates a new + /// + /// + /// + public ExceptionHandlingException(string message, Exception innerException) + : base(message, innerException) + { + } + /// + /// Instantiates a new + /// + /// + /// + protected ExceptionHandlingException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/Source/SuperMassive.ExceptionHandling/ExceptionManager.cs b/Source/SuperMassive.ExceptionHandling/ExceptionManager.cs new file mode 100644 index 0000000..e5a2024 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/ExceptionManager.cs @@ -0,0 +1,226 @@ +using SuperMassive.ExceptionHandling.Properties; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// Exception Manager + /// + public class ExceptionManager : IExceptionManager + { + #region Members + private readonly IEnumerable handlers; + private readonly PostHandlingAction postHandlingAction; + #endregion + + #region Properties + #endregion + + #region Constructors + /// + /// Instantiates a new + /// + /// + /// + public ExceptionManager(PostHandlingAction postHandlingAction, IEnumerable handlers) + { + if (handlers == null) + { + throw new ArgumentNullException("handlers"); + } + this.handlers = handlers; + this.postHandlingAction = postHandlingAction; + } + #endregion + + #region Public Methods + /// + /// Handles the specified + /// + /// An object. + /// + /// Whether or not a rethrow is recommended. + /// + /// + /// The following code shows the usage of the + /// exception handling framework. + /// + /// try + /// { + /// DoWork(); + /// } + /// catch (Exception e) + /// { + /// if (exceptionManager.HandleException(e)) throw; + /// } + /// + /// + public bool HandleException(Exception exceptionToHandle) + { + if (exceptionToHandle == null) + throw new ArgumentNullException("exceptionToHandle"); + Exception chainException = ExecuteHandlerChain(exceptionToHandle); + return RethrowRecommanded(chainException, exceptionToHandle); + } + /// + /// Handles the specified + /// + /// An object. + /// The new to throw, if any. + /// + /// If a rethrow is recommended and is , + /// then the original exception should be rethrown; otherwise, + /// the exception returned in should be thrown. + /// + /// + /// Whether or not a rethrow is recommended. + /// + /// + /// The following code shows the usage of the + /// exception handling framework. + /// + /// try + /// { + /// DoWork(); + /// } + /// catch (Exception e) + /// { + /// Exception exceptionToThrow; + /// if (exceptionManager.HandleException(e, out exceptionToThrow)) + /// { + /// if(exceptionToThrow == null) + /// throw; + /// else + /// throw exceptionToThrow; + /// } + /// } + /// + /// + public bool HandleException(Exception exceptionToHandle, out Exception exceptionToThrow) + { + try + { + bool shouldRethrow = HandleException(exceptionToHandle); + exceptionToThrow = null; + return shouldRethrow; + } + catch (Exception exception) + { + exceptionToThrow = exception; + return true; + } + } + /// + /// Excecutes the supplied delegate and handles any thrown exception. + /// + /// The delegate to execute. + /// + /// The following code shows the usage of this method. + /// + /// exceptionManager.Process(() => { DoWork(); }); + /// + /// + public void Process(Action action) + { + if (action == null) + { + throw new ArgumentNullException("action"); + } + try + { + action(); + } + catch (Exception exception) + { + if (HandleException(exception)) + { + throw; + } + } + } + /// + /// Executes the supplied delegate , and handles any thrown exception. + /// + /// Type of return value from . + /// The delegate to execute. + /// The value to return if an exception is thrown and the + /// exception policy swallows it instead of rethrowing. + /// If no exception occurs, returns the result from executing . If + /// an exception occurs and the policy does not re-throw, returns . + public TResult Process(Func action, TResult defaultResult) + { + if (action == null) + { + throw new ArgumentNullException("action"); + } + try + { + return action(); + } + catch (Exception exception) + { + if (HandleException(exception)) + { + throw; + } + } + return defaultResult; + } + #endregion + + #region Private Methods + private Exception ExecuteHandlerChain(Exception ex) + { + if (this.handlers == null || this.handlers.Count() == 0) + return ex; + + string lastHandlerName = String.Empty; + Exception originalException = ex; + + try + { + foreach (var handler in this.handlers) + { + lastHandlerName = handler.Name; + ex = handler.HandleException(ex); + } + } + catch (Exception handlingException) + { + throw new ExceptionHandlingException(String.Format(CultureInfo.CurrentCulture, Resources.UnableToHandleException, lastHandlerName), handlingException); + } + return ex; + } + private bool RethrowRecommanded(Exception chainException, Exception originalException) + { + if (postHandlingAction == PostHandlingAction.None) + return false; + if (postHandlingAction == PostHandlingAction.ThrowNewException) + { + throw IntentionalRethrow(chainException, originalException); + } + return true; + } + /// + /// Rethrows the given exception. Placed in a seperate method for + /// easier viewing in the stack trace. + /// + /// + /// + /// + private Exception IntentionalRethrow(Exception chainException, Exception originalException) + { + if (chainException != null) + { + throw chainException; + } + + Exception wrappedException = new ExceptionHandlingException(Resources.ExceptionNullException); + return wrappedException; + } + #endregion + } +} diff --git a/Source/SuperMassive.ExceptionHandling/IExceptionHandler.cs b/Source/SuperMassive.ExceptionHandling/IExceptionHandler.cs new file mode 100644 index 0000000..553c8b7 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/IExceptionHandler.cs @@ -0,0 +1,21 @@ +using System; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// ExceptionHandler Interface + /// + public interface IExceptionHandler + { + /// + /// Handler name + /// + string Name { get; } + /// + /// When implemented by a class, handles an . + /// + /// The exception to handle. + /// Modified exception to pass to the next exceptionHandlerData in the chain. + Exception HandleException(Exception exception); + } +} diff --git a/Source/SuperMassive.ExceptionHandling/IExceptionManager.cs b/Source/SuperMassive.ExceptionHandling/IExceptionManager.cs new file mode 100644 index 0000000..cff7e9e --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/IExceptionManager.cs @@ -0,0 +1,89 @@ +using System; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// ExceptionManager Interface + /// + public interface IExceptionManager + { + /// + /// Handles the specified + /// + /// An object. + /// + /// Whether or not a rethrow is recommended. + /// + /// + /// The following code shows the usage of the + /// exception handling framework. + /// + /// try + /// { + /// DoWork(); + /// } + /// catch (Exception e) + /// { + /// if (exceptionManager.HandleException(e)) throw; + /// } + /// + /// + bool HandleException(Exception exceptionToHandle); + /// + /// Handles the specified + /// + /// An object. + /// The new to throw, if any. + /// + /// If a rethrow is recommended and is , + /// then the original exception should be rethrown; otherwise, + /// the exception returned in should be thrown. + /// + /// + /// Whether or not a rethrow is recommended. + /// + /// + /// The following code shows the usage of the + /// exception handling framework. + /// + /// try + /// { + /// DoWork(); + /// } + /// catch (Exception e) + /// { + /// Exception exceptionToThrow; + /// if (exceptionManager.HandleException(e, out exceptionToThrow)) + /// { + /// if(exceptionToThrow == null) + /// throw; + /// else + /// throw exceptionToThrow; + /// } + /// } + /// + /// + bool HandleException(Exception exceptionToHandle, out Exception exceptionToThrow); + /// + /// Excecutes the supplied delegate and handles any thrown exception. + /// + /// The delegate to execute. + /// + /// The following code shows the usage of this method. + /// + /// exceptionManager.Process(() => { DoWork(); }); + /// + /// + void Process(Action action); + /// + /// Executes the supplied delegate , and handles any thrown exception. + /// + /// Type of return value from . + /// The delegate to execute. + /// The value to return if an exception is thrown and the + /// exception policy swallows it instead of rethrowing. + /// If no exception occurs, returns the result from executing . If + /// an exception occurs and the policy does not re-throw, returns . + TResult Process(Func action, TResult defaultResult); + } +} diff --git a/Source/SuperMassive.ExceptionHandling/IStringResolver.cs b/Source/SuperMassive.ExceptionHandling/IStringResolver.cs new file mode 100644 index 0000000..0c0d1b7 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/IStringResolver.cs @@ -0,0 +1,15 @@ + +namespace SuperMassive.ExceptionHandling +{ + /// + /// Resolves string objects. + /// + public interface IStringResolver + { + /// + /// Returns a string represented by the receiver. + /// + /// The string object. + string GetString(); + } +} diff --git a/Source/SuperMassive.ExceptionHandling/PostHandlingAction.cs b/Source/SuperMassive.ExceptionHandling/PostHandlingAction.cs new file mode 100644 index 0000000..9348227 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/PostHandlingAction.cs @@ -0,0 +1,22 @@ + +namespace SuperMassive.ExceptionHandling +{ + /// + /// Determines what action should occur after an exception is handled by the configured exception handling chain. + /// + public enum PostHandlingAction + { + /// + /// Indicates that no rethrow should occur. + /// + None = 0, + /// + /// Notify the caller that a rethrow is recommended. + /// + NotifyRethrow = 1, + /// + /// Throws the exception after the exception has been handled by all handlers in the chain. + /// + ThrowNewException = 2 + } +} diff --git a/Source/SuperMassive.ExceptionHandling/Properties/AssemblyInfo.cs b/Source/SuperMassive.ExceptionHandling/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e8d770f --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("SuperMassive.ExceptionHandling")] +[assembly: AssemblyDescription("Exception Handling Library")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: Guid("bfb79cdf-1b3a-4a6f-b130-aee0f5c10667")] diff --git a/Source/SuperMassive.ExceptionHandling/Properties/Resources.Designer.cs b/Source/SuperMassive.ExceptionHandling/Properties/Resources.Designer.cs new file mode 100644 index 0000000..26d8210 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/Properties/Resources.Designer.cs @@ -0,0 +1,630 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34209 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SuperMassive.ExceptionHandling.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SuperMassive.ExceptionHandling.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Custom. + /// + internal static string AddCustomHandlerData { + get { + return ResourceManager.GetString("AddCustomHandlerData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception Type. + /// + internal static string AddExceptionTypeDisplayName { + get { + return ResourceManager.GetString("AddExceptionTypeDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Add a new exception type that is handled by this exception policy.. + /// + internal static string AddExceptionTypeHelpText { + get { + return ResourceManager.GetString("AddExceptionTypeHelpText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Additional Info:. + /// + internal static string AdditionalInfo { + get { + return ResourceManager.GetString("AdditionalInfo", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Add a new policy.. + /// + internal static string AddPolicyDisplayDescription { + get { + return ResourceManager.GetString("AddPolicyDisplayDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Policy. + /// + internal static string AddPolicyDisplayName { + get { + return ResourceManager.GetString("AddPolicyDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Replace Handler. + /// + internal static string AddReplaceHandlerData { + get { + return ResourceManager.GetString("AddReplaceHandlerData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Replace the exception with another exception.. + /// + internal static string AddReplaceHandlerDataDescription { + get { + return ResourceManager.GetString("AddReplaceHandlerDataDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wrap Handler. + /// + internal static string AddWrapHandlerData { + get { + return ResourceManager.GetString("AddWrapHandlerData", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wrap the exception within another exception.. + /// + internal static string AddWrapHandlerDataDescription { + get { + return ResourceManager.GetString("AddWrapHandlerDataDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Attributes. + /// + internal static string AttributesDescription { + get { + return ResourceManager.GetString("AttributesDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Attributes. + /// + internal static string AttributesDisplayName { + get { + return ResourceManager.GetString("AttributesDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AuthorizationProviderTypeDescription. + /// + internal static string AuthorizationProviderTypeDescription { + get { + return ResourceManager.GetString("AuthorizationProviderTypeDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enterprise Library Exception Handling Application Block. + /// + internal static string BlockName { + get { + return ResourceManager.GetString("BlockName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot swallow exceptions for methods with non-null return type.. + /// + internal static string CantSwallowNonVoidReturnMessage { + get { + return ResourceManager.GetString("CantSwallowNonVoidReturnMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to HANDLING CHAIN EXCEPTION:. + /// + internal static string ChainException { + get { + return ResourceManager.GetString("ChainException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A configuration failure occurred while creating policy ‘{0}’.. + /// + internal static string ConfigurationFailureCreatingPolicy { + get { + return ResourceManager.GetString("ConfigurationFailureCreatingPolicy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The error occurred while handling an exception for policy "{0}".. + /// + internal static string ErrorHandlingExceptionMessage { + get { + return ResourceManager.GetString("ErrorHandlingExceptionMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Event id. + /// + internal static string EventIdDisplayName { + get { + return ResourceManager.GetString("EventIdDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exceptions Handled/sec is the rate at which exceptions were handled.. + /// + internal static string ExceptionHandledHelpResource { + get { + return ResourceManager.GetString("ExceptionHandledHelpResource", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception Handlers Executed/sec is the rate at which exception handlers were executed.. + /// + internal static string ExceptionHandlerExecutedHelpResource { + get { + return ResourceManager.GetString("ExceptionHandlerExecutedHelpResource", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Handlers. + /// + internal static string ExceptionHandlersDisplayName { + get { + return ResourceManager.GetString("ExceptionHandlersDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Handler Type. + /// + internal static string ExceptionHandlerTypeDescription { + get { + return ResourceManager.GetString("ExceptionHandlerTypeDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Custom Handler Type. + /// + internal static string ExceptionHandlerTypeDisplayName { + get { + return ResourceManager.GetString("ExceptionHandlerTypeDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception message. + /// + internal static string ExceptionMessageDisplayName { + get { + return ResourceManager.GetString("ExceptionMessageDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception message resource name. + /// + internal static string ExceptionMessageResourceNameDisplayName { + get { + return ResourceManager.GetString("ExceptionMessageResourceNameDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception message resource type. + /// + internal static string ExceptionMessageResourceTypeDisplayName { + get { + return ResourceManager.GetString("ExceptionMessageResourceTypeDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to rethrow exception: The exception to throw is null.. + /// + internal static string ExceptionNullException { + get { + return ResourceManager.GetString("ExceptionNullException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Policies. + /// + internal static string ExceptionPoliciesDisplayName { + get { + return ResourceManager.GetString("ExceptionPoliciesDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The policy with name '{0}' cannot be found. Exception handling aborted.. + /// + internal static string ExceptionPolicyNotFound { + get { + return ResourceManager.GetString("ExceptionPolicyNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value can not be an empty string or null.. + /// + internal static string ExceptionStringNullOrEmpty { + get { + return ResourceManager.GetString("ExceptionStringNullOrEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type must be of type Exception.. + /// + internal static string ExceptionTypeNotException { + get { + return ResourceManager.GetString("ExceptionTypeNotException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception Types. + /// + internal static string ExceptionTypesDisplayName { + get { + return ResourceManager.GetString("ExceptionTypesDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An exception of type '{0}' occurred and was caught.. + /// + internal static string ExceptionWasCaught { + get { + return ResourceManager.GetString("ExceptionWasCaught", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Access failed. + /// + internal static string FieldAccessFailed { + get { + return ResourceManager.GetString("FieldAccessFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Formatter type name. + /// + internal static string FormatterTypeNameDisplayName { + get { + return ResourceManager.GetString("FormatterTypeNameDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Help link : {0}. + /// + internal static string HelpLink { + get { + return ResourceManager.GetString("HelpLink", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inner Exception. + /// + internal static string InnerException { + get { + return ResourceManager.GetString("InnerException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Log category. + /// + internal static string LogCategoryDisplayName { + get { + return ResourceManager.GetString("LogCategoryDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Message : {0}. + /// + internal static string Message { + get { + return ResourceManager.GetString("Message", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name. + /// + internal static string NameDisplayName { + get { + return ResourceManager.GetString("NameDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OFFENDING EXCEPTION:. + /// + internal static string OffendingException { + get { + return ResourceManager.GetString("OffendingException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to ORIGINAL EXCEPTION:. + /// + internal static string OriginalException { + get { + return ResourceManager.GetString("OriginalException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Permission Denied. + /// + internal static string PermissionDenied { + get { + return ResourceManager.GetString("PermissionDenied", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to POLICY NAME: {0}. + /// + internal static string PolicyName { + get { + return ResourceManager.GetString("PolicyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Post handling action. + /// + internal static string PostHandlingActionDisplayName { + get { + return ResourceManager.GetString("PostHandlingActionDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Priority. + /// + internal static string PriorityDisplayName { + get { + return ResourceManager.GetString("PriorityDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Access failed. + /// + internal static string PropertyAccessFailed { + get { + return ResourceManager.GetString("PropertyAccessFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Replace exception type . + /// + internal static string ReplaceExceptionTypeNameDisplayName { + get { + return ResourceManager.GetString("ReplaceExceptionTypeNameDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception Handling Settings. + /// + internal static string SectionDisplayName { + get { + return ResourceManager.GetString("SectionDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Severity. + /// + internal static string SeverityDisplayName { + get { + return ResourceManager.GetString("SeverityDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Source : {0}. + /// + internal static string Source { + get { + return ResourceManager.GetString("Source", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stack Trace. + /// + internal static string StackTrace { + get { + return ResourceManager.GetString("StackTrace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The stack trace is unavailable.. + /// + internal static string StackTraceUnavailable { + get { + return ResourceManager.GetString("StackTraceUnavailable", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Title. + /// + internal static string TitleDisplayName { + get { + return ResourceManager.GetString("TitleDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Total Exceptions Handlers Executed is the total number which exception handlers were executed.. + /// + internal static string TotalExceptionHandlersExecutedHelpResource { + get { + return ResourceManager.GetString("TotalExceptionHandlersExecutedHelpResource", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Total Exceptions Handled is the total number of exceptions handled.. + /// + internal static string TotalExceptionsHandledHelpResource { + get { + return ResourceManager.GetString("TotalExceptionsHandledHelpResource", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type name. + /// + internal static string TypeNameDisplayName { + get { + return ResourceManager.GetString("TypeNameDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type : {0}. + /// + internal static string TypeString { + get { + return ResourceManager.GetString("TypeString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to handle exception: '{0}'.. + /// + internal static string UnableToHandleException { + get { + return ResourceManager.GetString("UnableToHandleException", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <undefined value>. + /// + internal static string UndefinedValue { + get { + return ResourceManager.GetString("UndefinedValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use default logger. + /// + internal static string UseDefaultLoggerDisplayName { + get { + return ResourceManager.GetString("UseDefaultLoggerDisplayName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wrap exception type. + /// + internal static string WrapExceptionTypeNameDisplayName { + get { + return ResourceManager.GetString("WrapExceptionTypeNameDisplayName", resourceCulture); + } + } + } +} diff --git a/Source/SuperMassive.ExceptionHandling/Properties/Resources.resx b/Source/SuperMassive.ExceptionHandling/Properties/Resources.resx new file mode 100644 index 0000000..e5ada14 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/Properties/Resources.resx @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Custom + + + Exception Type + + + Add a new exception type that is handled by this exception policy. + + + Additional Info: + + + Add a new policy. + + + Policy + + + Replace Handler + + + Replace the exception with another exception. + + + Wrap Handler + + + Wrap the exception within another exception. + + + Attributes + + + Attributes + + + AuthorizationProviderTypeDescription + + + Enterprise Library Exception Handling Application Block + + + Cannot swallow exceptions for methods with non-null return type. + + + HANDLING CHAIN EXCEPTION: + + + A configuration failure occurred while creating policy ‘{0}’. + + + The error occurred while handling an exception for policy "{0}". + + + Event id + + + Exceptions Handled/sec is the rate at which exceptions were handled. + + + Exception Handlers Executed/sec is the rate at which exception handlers were executed. + + + Handlers + + + Custom Handler Type + + + Custom Handler Type + + + Exception message + + + Exception message resource name + + + Exception message resource type + + + Unable to rethrow exception: The exception to throw is null. + + + Policies + + + The policy with name '{0}' cannot be found. Exception handling aborted. + + + The value can not be an empty string or null. + + + The type must be of type Exception. + + + Exception Types + + + An exception of type '{0}' occurred and was caught. + + + Access failed + + + Formatter type name + + + Help link : {0} + + + Inner Exception + + + Log category + + + Message : {0} + + + Name + + + OFFENDING EXCEPTION: + + + ORIGINAL EXCEPTION: + + + Permission Denied + + + POLICY NAME: {0} + + + Post handling action + + + Priority + + + Access failed + + + Replace exception type + + + Exception Handling Settings + + + Severity + + + Source : {0} + + + Stack Trace + + + The stack trace is unavailable. + + + Title + + + Total Exceptions Handlers Executed is the total number which exception handlers were executed. + + + Total Exceptions Handled is the total number of exceptions handled. + + + Type name + + + Type : {0} + + + Unable to handle exception: '{0}'. + + + <undefined value> + + + Use default logger + + + Wrap exception type + + \ No newline at end of file diff --git a/Source/SuperMassive.ExceptionHandling/ReplaceHandler.cs b/Source/SuperMassive.ExceptionHandling/ReplaceHandler.cs new file mode 100644 index 0000000..47ed6ba --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/ReplaceHandler.cs @@ -0,0 +1,86 @@ +using SuperMassive.ExceptionHandling.Properties; +using System; +using System.Globalization; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// Replaces the exception in the chain of handlers with a cleansed exception. + /// + public class ReplaceHandler : ExceptionHandler + { + #region Members + private readonly IStringResolver exceptionMessageResolver; + private readonly Type replaceExceptionType; + #endregion + + #region Properties + + /// + /// The type of exception to replace. + /// + public Type ReplaceExceptionType + { + get { return replaceExceptionType; } + } + + /// + /// Gets the message for the new exception. + /// + public string ExceptionMessage + { + get { return exceptionMessageResolver.GetString(); } + } + #endregion + + /// + /// Initializes a new instance of the class with an exception message and the type of to use. + /// + /// The exception message. + /// The type of to use to replace. + public ReplaceHandler(string exceptionMessage, Type replaceExceptionType) + : this(new ConstantStringResolver(exceptionMessage), replaceExceptionType) + { } + + /// + /// Initializes a new instance of the class with an exception message + /// resolver and the type of to use. + /// + /// The exception message resolver. + /// The type of to use to replace. + public ReplaceHandler(IStringResolver exceptionMessageResolver, Type replaceExceptionType) + : base("ReplaceHandler") + { + if (replaceExceptionType == null) throw new ArgumentNullException("replaceExceptionType"); + if (!typeof(Exception).IsAssignableFrom(replaceExceptionType)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.ExceptionTypeNotException, replaceExceptionType.Name), "replaceExceptionType"); + } + + this.exceptionMessageResolver = exceptionMessageResolver; + this.replaceExceptionType = replaceExceptionType; + } + + /// + /// Replaces the exception with the configured type for the specified policy. + /// + /// The original exception. + /// Modified exception to pass to the next exceptionHandlerData in the chain. + public override Exception HandleException(Exception exception) + { + return ReplaceException(ExceptionMessage); + } + + /// + /// Replaces an exception with a new exception of a specified type. + /// + /// The message for the new exception. + /// The replaced or "cleansed" exception. Returns null if unable to replace the exception. + private Exception ReplaceException(string replaceExceptionMessage) + { + + object[] extraParameters = new object[] { replaceExceptionMessage }; + return (Exception)Activator.CreateInstance(replaceExceptionType, extraParameters); + } + } +} diff --git a/Source/SuperMassive.ExceptionHandling/SuperMassive.ExceptionHandling.csproj b/Source/SuperMassive.ExceptionHandling/SuperMassive.ExceptionHandling.csproj new file mode 100644 index 0000000..e41bc6b --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/SuperMassive.ExceptionHandling.csproj @@ -0,0 +1,84 @@ + + + + + Debug + AnyCPU + {320C2290-3B8B-4C76-A2DA-B73A890A95AC} + Library + Properties + SuperMassive.ExceptionHandling + SuperMassive.ExceptionHandling + v4.5.1 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + GlobalAssemblyInfos.cs + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + {0671eeaf-72c5-4164-b728-5c6c516c8fc9} + SuperMassive + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + \ No newline at end of file diff --git a/Source/SuperMassive.ExceptionHandling/TextExceptionFormatter.cs b/Source/SuperMassive.ExceptionHandling/TextExceptionFormatter.cs new file mode 100644 index 0000000..78a7c46 --- /dev/null +++ b/Source/SuperMassive.ExceptionHandling/TextExceptionFormatter.cs @@ -0,0 +1,229 @@ +using SuperMassive.ExceptionHandling.Properties; +using System; +using System.Collections.Specialized; +using System.Globalization; +using System.IO; +using System.Reflection; + +namespace SuperMassive.ExceptionHandling +{ + /// + /// Represents an exception formatter that formats exception objects as text. + /// + public class TextExceptionFormatter : ExceptionFormatter + { + private readonly TextWriter writer; + private int innerDepth; + + /// + /// Initializes a new instance of the + /// using the specified + /// and + /// objects. + /// + /// The stream to write formatting information to. + /// The exception to format. + public TextExceptionFormatter(TextWriter writer, Exception exception) + : base(exception) + { + if (writer == null) throw new ArgumentNullException("writer"); + + this.writer = writer; + } + + /// + /// Gets the underlying + /// that the current formatter is writing to. + /// + public TextWriter Writer + { + get { return this.writer; } + } + + /// + /// Writes a generic description to the underlying text stream. + /// + protected override void WriteDescription() + { + // An exception of type {0} occurred and was caught. + // ------------------------------------------------- + string line = string.Format(CultureInfo.CurrentCulture, Resources.ExceptionWasCaught, base.Exception.GetType().FullName); + this.Writer.WriteLine(line); + + string separator = new string('-', line.Length); + + this.Writer.WriteLine(separator); + } + + /// + /// Writes and formats the exception and all nested inner exceptions to the . + /// + /// The exception to format. + /// The outer exception. This + /// value will be null when writing the outer-most exception. + protected override void WriteException(Exception exceptionToFormat, Exception outerException) + { + if (outerException != null) + { + this.innerDepth++; + this.Indent(); + string temp = Resources.InnerException; + string separator = new string('-', temp.Length); + this.Writer.WriteLine(temp); + this.Indent(); + this.Writer.WriteLine(separator); + + base.WriteException(exceptionToFormat, outerException); + this.innerDepth--; + } + else + { + base.WriteException(exceptionToFormat, outerException); + } + } + + /// + /// Writes the current date and time to the . + /// + /// The current time. + protected override void WriteDateTime(DateTime utcNow) + { + DateTime localTime = utcNow.ToLocalTime(); + string localTimeString = localTime.ToString("G", DateTimeFormatInfo.InvariantInfo); + + this.Writer.WriteLine(localTimeString); + } + + /// + /// Writes the value of the + /// property for the specified exception type to the . + /// + /// The of the exception. + protected override void WriteExceptionType(Type exceptionType) + { + IndentAndWriteLine(Resources.TypeString, exceptionType.AssemblyQualifiedName); + } + + /// + /// Writes the value of the + /// property to the underyling . + /// + /// The message to write. + protected override void WriteMessage(string message) + { + IndentAndWriteLine(Resources.Message, message); + } + + /// + /// Writes the value of the specified source taken + /// from the value of the + /// property to the . + /// + /// The source of the exception. + protected override void WriteSource(string source) + { + IndentAndWriteLine(Resources.Source, source); + } + + /// + /// Writes the value of the specified help link taken + /// from the value of the + /// property to the . + /// + /// The exception's help link. + protected override void WriteHelpLink(string helpLink) + { + IndentAndWriteLine(Resources.HelpLink, helpLink); + } + + /// + /// Writes the name and value of the specified property to the . + /// + /// The reflected object. + /// The value of the object. + protected override void WritePropertyInfo(PropertyInfo propertyInfo, object value) + { + this.Indent(); + this.Writer.Write(propertyInfo.Name); + this.Writer.Write(" : "); + this.Writer.WriteLine(value); + } + + /// + /// Writes the name and value of the specified field to the . + /// + /// The reflected object. + /// The value of the object. + protected override void WriteFieldInfo(FieldInfo fieldInfo, object value) + { + this.Indent(); + this.Writer.Write(fieldInfo.Name); + this.Writer.Write(" : "); + this.Writer.WriteLine(value); + } + + /// + /// Writes the value of the property to the . + /// + /// The stack trace of the exception. + /// + /// If there is no stack trace available, an appropriate message will be displayed. + /// + protected override void WriteStackTrace(string stackTrace) + { + this.Indent(); + this.Writer.Write(Resources.StackTrace); + this.Writer.Write(" : "); + if (stackTrace == null || stackTrace.Length == 0) + { + this.Writer.WriteLine(Resources.StackTraceUnavailable); + } + else + { + // The stack trace has all '\n's prepended with a number + // of tabs equal to the InnerDepth property in order + // to make the formatting pretty. + string indentation = new String('\t', this.innerDepth); + string indentedStackTrace = stackTrace.Replace("\n", "\n" + indentation); + + this.Writer.WriteLine(indentedStackTrace); + this.Writer.WriteLine(); + } + } + + /// + /// Writes the additional properties to the . + /// + /// Additional information to be included with the exception report + protected override void WriteAdditionalInfo(NameValueCollection additionalInformation) + { + this.Writer.WriteLine(Resources.AdditionalInfo); + this.Writer.WriteLine(); + + foreach (string name in additionalInformation.AllKeys) + { + this.Writer.Write(name); + this.Writer.Write(" : "); + this.Writer.Write(additionalInformation[name]); + this.Writer.Write("\n"); + } + } + + /// + /// Indents the . + /// + protected virtual void Indent() + { + for (int i = 0; i < innerDepth; i++) + { + this.Writer.Write("\t"); + } + } + + private void IndentAndWriteLine(string format, params object[] arg) + { + this.Indent(); + this.Writer.WriteLine(format, arg); + } + } +} diff --git a/Source/SuperMassive.Fakers/SuperMassive.Fakers.csproj b/Source/SuperMassive.Fakers/SuperMassive.Fakers.csproj index 655dba4..01a6473 100644 --- a/Source/SuperMassive.Fakers/SuperMassive.Fakers.csproj +++ b/Source/SuperMassive.Fakers/SuperMassive.Fakers.csproj @@ -32,8 +32,9 @@ 4 - - ..\..\packages\FFaker.Net.1.1.0.0\lib\net40\FFaker.Net.dll + + False + ..\..\packages\FFaker.Net.1.1.0.1\lib\net40\FFaker.Net.dll diff --git a/Source/SuperMassive.Fakers/packages.config b/Source/SuperMassive.Fakers/packages.config index a16d611..90fd792 100644 --- a/Source/SuperMassive.Fakers/packages.config +++ b/Source/SuperMassive.Fakers/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/Source/SuperMassive.Logging.AzureTable/AzureTableFormattedTraceListener.cs b/Source/SuperMassive.Logging.AzureTable/AzureTableFormattedTraceListener.cs index 8007760..e0ed002 100644 --- a/Source/SuperMassive.Logging.AzureTable/AzureTableFormattedTraceListener.cs +++ b/Source/SuperMassive.Logging.AzureTable/AzureTableFormattedTraceListener.cs @@ -3,10 +3,7 @@ using SuperMassive.Logging.Formatters; using SuperMassive.Logging.TraceListeners; using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; using System.Threading.Tasks; namespace SuperMassive.Logging.AzureTable @@ -15,7 +12,7 @@ namespace SuperMassive.Logging.AzureTable /// A that writes to a Cloud Storage, /// formatting the output with an . /// - public class FormattedAzureTableTraceListener : FormattedTraceListenerBase + public class AzureTableFormattedTraceListener : FormattedTraceListenerBase { /// /// The name of the Azure Table where the log will be saved @@ -33,35 +30,35 @@ public class FormattedAzureTableTraceListener : FormattedTraceListenerBase protected string _azureTableName; /// - /// Creates a new instance of the + /// Creates a new instance of the /// /// - public FormattedAzureTableTraceListener(string cloudStorageConnectionString) + public AzureTableFormattedTraceListener(string cloudStorageConnectionString) : this(cloudStorageConnectionString, DefaultAzureTableName, null) { } /// - /// Creates a new instance of the + /// Creates a new instance of the /// /// /// - public FormattedAzureTableTraceListener(string cloudStorageConnectionString, string azureTableName) + public AzureTableFormattedTraceListener(string cloudStorageConnectionString, string azureTableName) : this(cloudStorageConnectionString, azureTableName, null) { } /// - /// Creates a new instance of the + /// Creates a new instance of the /// /// - /// + /// /// - public FormattedAzureTableTraceListener(string cloudStorageConnectionString, string azureTaleName, ILogFormatter formatter) + public AzureTableFormattedTraceListener(string cloudStorageConnectionString, string azureTableName, ILogFormatter formatter) : base(formatter) { Guard.ArgumentNotNullOrWhiteSpace(cloudStorageConnectionString, "cloudStorageConnectionString"); - Guard.ArgumentNotNullOrWhiteSpace(azureTaleName, "azureTableName"); _cloudStorageConnectionString = cloudStorageConnectionString; - _azureTableName = azureTaleName; + Guard.ArgumentNotNullOrWhiteSpace(azureTableName, "azureTableName"); + _azureTableName = azureTableName; } /// @@ -185,7 +182,7 @@ private CloudTable GetTableReference() { CloudStorageAccount storageAccount = CloudStorageAccount.Parse(_cloudStorageConnectionString); CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); - return tableClient.GetTableReference(DefaultAzureTableName); + return tableClient.GetTableReference(_azureTableName); } } } diff --git a/SuperMassive.sln b/SuperMassive.sln index 4109ce0..6236b0f 100644 --- a/SuperMassive.sln +++ b/SuperMassive.sln @@ -39,6 +39,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperMassive.Logging.Tests" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperMassive.Logging.AzureTable.Tests", "Source\UnitTests\SuperMassive.Logging.AzureTable.Tests\SuperMassive.Logging.AzureTable.Tests.csproj", "{312D71E7-A124-464B-9C83-6B812599F6B8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperMassive.ExceptionHandling", "Source\SuperMassive.ExceptionHandling\SuperMassive.ExceptionHandling.csproj", "{320C2290-3B8B-4C76-A2DA-B73A890A95AC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperMassive.ExceptionHandling.Logging", "Source\SuperMassive.ExceptionHandling.Logging\SuperMassive.ExceptionHandling.Logging.csproj", "{0F55959E-D2EA-4A2B-89A8-2E62FDF78A05}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -81,6 +85,14 @@ Global {312D71E7-A124-464B-9C83-6B812599F6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU {312D71E7-A124-464B-9C83-6B812599F6B8}.Release|Any CPU.ActiveCfg = Release|Any CPU {312D71E7-A124-464B-9C83-6B812599F6B8}.Release|Any CPU.Build.0 = Release|Any CPU + {320C2290-3B8B-4C76-A2DA-B73A890A95AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {320C2290-3B8B-4C76-A2DA-B73A890A95AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {320C2290-3B8B-4C76-A2DA-B73A890A95AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {320C2290-3B8B-4C76-A2DA-B73A890A95AC}.Release|Any CPU.Build.0 = Release|Any CPU + {0F55959E-D2EA-4A2B-89A8-2E62FDF78A05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F55959E-D2EA-4A2B-89A8-2E62FDF78A05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F55959E-D2EA-4A2B-89A8-2E62FDF78A05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F55959E-D2EA-4A2B-89A8-2E62FDF78A05}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -95,5 +107,7 @@ Global {6E414529-342A-46D2-80FE-90CC23498DF4} = {5AA919F6-161A-4B73-BED4-F3479A337A96} {57E99EBC-F092-4B24-B8DA-7C5555C14FD7} = {C5BD50D1-7BEA-4228-91F1-B43BD9741618} {312D71E7-A124-464B-9C83-6B812599F6B8} = {C5BD50D1-7BEA-4228-91F1-B43BD9741618} + {320C2290-3B8B-4C76-A2DA-B73A890A95AC} = {5AA919F6-161A-4B73-BED4-F3479A337A96} + {0F55959E-D2EA-4A2B-89A8-2E62FDF78A05} = {5AA919F6-161A-4B73-BED4-F3479A337A96} EndGlobalSection EndGlobal diff --git a/supermassive.png b/supermassive.png new file mode 100644 index 0000000..5894822 Binary files /dev/null and b/supermassive.png differ